msdf-atlas-gen/msdf-atlas-gen/artery-font-export.cpp

199 lines
9.7 KiB
C++

#include "artery-font-export.h"
#ifndef MSDF_ATLAS_NO_ARTERY_FONT
#include <artery-font/std-artery-font.h>
#include <artery-font/stdio-serialization.h>
#include "GlyphGeometry.h"
#include "image-encode.h"
namespace msdf_atlas {
static artery_font::ImageType convertImageType(ImageType imageType) {
switch (imageType) {
case ImageType::HARD_MASK:
case ImageType::SOFT_MASK:
return artery_font::IMAGE_LINEAR_MASK;
case ImageType::SDF:
return artery_font::IMAGE_SDF;
case ImageType::PSDF:
return artery_font::IMAGE_PSDF;
case ImageType::MSDF:
return artery_font::IMAGE_MSDF;
case ImageType::MTSDF:
return artery_font::IMAGE_MTSDF;
}
return artery_font::IMAGE_NONE;
}
static artery_font::CodepointType convertCodepointType(GlyphIdentifierType glyphIdentifierType) {
switch (glyphIdentifierType) {
case GlyphIdentifierType::GLYPH_INDEX:
return artery_font::CP_INDEXED;
case GlyphIdentifierType::UNICODE_CODEPOINT:
return artery_font::CP_UNICODE;
}
return artery_font::CP_UNSPECIFIED;
}
template <typename T, int N>
static bool encodeTiff(std::vector<byte> &output, const msdfgen::BitmapConstRef<T, N> &atlas) {
// TODO
return false;
}
template <typename T>
static artery_font::PixelFormat getPixelFormat();
template <>
artery_font::PixelFormat getPixelFormat<byte>() {
return artery_font::PIXEL_UNSIGNED8;
}
template <>
artery_font::PixelFormat getPixelFormat<float>() {
return artery_font::PIXEL_FLOAT32;
}
template <typename REAL, typename T, int N>
bool exportArteryFont(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<T, N> &atlas, const char *filename, const ArteryFontExportProperties &properties) {
artery_font::StdArteryFont<REAL> arfont = { };
arfont.metadataFormat = artery_font::METADATA_NONE;
arfont.variants = artery_font::StdList<typename artery_font::StdArteryFont<REAL>::Variant>(fontCount);
for (int i = 0; i < fontCount; ++i) {
const FontGeometry &font = fonts[i];
GlyphIdentifierType identifierType = font.getPreferredIdentifierType();
const msdfgen::FontMetrics &fontMetrics = font.getMetrics();
typename artery_font::StdArteryFont<REAL>::Variant &fontVariant = arfont.variants[i] = typename artery_font::StdArteryFont<REAL>::Variant();
fontVariant.codepointType = convertCodepointType(identifierType);
fontVariant.imageType = convertImageType(properties.imageType);
fontVariant.metrics.fontSize = REAL(properties.fontSize*fontMetrics.emSize);
if (properties.imageType != ImageType::HARD_MASK) {
fontVariant.metrics.distanceRange = REAL(properties.pxRange.upper-properties.pxRange.lower);
fontVariant.metrics.distanceRangeMiddle = REAL(.5*(properties.pxRange.lower+properties.pxRange.upper));
}
fontVariant.metrics.emSize = REAL(fontMetrics.emSize);
fontVariant.metrics.ascender = REAL(fontMetrics.ascenderY);
fontVariant.metrics.descender = REAL(fontMetrics.descenderY);
fontVariant.metrics.lineHeight = REAL(fontMetrics.lineHeight);
fontVariant.metrics.underlineY = REAL(fontMetrics.underlineY);
fontVariant.metrics.underlineThickness = REAL(fontMetrics.underlineThickness);
const char *name = font.getName();
if (name)
(std::string &) fontVariant.name = name;
fontVariant.glyphs = artery_font::StdList<artery_font::Glyph<REAL> >(font.getGlyphs().size());
int j = 0;
for (const GlyphGeometry &glyphGeom : font.getGlyphs()) {
artery_font::Glyph<REAL> &glyph = fontVariant.glyphs[j++];
glyph.codepoint = glyphGeom.getIdentifier(identifierType);
glyph.image = 0;
double l, b, r, t;
glyphGeom.getQuadPlaneBounds(l, b, r, t);
glyph.planeBounds.l = REAL(l);
glyph.planeBounds.b = REAL(b);
glyph.planeBounds.r = REAL(r);
glyph.planeBounds.t = REAL(t);
glyphGeom.getQuadAtlasBounds(l, b, r, t);
glyph.imageBounds.l = REAL(l);
glyph.imageBounds.b = REAL(b);
glyph.imageBounds.r = REAL(r);
glyph.imageBounds.t = REAL(t);
glyph.advance.h = REAL(glyphGeom.getAdvance());
glyph.advance.v = REAL(0);
}
switch (identifierType) {
case GlyphIdentifierType::GLYPH_INDEX:
for (const std::pair<std::pair<int, int>, double> &elem : font.getKerning()) {
artery_font::KernPair<REAL> kernPair = { };
kernPair.codepoint1 = elem.first.first;
kernPair.codepoint2 = elem.first.second;
kernPair.advance.h = REAL(elem.second);
((std::vector<artery_font::KernPair<REAL> > &) fontVariant.kernPairs).push_back((artery_font::KernPair<REAL> &&) kernPair);
}
break;
case GlyphIdentifierType::UNICODE_CODEPOINT:
for (const std::pair<std::pair<int, int>, double> &elem : font.getKerning()) {
const GlyphGeometry *glyph1 = font.getGlyph(msdfgen::GlyphIndex(elem.first.first));
const GlyphGeometry *glyph2 = font.getGlyph(msdfgen::GlyphIndex(elem.first.second));
if (glyph1 && glyph2 && glyph1->getCodepoint() && glyph2->getCodepoint()) {
artery_font::KernPair<REAL> kernPair = { };
kernPair.codepoint1 = glyph1->getCodepoint();
kernPair.codepoint2 = glyph2->getCodepoint();
kernPair.advance.h = REAL(elem.second);
((std::vector<artery_font::KernPair<REAL> > &) fontVariant.kernPairs).push_back((artery_font::KernPair<REAL> &&) kernPair);
}
}
break;
}
}
arfont.images = artery_font::StdList<typename artery_font::StdArteryFont<REAL>::Image>(1);
{
typename artery_font::StdArteryFont<REAL>::Image &image = arfont.images[0] = typename artery_font::StdArteryFont<REAL>::Image();
image.width = atlas.width;
image.height = atlas.height;
image.channels = N;
image.imageType = convertImageType(properties.imageType);
switch (properties.imageFormat) {
#ifndef MSDFGEN_DISABLE_PNG
case ImageFormat::PNG:
image.encoding = artery_font::IMAGE_PNG;
image.pixelFormat = artery_font::PIXEL_UNSIGNED8;
if (!encodePng((std::vector<byte> &) image.data, atlas))
return false;
break;
#endif
case ImageFormat::TIFF:
image.encoding = artery_font::IMAGE_TIFF;
image.pixelFormat = artery_font::PIXEL_FLOAT32;
if (!encodeTiff((std::vector<byte> &) image.data, atlas))
return false;
break;
case ImageFormat::BINARY:
image.pixelFormat = artery_font::PIXEL_UNSIGNED8;
goto BINARY_EITHER;
case ImageFormat::BINARY_FLOAT:
image.pixelFormat = artery_font::PIXEL_FLOAT32;
goto BINARY_EITHER;
BINARY_EITHER:
if (image.pixelFormat != getPixelFormat<T>())
return false;
image.encoding = artery_font::IMAGE_RAW_BINARY;
image.rawBinaryFormat.rowLength = N*sizeof(T)*atlas.width;
image.data = artery_font::StdByteArray(N*sizeof(T)*atlas.width*atlas.height);
switch (properties.yDirection) {
case YDirection::BOTTOM_UP:
image.rawBinaryFormat.orientation = artery_font::ORIENTATION_BOTTOM_UP;
memcpy((byte *) image.data, atlas.pixels, N*sizeof(T)*atlas.width*atlas.height);
break;
case YDirection::TOP_DOWN: {
image.rawBinaryFormat.orientation = artery_font::ORIENTATION_TOP_DOWN;
byte *imageData = (byte *) image.data;
for (int y = atlas.height-1; y >= 0; --y) {
memcpy(imageData, atlas.pixels+N*atlas.width*y, N*sizeof(T)*atlas.width);
imageData += N*sizeof(T)*atlas.width;
}
break;
}
}
break;
default:
return false;
}
}
return artery_font::writeFile(arfont, filename);
}
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<byte, 1> &atlas, const char *filename, const ArteryFontExportProperties &properties);
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<byte, 3> &atlas, const char *filename, const ArteryFontExportProperties &properties);
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<byte, 4> &atlas, const char *filename, const ArteryFontExportProperties &properties);
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<float, 1> &atlas, const char *filename, const ArteryFontExportProperties &properties);
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<float, 3> &atlas, const char *filename, const ArteryFontExportProperties &properties);
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<float, 4> &atlas, const char *filename, const ArteryFontExportProperties &properties);
}
#endif