mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2024-12-27 05:48:20 +01:00
Save work.
This commit is contained in:
parent
858cc101b6
commit
688810f143
1
.gitignore
vendored
1
.gitignore
vendored
@ -13,4 +13,5 @@
|
|||||||
/pdfiototext
|
/pdfiototext
|
||||||
/testpdfio
|
/testpdfio
|
||||||
/testpdfio-*.pdf
|
/testpdfio-*.pdf
|
||||||
|
/testttf
|
||||||
/x64
|
/x64
|
||||||
|
13
Makefile
13
Makefile
@ -67,12 +67,14 @@ LIBOBJS = \
|
|||||||
OBJS = \
|
OBJS = \
|
||||||
$(LIBOBJS) \
|
$(LIBOBJS) \
|
||||||
pdfiototext.o \
|
pdfiototext.o \
|
||||||
testpdfio.o
|
testpdfio.o \
|
||||||
|
testttf.o
|
||||||
TARGETS = \
|
TARGETS = \
|
||||||
$(DSONAME) \
|
$(DSONAME) \
|
||||||
libpdfio.a \
|
libpdfio.a \
|
||||||
pdfiototext \
|
pdfiototext \
|
||||||
testpdfio
|
testpdfio \
|
||||||
|
testttf
|
||||||
|
|
||||||
|
|
||||||
# Make everything
|
# Make everything
|
||||||
@ -136,6 +138,7 @@ install-shared:
|
|||||||
|
|
||||||
# Test everything
|
# Test everything
|
||||||
test: testpdfio
|
test: testpdfio
|
||||||
|
./testttf 2>test.log
|
||||||
./testpdfio 2>test.log
|
./testpdfio 2>test.log
|
||||||
|
|
||||||
valgrind: testpdfio
|
valgrind: testpdfio
|
||||||
@ -182,10 +185,16 @@ testpdfio: testpdfio.o libpdfio.a
|
|||||||
echo Linking $@...
|
echo Linking $@...
|
||||||
$(CC) $(LDFLAGS) $(COMMONFLAGS) -o $@ testpdfio.o libpdfio.a $(LIBS)
|
$(CC) $(LDFLAGS) $(COMMONFLAGS) -o $@ testpdfio.o libpdfio.a $(LIBS)
|
||||||
|
|
||||||
|
# TTF test program
|
||||||
|
testttf: ttf.o testttf.o
|
||||||
|
echo Linking $@...
|
||||||
|
$(CC) $(LDFLAGS) -o testttf ttf.o testttf.o $(LIBS)
|
||||||
|
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
$(OBJS): pdfio.h pdfio-private.h Makefile
|
$(OBJS): pdfio.h pdfio-private.h Makefile
|
||||||
pdfio-content.o: pdfio-content.h ttf.h
|
pdfio-content.o: pdfio-content.h ttf.h
|
||||||
|
testttf.o: ttf.h
|
||||||
ttf.o: ttf.h
|
ttf.o: ttf.h
|
||||||
|
|
||||||
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
|
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
|
||||||
|
@ -1466,8 +1466,8 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Map to specified glyph...
|
// Map to specified glyph...
|
||||||
*bufptr++ = (unsigned char)((cmap[i] + 1) >> 8);
|
*bufptr++ = (unsigned char)(cmap[i] >> 8);
|
||||||
*bufptr++ = (unsigned char)((cmap[i] + 1) & 255);
|
*bufptr++ = (unsigned char)(cmap[i] & 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bufptr >= bufend)
|
if (bufptr >= bufend)
|
||||||
|
305
testttf.c
Normal file
305
testttf.c
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
//
|
||||||
|
// Unit test program for TTF library
|
||||||
|
//
|
||||||
|
// https://github.com/michaelrsweet/ttf
|
||||||
|
//
|
||||||
|
// Copyright © 2018-2023 by Michael R Sweet.
|
||||||
|
//
|
||||||
|
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||||
|
// information.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
//
|
||||||
|
// ./testttf [FILENAME]
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "ttf.h"
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Local functions...
|
||||||
|
//
|
||||||
|
|
||||||
|
static void error_cb(void *data, const char *message);
|
||||||
|
static int test_font(const char *filename);
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'main()' - Main entry for unit tests.
|
||||||
|
//
|
||||||
|
|
||||||
|
int // O - Exit status
|
||||||
|
main(int argc, // I - Number of command-line arguments
|
||||||
|
char *argv[]) // I - Command-line arguments
|
||||||
|
{
|
||||||
|
int i; // Looping var
|
||||||
|
int errors = 0; // Number of errors
|
||||||
|
|
||||||
|
|
||||||
|
if (argc > 1)
|
||||||
|
{
|
||||||
|
for (i = 1; i < argc; i ++)
|
||||||
|
errors += test_font(argv[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Test with the bundled TrueType files...
|
||||||
|
errors += test_font("testfiles/OpenSans-Bold.ttf");
|
||||||
|
errors += test_font("testfiles/OpenSans-Regular.ttf");
|
||||||
|
errors += test_font("testfiles/NotoSansJP-Regular.otf");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!errors)
|
||||||
|
puts("\nALL TESTS PASSED");
|
||||||
|
else
|
||||||
|
printf("\n%d TEST(S) FAILED\n", errors);
|
||||||
|
|
||||||
|
return (errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'error_cb()' - Error callback.
|
||||||
|
//
|
||||||
|
|
||||||
|
static void
|
||||||
|
error_cb(void *data, // I - User data (not used)
|
||||||
|
const char *message) // I - Message string
|
||||||
|
{
|
||||||
|
fprintf(stderr, "FAIL (%s)\n", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'test_font()' - Test a font file.
|
||||||
|
//
|
||||||
|
|
||||||
|
static int // O - Number of errors
|
||||||
|
test_font(const char *filename) // I - Font filename
|
||||||
|
{
|
||||||
|
int i, // Looping var
|
||||||
|
errors = 0; // Number of errors
|
||||||
|
ttf_t *font; // Font
|
||||||
|
const char *value; // Font (string) value
|
||||||
|
int intvalue; // Font (integer) value
|
||||||
|
float realvalue; // Font (real) value
|
||||||
|
ttf_rect_t bounds; // Bounds
|
||||||
|
ttf_rect_t extents; // Extents
|
||||||
|
size_t num_fonts; // Number of fonts
|
||||||
|
ttf_style_t style; // Font style
|
||||||
|
ttf_weight_t weight; // Font weight
|
||||||
|
static const char * const stretches[] =
|
||||||
|
{ // Font stretch strings
|
||||||
|
"TTF_STRETCH_NORMAL", // normal
|
||||||
|
"TTF_STRETCH_ULTRA_CONDENSED", // ultra-condensed
|
||||||
|
"TTF_STRETCH_EXTRA_CONDENSED", // extra-condensed
|
||||||
|
"TTF_STRETCH_CONDENSED", // condensed
|
||||||
|
"TTF_STRETCH_SEMI_CONDENSED", // semi-condensed
|
||||||
|
"TTF_STRETCH_SEMI_EXPANDED", // semi-expanded
|
||||||
|
"TTF_STRETCH_EXPANDED", // expanded
|
||||||
|
"TTF_STRETCH_EXTRA_EXPANDED", // extra-expanded
|
||||||
|
"TTF_STRETCH_ULTRA_EXPANDED" // ultra-expanded
|
||||||
|
};
|
||||||
|
static const char * const strings[] = // Test strings
|
||||||
|
{
|
||||||
|
"Hello, World!", // English
|
||||||
|
"مرحبا بالعالم!", // Arabic
|
||||||
|
"Bonjour le monde!", // French
|
||||||
|
"Γειά σου Κόσμε!", // Greek
|
||||||
|
"שלום עולם!", // Hebrew
|
||||||
|
"Привет мир!", // Russian
|
||||||
|
"こんにちは世界!" // Japanese
|
||||||
|
};
|
||||||
|
static const char * const styles[] = // Font style names
|
||||||
|
{
|
||||||
|
"TTF_STYLE_NORMAL",
|
||||||
|
"TTF_STYLE_ITALIC",
|
||||||
|
"TTF_STYLE_OBLIQUE"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
printf("ttfCreate(\"%s\"): ", filename);
|
||||||
|
if ((font = ttfCreate(filename, 0, error_cb, NULL)) != NULL)
|
||||||
|
puts("PASS");
|
||||||
|
else
|
||||||
|
errors ++;
|
||||||
|
|
||||||
|
fputs("ttfGetAscent: ", stdout);
|
||||||
|
if ((intvalue = ttfGetAscent(font)) > 0)
|
||||||
|
{
|
||||||
|
printf("PASS (%d)\n", intvalue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("FAIL (%d)\n", intvalue);
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetBounds: ", stdout);
|
||||||
|
if (ttfGetBounds(font, &bounds))
|
||||||
|
{
|
||||||
|
printf("PASS (%g %g %g %g)\n", bounds.left, bounds.bottom, bounds.right, bounds.top);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetCapHeight: ", stdout);
|
||||||
|
if ((intvalue = ttfGetCapHeight(font)) > 0)
|
||||||
|
{
|
||||||
|
printf("PASS (%d)\n", intvalue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("FAIL (%d)\n", intvalue);
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetCopyright: ", stdout);
|
||||||
|
if ((value = ttfGetCopyright(font)) != NULL)
|
||||||
|
{
|
||||||
|
printf("PASS (%s)\n", value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < (int)(sizeof(strings) / sizeof(strings[0])); i ++)
|
||||||
|
{
|
||||||
|
printf("ttfGetExtents(\"%s\"): ", strings[i]);
|
||||||
|
if (ttfGetExtents(font, 12.0f, strings[i], &extents))
|
||||||
|
{
|
||||||
|
printf("PASS (%.1f %.1f %.1f %.1f)\n", extents.left, extents.bottom, extents.right, extents.top);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetFamily: ", stdout);
|
||||||
|
if ((value = ttfGetFamily(font)) != NULL)
|
||||||
|
{
|
||||||
|
printf("PASS (%s)\n", value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetItalicAngle: ", stdout);
|
||||||
|
if ((realvalue = ttfGetItalicAngle(font)) >= 0.0)
|
||||||
|
{
|
||||||
|
printf("PASS (%g)\n", realvalue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("FAIL (%g)\n", realvalue);
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetNumFonts: ", stdout);
|
||||||
|
if ((num_fonts = ttfGetNumFonts(font)) > 0)
|
||||||
|
{
|
||||||
|
printf("PASS (%u)\n", (unsigned)num_fonts);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetPostScriptName: ", stdout);
|
||||||
|
if ((value = ttfGetPostScriptName(font)) != NULL)
|
||||||
|
{
|
||||||
|
printf("PASS (%s)\n", value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetStretch: ", stdout);
|
||||||
|
if ((intvalue = (int)ttfGetStretch(font)) >= TTF_STRETCH_NORMAL && intvalue <= TTF_STRETCH_ULTRA_EXPANDED)
|
||||||
|
{
|
||||||
|
printf("PASS (%s)\n", stretches[intvalue]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("FAIL (%d)\n", intvalue);
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetStyle: ", stdout);
|
||||||
|
if ((style = ttfGetStyle(font)) >= TTF_STYLE_NORMAL && style <= TTF_STYLE_ITALIC)
|
||||||
|
{
|
||||||
|
printf("PASS (%s)\n", styles[style]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetVersion: ", stdout);
|
||||||
|
if ((value = ttfGetVersion(font)) != NULL)
|
||||||
|
{
|
||||||
|
printf("PASS (%s)\n", value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetWeight: ", stdout);
|
||||||
|
if ((weight = ttfGetWeight(font)) >= 0)
|
||||||
|
{
|
||||||
|
printf("PASS (%u)\n", (unsigned)weight);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetWidth(' '): ", stdout);
|
||||||
|
if ((intvalue = ttfGetWidth(font, ' ')) > 0)
|
||||||
|
{
|
||||||
|
printf("PASS (%d)\n", intvalue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("FAIL (%d)\n", intvalue);
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfGetXHeight: ", stdout);
|
||||||
|
if ((intvalue = ttfGetXHeight(font)) > 0)
|
||||||
|
{
|
||||||
|
printf("PASS (%d)\n", intvalue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("FAIL (%d)\n", intvalue);
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("ttfIsFixedPitch: ", stdout);
|
||||||
|
if (ttfIsFixedPitch(font))
|
||||||
|
puts("PASS (true)");
|
||||||
|
else
|
||||||
|
puts("PASS (false)");
|
||||||
|
|
||||||
|
ttfDelete(font);
|
||||||
|
|
||||||
|
return (errors);
|
||||||
|
}
|
24
ttf.c
24
ttf.c
@ -75,6 +75,7 @@ typedef __int64 ssize_t; // POSIX type not present on Windows...
|
|||||||
// DEBUG is defined and is a no-op otherwise...
|
// DEBUG is defined and is a no-op otherwise...
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#define DEBUG
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
# define TTF_DEBUG(...) fprintf(stderr, __VA_ARGS__)
|
# define TTF_DEBUG(...) fprintf(stderr, __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
@ -448,7 +449,7 @@ ttfCreate(const char *filename, // I - Filename
|
|||||||
font->cap_height = font->ascent;
|
font->cap_height = font->ascent;
|
||||||
|
|
||||||
if (font->x_height == 0)
|
if (font->x_height == 0)
|
||||||
font->x_height = 3 * font->ascent / 5;
|
font->x_height = 3 * font->ascent / 5;
|
||||||
|
|
||||||
// Build a sparse glyph widths table...
|
// Build a sparse glyph widths table...
|
||||||
font->min_char = -1;
|
font->min_char = -1;
|
||||||
@ -458,7 +459,8 @@ ttfCreate(const char *filename, // I - Filename
|
|||||||
if (font->cmap[i] >= 0)
|
if (font->cmap[i] >= 0)
|
||||||
{
|
{
|
||||||
int bin = (int)i / 256, // Sub-array bin
|
int bin = (int)i / 256, // Sub-array bin
|
||||||
glyph = font->cmap[i]; // Glyph index
|
glyph = font->cmap[i] + 1;
|
||||||
|
// Glyph index (+1 to get past .notdef)
|
||||||
|
|
||||||
// Update min/max...
|
// Update min/max...
|
||||||
if (font->min_char < 0)
|
if (font->min_char < 0)
|
||||||
@ -687,9 +689,6 @@ ttfGetExtents(
|
|||||||
ch = *s++;
|
ch = *s++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue #1: Offset past ".notdef"...
|
|
||||||
ch ++;
|
|
||||||
|
|
||||||
// Find its width...
|
// Find its width...
|
||||||
if ((widths = font->widths[ch / 256]) != NULL)
|
if ((widths = font->widths[ch / 256]) != NULL)
|
||||||
{
|
{
|
||||||
@ -855,17 +854,14 @@ int // O - Width in 1000ths
|
|||||||
ttfGetWidth(ttf_t *font, // I - Font
|
ttfGetWidth(ttf_t *font, // I - Font
|
||||||
int ch) // I - Unicode character
|
int ch) // I - Unicode character
|
||||||
{
|
{
|
||||||
int bin; // Bin in widths array
|
ch --;
|
||||||
|
int bin = ch >> 8; // Bin in widths array
|
||||||
|
|
||||||
|
|
||||||
// Range check input...
|
// Range check input...
|
||||||
if (!font || ch < ' ' || ch == 0x7f)
|
if (!font || ch < ' ' || ch == 0x7f)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
// Issue #1: Offset past ".notdef"...
|
|
||||||
ch ++;
|
|
||||||
bin = ch >> 8;
|
|
||||||
|
|
||||||
if (font->widths[bin])
|
if (font->widths[bin])
|
||||||
return ((int)(1000.0f * font->widths[bin][ch & 255].width / font->units));
|
return ((int)(1000.0f * font->widths[bin][ch & 255].width / font->units));
|
||||||
else if (font->widths[0]) // .notdef
|
else if (font->widths[0]) // .notdef
|
||||||
@ -1309,17 +1305,17 @@ read_cmap(ttf_t *font) // I - Font
|
|||||||
{
|
{
|
||||||
// Use an "obscure indexing trick" (words from the spec, not
|
// Use an "obscure indexing trick" (words from the spec, not
|
||||||
// mine) to look up the glyph index...
|
// mine) to look up the glyph index...
|
||||||
temp = segment->idRangeOffset / 2 + ch - segment->startCode + seg - segCount - 1;
|
temp = segment->idRangeOffset / 2 + ch - segment->startCode + seg - segCount;
|
||||||
|
|
||||||
if (temp < 0 || temp >= numGlyphIdArray || !glyphIdArray[temp])
|
if (temp < 0 || temp >= numGlyphIdArray)
|
||||||
glyph = -1;
|
glyph = -1;
|
||||||
else
|
else
|
||||||
glyph = ((glyphIdArray[temp] + segment->idDelta) & 65535) - 1;
|
glyph = (glyphIdArray[temp] + segment->idDelta) & 65535;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Just use idDelta to compute a glyph index...
|
// Just use idDelta to compute a glyph index...
|
||||||
glyph = ((ch + segment->idDelta) & 65535) - 1;
|
glyph = (ch + segment->idDelta) & 65535;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmapptr[ch] = glyph;
|
cmapptr[ch] = glyph;
|
||||||
|
Loading…
Reference in New Issue
Block a user