mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2025-07-13 14:34:28 +02:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
9fec2195d0 | |||
8ccbdaed94 | |||
4804db38a5 | |||
ddd984215a | |||
efe7c01015 | |||
600fa4ce59 | |||
688810f143 | |||
858cc101b6 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -13,4 +13,5 @@
|
|||||||
/pdfiototext
|
/pdfiototext
|
||||||
/testpdfio
|
/testpdfio
|
||||||
/testpdfio-*.pdf
|
/testpdfio-*.pdf
|
||||||
|
/testttf
|
||||||
/x64
|
/x64
|
||||||
|
@ -2,6 +2,13 @@ Changes in PDFio
|
|||||||
================
|
================
|
||||||
|
|
||||||
|
|
||||||
|
v1.1.3 (November 15, 2023)
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
- Fixed Unicode font support (Issue #16)
|
||||||
|
- Fixed missing initializer for 40-bit RC4 encryption (Issue #51)
|
||||||
|
|
||||||
|
|
||||||
v1.1.2 (October 10, 2023)
|
v1.1.2 (October 10, 2023)
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
15
Makefile
15
Makefile
@ -29,7 +29,7 @@ DSONAME =
|
|||||||
LDFLAGS =
|
LDFLAGS =
|
||||||
LIBS = -lm -lz
|
LIBS = -lm -lz
|
||||||
RANLIB = ranlib
|
RANLIB = ranlib
|
||||||
VERSION = 1.1.2
|
VERSION = 1.1.3
|
||||||
prefix = /usr/local
|
prefix = /usr/local
|
||||||
|
|
||||||
|
|
||||||
@ -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) $(COMMONFLAGS) -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>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
.TH pdfio 3 "pdf read/write library" "2023-10-06" "pdf read/write library"
|
.TH pdfio 3 "pdf read/write library" "2023-11-15" "pdf read/write library"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
pdfio \- pdf read/write library
|
pdfio \- pdf read/write library
|
||||||
.SH Introduction
|
.SH Introduction
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en-US">
|
<html lang="en-US">
|
||||||
<head>
|
<head>
|
||||||
<title>PDFio Programming Manual v1.1.2</title>
|
<title>PDFio Programming Manual v1.1.3</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||||
<meta name="generator" content="codedoc v3.7">
|
<meta name="generator" content="codedoc v3.7">
|
||||||
<meta name="author" content="Michael R Sweet">
|
<meta name="author" content="Michael R Sweet">
|
||||||
<meta name="language" content="en-US">
|
<meta name="language" content="en-US">
|
||||||
<meta name="copyright" content="Copyright © 2021-2023 by Michael R Sweet">
|
<meta name="copyright" content="Copyright © 2021-2023 by Michael R Sweet">
|
||||||
<meta name="version" content="1.1.2">
|
<meta name="version" content="1.1.3">
|
||||||
<style type="text/css"><!--
|
<style type="text/css"><!--
|
||||||
body {
|
body {
|
||||||
background: white;
|
background: white;
|
||||||
@ -245,7 +245,7 @@ span.string {
|
|||||||
<body>
|
<body>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<p><img class="title" src="pdfio-512.png"></p>
|
<p><img class="title" src="pdfio-512.png"></p>
|
||||||
<h1 class="title">PDFio Programming Manual v1.1.2</h1>
|
<h1 class="title">PDFio Programming Manual v1.1.3</h1>
|
||||||
<p>Michael R Sweet</p>
|
<p>Michael R Sweet</p>
|
||||||
<p>Copyright © 2021-2023 by Michael R Sweet</p>
|
<p>Copyright © 2021-2023 by Michael R Sweet</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -375,9 +375,9 @@ _pdfioFileSeek(pdfio_file_t *pdf, // I - PDF file
|
|||||||
if (whence != SEEK_END && offset >= pdf->bufpos && offset < (pdf->bufpos + pdf->bufend - pdf->buffer))
|
if (whence != SEEK_END && offset >= pdf->bufpos && offset < (pdf->bufpos + pdf->bufend - pdf->buffer))
|
||||||
{
|
{
|
||||||
// Yes, seek within existing buffer...
|
// Yes, seek within existing buffer...
|
||||||
pdf->bufptr = pdf->buffer + offset - pdf->bufpos;
|
pdf->bufptr = pdf->buffer + (offset - pdf->bufpos);
|
||||||
PDFIO_DEBUG("_pdfioFileSeek: Seek within buffer, bufpos=%ld.\n", (long)pdf->bufpos);
|
PDFIO_DEBUG("_pdfioFileSeek: Seek within buffer, bufpos=%ld.\n", (long)pdf->bufpos);
|
||||||
PDFIO_DEBUG("_pdfioFileSeek: buffer=%p, bufptr=%p, bufend=%p\n", pdf->buffer, pdf->bufptr, pdf->bufend);
|
PDFIO_DEBUG("_pdfioFileSeek: buffer=%p, bufptr=%p(<%02X%02X...>), bufend=%p\n", pdf->buffer, pdf->bufptr, pdf->bufptr[0] & 255, pdf->bufptr[1] & 255, pdf->bufend);
|
||||||
return (offset);
|
return (offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1410,6 +1410,7 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
pdfio_dict_t *cid2gid; // CIDToGIDMap dictionary
|
pdfio_dict_t *cid2gid; // CIDToGIDMap dictionary
|
||||||
pdfio_obj_t *cid2gid_obj; // CIDToGIDMap object
|
pdfio_obj_t *cid2gid_obj; // CIDToGIDMap object
|
||||||
size_t i, // Looping var
|
size_t i, // Looping var
|
||||||
|
start, // Start character
|
||||||
num_cmap; // Number of CMap entries
|
num_cmap; // Number of CMap entries
|
||||||
const int *cmap; // CMap entries
|
const int *cmap; // CMap entries
|
||||||
unsigned char *bufptr, // Pointer into buffer
|
unsigned char *bufptr, // Pointer into buffer
|
||||||
@ -1418,6 +1419,9 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
pdfio_obj_t *type2_obj; // CIDFontType2 font object
|
pdfio_obj_t *type2_obj; // CIDFontType2 font object
|
||||||
pdfio_array_t *descendants; // Decendant font list
|
pdfio_array_t *descendants; // Decendant font list
|
||||||
pdfio_dict_t *sidict; // CIDSystemInfo dictionary
|
pdfio_dict_t *sidict; // CIDSystemInfo dictionary
|
||||||
|
pdfio_array_t *w_array, // Width array
|
||||||
|
*temp_array; // Temporary width sub-array
|
||||||
|
int w0, w1; // Widths
|
||||||
|
|
||||||
// Create a CIDToGIDMap object for the Unicode font...
|
// Create a CIDToGIDMap object for the Unicode font...
|
||||||
if ((cid2gid = pdfioDictCreate(pdf)) == NULL)
|
if ((cid2gid = pdfioDictCreate(pdf)) == NULL)
|
||||||
@ -1506,9 +1510,57 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Width array
|
||||||
|
if ((w_array = pdfioArrayCreate(pdf)) == NULL)
|
||||||
|
{
|
||||||
|
ttfDelete(font);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (start = 0, w0 = ttfGetWidth(font, 0), i = 1; i < 65536; start = i, w0 = w1, i ++)
|
||||||
|
{
|
||||||
|
while (i < 65536 && (w1 = ttfGetWidth(font, i)) == w0)
|
||||||
|
i ++;
|
||||||
|
|
||||||
|
if ((i - start) > 1)
|
||||||
|
{
|
||||||
|
// Encode a repeating sequence...
|
||||||
|
pdfioArrayAppendNumber(w_array, start);
|
||||||
|
pdfioArrayAppendNumber(w_array, i - 1);
|
||||||
|
pdfioArrayAppendNumber(w_array, w0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Encode a non-repeating sequence...
|
||||||
|
pdfioArrayAppendNumber(w_array, start);
|
||||||
|
|
||||||
|
if ((temp_array = pdfioArrayCreate(pdf)) == NULL)
|
||||||
|
{
|
||||||
|
ttfDelete(font);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfioArrayAppendNumber(temp_array, w0);
|
||||||
|
for (w0 = w1, i ++; i < 65536; w0 = w1, i ++)
|
||||||
|
{
|
||||||
|
if ((w1 = ttfGetWidth(font, i)) == w0 && i < 65535)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pdfioArrayAppendNumber(temp_array, w0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 65536)
|
||||||
|
pdfioArrayAppendNumber(temp_array, w0);
|
||||||
|
else
|
||||||
|
i --;
|
||||||
|
|
||||||
|
pdfioArrayAppendArray(w_array, temp_array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CIDSystemInfo mapping to Adobe UCS2 v0 (Unicode)
|
// CIDSystemInfo mapping to Adobe UCS2 v0 (Unicode)
|
||||||
pdfioDictSetString(sidict, "Registry", "Adobe");
|
pdfioDictSetString(sidict, "Registry", "Adobe");
|
||||||
pdfioDictSetString(sidict, "Ordering", "Identity-H");
|
pdfioDictSetString(sidict, "Ordering", "Identity");
|
||||||
pdfioDictSetNumber(sidict, "Supplement", 0);
|
pdfioDictSetNumber(sidict, "Supplement", 0);
|
||||||
|
|
||||||
// Then the dictionary for the CID base font...
|
// Then the dictionary for the CID base font...
|
||||||
@ -1518,6 +1570,7 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
pdfioDictSetDict(type2, "CIDSystemInfo", sidict);
|
pdfioDictSetDict(type2, "CIDSystemInfo", sidict);
|
||||||
pdfioDictSetObj(type2, "CIDToGIDMap", cid2gid_obj);
|
pdfioDictSetObj(type2, "CIDToGIDMap", cid2gid_obj);
|
||||||
pdfioDictSetObj(type2, "FontDescriptor", desc_obj);
|
pdfioDictSetObj(type2, "FontDescriptor", desc_obj);
|
||||||
|
pdfioDictSetArray(type2, "W", w_array);
|
||||||
|
|
||||||
if ((type2_obj = pdfioFileCreateObj(pdf, type2)) == NULL)
|
if ((type2_obj = pdfioFileCreateObj(pdf, type2)) == NULL)
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Cryptographic support functions for PDFio.
|
// Cryptographic support functions for PDFio.
|
||||||
//
|
//
|
||||||
// Copyright © 2021 by Michael R Sweet.
|
// Copyright © 2021-2023 by Michael R Sweet.
|
||||||
//
|
//
|
||||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||||
// information.
|
// information.
|
||||||
@ -446,6 +446,7 @@ _pdfio_crypto_cb_t // O - Decryption callback or `NULL` for none
|
|||||||
|
|
||||||
// Initialize the RC4 context using 40 bits of the digest...
|
// Initialize the RC4 context using 40 bits of the digest...
|
||||||
_pdfioCryptoRC4Init(&ctx->rc4, digest, 5);
|
_pdfioCryptoRC4Init(&ctx->rc4, digest, 5);
|
||||||
|
*ivlen = 0;
|
||||||
return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt);
|
return ((_pdfio_crypto_cb_t)_pdfioCryptoRC4Crypt);
|
||||||
|
|
||||||
case PDFIO_ENCRYPTION_RC4_128 :
|
case PDFIO_ENCRYPTION_RC4_128 :
|
||||||
|
15
pdfio-file.c
15
pdfio-file.c
@ -1514,6 +1514,7 @@ load_obj_stream(pdfio_obj_t *obj) // I - Object to load
|
|||||||
|
|
||||||
// Skip offset
|
// Skip offset
|
||||||
_pdfioTokenGet(&tb, buffer, sizeof(buffer));
|
_pdfioTokenGet(&tb, buffer, sizeof(buffer));
|
||||||
|
PDFIO_DEBUG("load_obj_stream: %ld at offset %s\n", (long)number, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!buffer[0])
|
if (!buffer[0])
|
||||||
@ -1865,8 +1866,18 @@ load_xref(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i >= num_sobjs && num_sobjs < (sizeof(sobjs) / sizeof(sobjs[0])))
|
if (i >= num_sobjs)
|
||||||
sobjs[num_sobjs ++] = (size_t)offset;
|
{
|
||||||
|
if (num_sobjs < (sizeof(sobjs) / sizeof(sobjs[0])))
|
||||||
|
{
|
||||||
|
sobjs[num_sobjs ++] = (size_t)offset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "Too many object streams.");
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!current)
|
else if (!current)
|
||||||
{
|
{
|
||||||
|
@ -452,6 +452,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFIO_DEBUG("_pdfioStreamOpen: ivlen=%d\n", (int)ivlen);
|
||||||
if (ivlen > 0)
|
if (ivlen > 0)
|
||||||
_pdfioFileConsume(st->pdf, ivlen);
|
_pdfioFileConsume(st->pdf, ivlen);
|
||||||
|
|
||||||
@ -567,6 +568,7 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
|
|||||||
else
|
else
|
||||||
st->predictor = _PDFIO_PREDICTOR_NONE;
|
st->predictor = _PDFIO_PREDICTOR_NONE;
|
||||||
|
|
||||||
|
PDFIO_DEBUG("_pdfioStreamOpen: pos=%ld\n", (long)_pdfioFileTell(st->pdf));
|
||||||
if (sizeof(st->cbuffer) > st->remaining)
|
if (sizeof(st->cbuffer) > st->remaining)
|
||||||
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
|
rbytes = _pdfioFileRead(st->pdf, st->cbuffer, st->remaining);
|
||||||
else
|
else
|
||||||
|
2
pdfio.h
2
pdfio.h
@ -23,7 +23,7 @@ extern "C" {
|
|||||||
// Version number...
|
// Version number...
|
||||||
//
|
//
|
||||||
|
|
||||||
# define PDFIO_VERSION "1.1.2"
|
# define PDFIO_VERSION "1.1.3"
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<metadata>
|
<metadata>
|
||||||
<id>pdfio_native</id>
|
<id>pdfio_native</id>
|
||||||
<title>PDFio Library for VS2019+</title>
|
<title>PDFio Library for VS2019+</title>
|
||||||
<version>1.1.2</version>
|
<version>1.1.3</version>
|
||||||
<authors>Michael R Sweet</authors>
|
<authors>Michael R Sweet</authors>
|
||||||
<owners>michaelrsweet</owners>
|
<owners>michaelrsweet</owners>
|
||||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||||
@ -16,7 +16,7 @@
|
|||||||
<copyright>Copyright © 2019-2023 by Michael R Sweet</copyright>
|
<copyright>Copyright © 2019-2023 by Michael R Sweet</copyright>
|
||||||
<tags>pdf file native</tags>
|
<tags>pdf file native</tags>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="pdfio_native.redist" version="1.1.2" />
|
<dependency id="pdfio_native.redist" version="1.1.3" />
|
||||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<metadata>
|
<metadata>
|
||||||
<id>pdfio_native.redist</id>
|
<id>pdfio_native.redist</id>
|
||||||
<title>PDFio Library for VS2019+</title>
|
<title>PDFio Library for VS2019+</title>
|
||||||
<version>1.1.2</version>
|
<version>1.1.3</version>
|
||||||
<authors>Michael R Sweet</authors>
|
<authors>Michael R Sweet</authors>
|
||||||
<owners>michaelrsweet</owners>
|
<owners>michaelrsweet</owners>
|
||||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||||
|
23
testpdfio.c
23
testpdfio.c
@ -455,7 +455,7 @@ do_test_file(const char *filename, // I - PDF filename
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" Page #%d is %gx%g.\n", (int)n + 1, media_box.x2, media_box.y2);
|
printf(" Page #%d (obj %d) is %gx%g.\n", (int)n + 1, (int)pdfioObjGetNumber(obj), media_box.x2, media_box.y2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2391,24 +2391,11 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
fputs("pdfioFileCreateFontObjFromFile(OpenSans-Regular.ttf): ", stdout);
|
||||||
if (unicode)
|
if ((opensans = pdfioFileCreateFontObjFromFile(pdf, "testfiles/OpenSans-Regular.ttf", unicode)) != NULL)
|
||||||
{
|
puts("PASS");
|
||||||
fputs("pdfioFileCreateFontObjFromFile(NotoSansJP-Regular.otf): ", stdout);
|
|
||||||
if ((opensans = pdfioFileCreateFontObjFromFile(pdf, "testfiles/NotoSansJP-Regular.otf", true)) != NULL)
|
|
||||||
puts("PASS");
|
|
||||||
else
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
#endif // 0
|
return (1);
|
||||||
{
|
|
||||||
fputs("pdfioFileCreateFontObjFromFile(OpenSans-Regular.ttf): ", stdout);
|
|
||||||
if ((opensans = pdfioFileCreateFontObjFromFile(pdf, "testfiles/OpenSans-Regular.ttf", unicode)) != NULL)
|
|
||||||
puts("PASS");
|
|
||||||
else
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("pdfioDictCreate: ", stdout);
|
fputs("pdfioDictCreate: ", stdout);
|
||||||
if ((dict = pdfioDictCreate(pdf)) != NULL)
|
if ((dict = pdfioDictCreate(pdf)) != NULL)
|
||||||
|
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);
|
||||||
|
}
|
49
ttf.c
49
ttf.c
@ -71,7 +71,7 @@ typedef __int64 ssize_t; // POSIX type not present on Windows...
|
|||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// DEBUG is typically defined for debug builds. TTF_DEBUG maps to printf when
|
// DEBUG is typically defined for debug builds. TTF_DEBUG maps to fprintf when
|
||||||
// DEBUG is defined and is a no-op otherwise...
|
// DEBUG is defined and is a no-op otherwise...
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -448,7 +448,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;
|
||||||
@ -477,6 +477,11 @@ ttfCreate(const char *filename, // I - Filename
|
|||||||
else
|
else
|
||||||
font->widths[bin][i & 255] = widths[glyph];
|
font->widths[bin][i & 255] = widths[glyph];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (i >= ' ' && i < 127)
|
||||||
|
TTF_DEBUG("ttfCreate: width['%c']=%d(%d)\n", (char)i, font->widths[0][i].width, font->widths[0][i].left_bearing);
|
||||||
|
#endif // DEBUG
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup and return the font...
|
// Cleanup and return the font...
|
||||||
@ -687,9 +692,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)
|
||||||
{
|
{
|
||||||
@ -736,17 +738,6 @@ ttfGetFamily(ttf_t *font) // I - Font
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// 'ttfIsFixedPitch()' - Determine whether a font is fixedpitch.
|
|
||||||
//
|
|
||||||
|
|
||||||
bool // O - `true` if fixed pitch, `false` otherwise
|
|
||||||
ttfIsFixedPitch(ttf_t *font) // I - Font
|
|
||||||
{
|
|
||||||
return (font ? font->is_fixed : false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'ttfGetItalicAngle()' - Get the italic angle.
|
// 'ttfGetItalicAngle()' - Get the italic angle.
|
||||||
//
|
//
|
||||||
@ -855,13 +846,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 = ch >> 8; // Bin in widths array
|
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);
|
||||||
else 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
|
||||||
return ((int)(1000.0f * font->widths[0][0].width / font->units));
|
return ((int)(1000.0f * font->widths[0][0].width / font->units));
|
||||||
@ -881,6 +873,17 @@ ttfGetXHeight(ttf_t *font) // I - Font
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'ttfIsFixedPitch()' - Determine whether a font is fixedpitch.
|
||||||
|
//
|
||||||
|
|
||||||
|
bool // O - `true` if fixed pitch, `false` otherwise
|
||||||
|
ttfIsFixedPitch(ttf_t *font) // I - Font
|
||||||
|
{
|
||||||
|
return (font ? font->is_fixed : false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'copy_name()' - Copy a name string from a font.
|
// 'copy_name()' - Copy a name string from a font.
|
||||||
//
|
//
|
||||||
@ -1304,17 +1307,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;
|
||||||
@ -1581,6 +1584,8 @@ read_hmtx(ttf_t *font, // I - Font
|
|||||||
{
|
{
|
||||||
widths[i].width = (short)read_ushort(font);
|
widths[i].width = (short)read_ushort(font);
|
||||||
widths[i].left_bearing = (short)read_short(font);
|
widths[i].left_bearing = (short)read_short(font);
|
||||||
|
|
||||||
|
TTF_DEBUG("read_hmtx: widths[%d].width=%d, .left_bearing=%d\n", i, widths[i].width, widths[i].left_bearing);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (widths);
|
return (widths);
|
||||||
|
Reference in New Issue
Block a user