add apis for font format conversion and merging

Change-Id: Ica67fba1ea32a0d98326e6c2979556bee1759a3b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191211
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit fe9e639b38e6b6a07e0a37e215d1fc75e62e537b)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192333
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
Tested-by: Jenkins
This commit is contained in:
Caolán McNamara
2025-10-14 17:13:37 +02:00
parent 4297095d67
commit e20bf4d9df
5 changed files with 288 additions and 0 deletions
+13
View File
@@ -109,6 +109,19 @@ public:
EmbeddedFontsManager(const css::uno::Reference<css::frame::XModel>& xModel);
~EmbeddedFontsManager();
// write text dump
static bool tx_dump(const OUString& srcFontUrl, const OUString& destFileUrl);
// write Type 1 font
static bool tx_t1(const OUString& srcFontUrl, const OUString& destFontUrl);
// merge fonts together (can also be used to convert a name keyed font to a cid keyed font)
// each font in fonts is glyphaliasfile, mergefontfile
static bool mergefonts(const OUString& cidFontInfoUrl, const OUString& destFileUrl,
const std::vector<std::pair<OUString, OUString>>& fonts);
// write OTF font, features is optional
static bool makeotf(const OUString& srcFontUrl, const OUString& destFileUrl,
const OUString& fontMenuNameDBUrl, const OUString& charMapUrl,
const OUString& featuresUrl);
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+1
View File
@@ -20,6 +20,7 @@
#include <svdpdf.hxx>
#include <tools/UnitConversion.hxx>
#include <vcl/embeddedfontsmanager.hxx>
#include <vcl/graph.hxx>
#include <vcl/vectorgraphicdata.hxx>
+2
View File
@@ -323,6 +323,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/source/gdi/formpdfexport \
vcl/source/gdi/cvtgrf \
vcl/source/gdi/embeddedfontsmanager \
vcl/source/gdi/embeddedfontsafdko \
vcl/source/gdi/FileDefinitionWidgetDraw \
vcl/source/gdi/WidgetDefinitionReader \
vcl/source/gdi/WidgetDefinition \
@@ -722,6 +723,7 @@ $(eval $(call gb_Library_use_externals,vcl,\
freetype \
) \
$(if $(filter PDFIUM,$(BUILD_TYPE)),pdfium) \
$(if $(filter AFDKO,$(BUILD_TYPE)),afdko libxml2) \
))
$(eval $(call gb_Library_add_libs,vcl,\
+32
View File
@@ -0,0 +1,32 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Copyright 2014-2018 Adobe Systems Incorporated (http://www.adobe.com/). All Rights Reserved.
* This software is licensed as OpenSource, under the Apache License, Version 2.0.
* This license is available at: http://opensource.org/licenses/Apache-2.0.
*/
#pragma once
extern "C" {
#include <tx_shared.h>
#include <hotconv.h>
#include <cb.h>
extern txCtx txNew(char* progname);
extern void txFree(txCtx h);
extern void cfrReadFont(txCtx h, long origin, int ttcIndex);
extern txCtx mergeFontsNew(char* progname);
extern void mergeFontsFree(txCtx h);
extern void readCIDFontInfo(txCtx h, char* filePath);
extern int doMergeFileSet(txCtx h, int argc, char* args[], int i);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
+240
View File
@@ -0,0 +1,240 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Copyright 2014-2018 Adobe Systems Incorporated (http://www.adobe.com/). All Rights Reserved.
* This software is licensed as OpenSource, under the Apache License, Version 2.0.
* This license is available at: http://opensource.org/licenses/Apache-2.0.
*/
#include <vcl/embeddedfontsmanager.hxx>
#include <osl/file.hxx>
#include "afdko.hxx"
static bool convertTx(txCtx h)
{
h->src.stm.fp = fopen(h->src.stm.filename, "rb");
if (!h->src.stm.fp)
return false;
h->src.stm.flags = STM_DONT_CLOSE;
buildFontList(h);
for (long i = 0; i < h->fonts.cnt; ++i)
{
const FontRec& rec = h->fonts.array[i];
h->src.type = rec.type;
switch (h->src.type)
{
case src_Type1:
t1rReadFont(h, rec.offset);
break;
case src_OTF:
h->cfr.flags |= CFR_NO_ENCODING;
[[fallthrough]];
case src_CFF:
cfrReadFont(h, rec.offset, rec.iTTC);
break;
default:
SAL_WARN("vcl.fonts", "unhandled font type: " << h->src.type);
break;
}
}
return true;
}
// System afdko could be used by calling: tx -dump src dest here
bool EmbeddedFontsManager::tx_dump(const OUString& srcFontUrl, const OUString& destFileUrl)
{
OUString srcFontPath, destFilePath;
if (osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL(srcFontUrl, srcFontPath)
|| osl::FileBase::E_None
!= osl::FileBase::getSystemPathFromFileURL(destFileUrl, destFilePath))
{
SAL_WARN("vcl.fonts", "path failure");
return false;
}
txCtx h = txNew(nullptr);
if (!h)
return false;
OString srcFontPathA(srcFontPath.toUtf8());
h->src.stm.filename = const_cast<char*>(srcFontPathA.getStr());
OString destFilePathA(destFilePath.toUtf8());
h->dst.stm.filename = const_cast<char*>(destFilePathA.getStr());
bool result = convertTx(h);
txFree(h);
return result;
}
// System afdko could be used by calling: tx -t1 src dest here
bool EmbeddedFontsManager::tx_t1(const OUString& srcFontUrl, const OUString& destFileUrl)
{
OUString srcFontPath, destFilePath;
if (osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL(srcFontUrl, srcFontPath)
|| osl::FileBase::E_None
!= osl::FileBase::getSystemPathFromFileURL(destFileUrl, destFilePath))
{
SAL_WARN("vcl.fonts", "path failure");
return false;
}
txCtx h = txNew(nullptr);
if (!h)
return false;
setMode(h, mode_t1);
OString srcFontPathA(srcFontPath.toUtf8());
h->src.stm.filename = const_cast<char*>(srcFontPathA.getStr());
OString destFilePathA(destFilePath.toUtf8());
h->dst.stm.filename = const_cast<char*>(destFilePathA.getStr());
bool result = convertTx(h);
txFree(h);
return result;
}
// System afdko could be used by calling: mergefonts -cid cidfontinfo destfile [glyphaliasfile mergefontfile]+ here
bool EmbeddedFontsManager::mergefonts(const OUString& cidFontInfoUrl, const OUString& destFileUrl,
const std::vector<std::pair<OUString, OUString>>& fonts)
{
OUString cidFontInfoPath, destFilePath;
if (osl::FileBase::E_None
!= osl::FileBase::getSystemPathFromFileURL(cidFontInfoUrl, cidFontInfoPath)
|| osl::FileBase::E_None
!= osl::FileBase::getSystemPathFromFileURL(destFileUrl, destFilePath))
{
SAL_WARN("vcl.fonts", "path failure");
return false;
}
std::vector<OString> paths;
for (const auto& font : fonts)
{
OUString glyphAliasPath;
OUString mergeFontFilePath;
if (osl::FileBase::E_None
!= osl::FileBase::getSystemPathFromFileURL(font.first, glyphAliasPath)
|| osl::FileBase::E_None
!= osl::FileBase::getSystemPathFromFileURL(font.second, mergeFontFilePath))
{
SAL_WARN("vcl.fonts", "path failure");
return false;
}
paths.push_back(glyphAliasPath.toUtf8());
paths.push_back(mergeFontFilePath.toUtf8());
}
txCtx h = mergeFontsNew(nullptr);
if (!h)
return false;
OString cidFontInfoPathA(cidFontInfoPath.toUtf8());
readCIDFontInfo(h, const_cast<char*>(cidFontInfoPathA.getStr()));
setMode(h, mode_cff);
OString destFilePathA(destFilePath.toUtf8());
dstFileSetName(h, const_cast<char*>(destFilePathA.getStr()));
h->cfw.flags |= CFW_CHECK_IF_GLYPHS_DIFFER;
h->cfw.flags |= CFW_PRESERVE_GLYPH_ORDER;
std::vector<char*> args;
for (const auto& path : paths)
{
args.push_back(const_cast<char*>(path.getStr()));
}
// merge the input fonts into destfile
size_t resultarg = doMergeFileSet(h, args.size(), args.data(), 0);
SAL_WARN_IF(resultarg != args.size() - 1, "vcl.fonts",
"suspicious doMergeFileSet result of: " << resultarg);
// convert that merged cid result to Type 1
h->src.stm.filename = const_cast<char*>(destFilePathA.getStr());
OString tmpdestfile = destFilePathA + ".temp";
h->dst.stm.filename = const_cast<char*>(tmpdestfile.getStr());
setMode(h, mode_t1);
bool result = convertTx(h);
remove(destFilePathA.getStr());
rename(h->dst.stm.filename, destFilePathA.getStr());
mergeFontsFree(h);
return result;
}
static void* cb_memory(ctlMemoryCallbacks* /*cb*/, void* old, size_t size)
{
if (size == 0)
{
free(old);
return nullptr;
}
if (old != nullptr)
return realloc(old, size);
return malloc(size);
}
// System afdko could be used by calling: makeotf[exe] -mf fontMenuNameDB -f srcFont -o destFile -ch charMap [-ff features]
bool EmbeddedFontsManager::makeotf(const OUString& srcFontUrl, const OUString& destFileUrl,
const OUString& fontMenuNameDBUrl, const OUString& charMapUrl,
const OUString& featuresUrl)
{
OUString srcFontPath, destFilePath, charMapPath, fontMenuNameDBPath, featuresPath;
if (osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL(srcFontUrl, srcFontPath)
|| osl::FileBase::E_None
!= osl::FileBase::getSystemPathFromFileURL(destFileUrl, destFilePath)
|| osl::FileBase::E_None
!= osl::FileBase::getSystemPathFromFileURL(fontMenuNameDBUrl, fontMenuNameDBPath)
|| osl::FileBase::E_None
!= osl::FileBase::getSystemPathFromFileURL(charMapUrl, charMapPath))
{
SAL_WARN("vcl.fonts", "path failure");
return false;
}
if (!featuresUrl.isEmpty()
&& osl::FileBase::E_None
!= osl::FileBase::getSystemPathFromFileURL(featuresUrl, featuresPath))
{
SAL_WARN("vcl.fonts", "path failure");
return false;
}
ctlMemoryCallbacks cb_dna_memcb{ nullptr, cb_memory };
dnaCtx mainDnaCtx = dnaNew(&cb_dna_memcb, DNA_CHECK_ARGS);
cbCtx cbctx = cbNew(nullptr, const_cast<char*>(""), const_cast<char*>(""),
const_cast<char*>(""), const_cast<char*>(""), mainDnaCtx);
OString fontMenuNameDBPathA(fontMenuNameDBPath.toUtf8());
cbFCDBRead(cbctx, const_cast<char*>(fontMenuNameDBPathA.getStr()));
OString srcFontPathA(srcFontPath.toUtf8());
OString destFilePathA(destFilePath.toUtf8());
OString charMapPathA(charMapPath.toUtf8());
OString featuresPathA(featuresPath.toUtf8());
cbConvert(cbctx, HOT_NO_OLD_OPS, nullptr, const_cast<char*>(srcFontPathA.getStr()),
const_cast<char*>(destFilePathA.getStr()),
!featuresPathA.isEmpty() ? const_cast<char*>(featuresPathA.getStr()) : nullptr,
const_cast<char*>(charMapPathA.getStr()), nullptr, nullptr, nullptr, 0, 0, 0, 0, 0,
-1, -1, 0, nullptr);
return true;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */