Add code to convert between WOFF<->sfnt font files

This commit is contained in:
Kovid Goyal 2012-10-21 15:09:07 +05:30
parent 7e96216b58
commit 93b2f860f9
8 changed files with 1694 additions and 2 deletions

View File

@ -50,9 +50,9 @@ class Extension(object):
reflow_sources = glob.glob(os.path.join(SRC, 'calibre', 'ebooks', 'pdf', '*.cpp'))
reflow_headers = glob.glob(os.path.join(SRC, 'calibre', 'ebooks', 'pdf', '*.h'))
pdfreflow_libs = []
woff_libs = ['z']
if iswindows:
pdfreflow_libs = ['advapi32', 'User32', 'Gdi32', 'zlib']
woff_libs = ['zlib']
icu_libs = ['icudata', 'icui18n', 'icuuc', 'icuio']
icu_cflags = []
@ -132,6 +132,16 @@ extensions = [
lib_dirs=[fc_lib],
error=fc_error),
Extension('woff',
['calibre/utils/fonts/woff/main.c',
'calibre/utils/fonts/woff/woff.c'],
headers=[
'calibre/utils/fonts/woff/woff.h',
'calibre/utils/fonts/woff/woff-private.h'],
libraries=woff_libs
),
Extension('msdes',
['calibre/utils/msdes/msdesmodule.c',
'calibre/utils/msdes/des.c'],

View File

@ -90,6 +90,7 @@ class Plugins(collections.Mapping):
'icu',
'speedup',
'freetype',
'woff',
]
if iswindows:
plugins.extend(['winutil', 'wpd', 'winfonts'])

View File

@ -114,6 +114,10 @@ def test_wpd():
else:
wpd.uninit()
def test_woff():
from calibre.utils.fonts.woff import test
test()
def test():
test_plugins()
test_lxml()
@ -124,6 +128,7 @@ def test():
test_imaging()
test_unrar()
test_icu()
test_woff()
if iswindows:
test_win32()
test_winutil()

View File

@ -0,0 +1,36 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from calibre.constants import plugins
def get_woff():
woff, woff_err = plugins['woff']
if woff_err:
raise RuntimeError('Failed to load the WOFF plugin: %s'%woff_err)
return woff
def to_woff(raw):
woff = get_woff()
return woff.to_woff(raw)
def from_woff(raw):
woff = get_woff()
return woff.from_woff(raw)
def test():
sfnt = P('fonts/calibreSymbols.otf', data=True)
woff = to_woff(sfnt)
recon = from_woff(woff)
if recon != sfnt:
raise ValueError('WOFF roundtrip resulted in different sfnt')
if __name__ == '__main__':
test()

View File

@ -0,0 +1,108 @@
/*
* main.c
* Copyright (C) 2012 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#define _UNICODE
#define UNICODE
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "woff.h"
static PyObject *WOFFError = NULL;
static PyObject* woff_err(uint32_t status) {
const char *msg;
switch(status) {
case eWOFF_out_of_memory:
return PyErr_NoMemory();
case eWOFF_invalid:
msg = "Invalid input data"; break;
case eWOFF_compression_failure:
msg = "Compression failed"; break;
case eWOFF_bad_signature:
msg = "Bad font signature"; break;
case eWOFF_buffer_too_small:
msg = "Buffer too small"; break;
case eWOFF_bad_parameter:
msg = "Bad parameter"; break;
case eWOFF_illegal_order:
msg = "Illegal order of WOFF chunks"; break;
default:
msg = "Unknown Error";
}
PyErr_SetString(WOFFError, msg);
return NULL;
}
static PyObject*
to_woff(PyObject *self, PyObject *args) {
const char *sfnt;
char *woff = NULL;
Py_ssize_t sz;
uint32_t wofflen = 0, status = eWOFF_ok;
PyObject *ans;
if (!PyArg_ParseTuple(args, "s#", &sfnt, &sz)) return NULL;
woff = (char*)woffEncode((uint8_t*)sfnt, sz, 0, 0, &wofflen, &status);
if (WOFF_FAILURE(status) || woff == NULL) return woff_err(status);
ans = Py_BuildValue("s#", woff, wofflen);
free(woff);
return ans;
}
static PyObject*
from_woff(PyObject *self, PyObject *args) {
const char *woff;
char *sfnt;
Py_ssize_t sz;
uint32_t sfntlen = 0, status = eWOFF_ok;
PyObject *ans;
if (!PyArg_ParseTuple(args, "s#", &woff, &sz)) return NULL;
sfnt = (char*)woffDecode((uint8_t*)woff, sz, &sfntlen, &status);
if (WOFF_FAILURE(status) || sfnt == NULL) return woff_err(status);
ans = Py_BuildValue("s#", sfnt, sfntlen);
free(sfnt);
return ans;
}
static
PyMethodDef methods[] = {
{"to_woff", (PyCFunction)to_woff, METH_VARARGS,
"to_woff(bytestring) -> Convert the sfnt data in bytestring to WOFF format (returned as a bytestring)."
},
{"from_woff", (PyCFunction)from_woff, METH_VARARGS,
"from_woff(bytestring) -> Convert the woff data in bytestring to SFNT format (returned as a bytestring)."
},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC
initwoff(void) {
PyObject *m;
m = Py_InitModule3(
"woff", methods,
"Convert to/from the WOFF<->sfnt font formats"
);
if (m == NULL) return;
WOFFError = PyErr_NewException((char*)"woff.WOFFError", NULL, NULL);
if (WOFFError == NULL) return;
PyModule_AddObject(m, "WOFFError", WOFFError);
}

View File

@ -0,0 +1,151 @@
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is WOFF font packaging code.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jonathan Kew <jfkthame@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef WOFF_PRIVATE_H_
#define WOFF_PRIVATE_H_
#include "woff.h"
/* private definitions used in the WOFF encoder/decoder functions */
/* create an OT tag from 4 characters */
#define TAG(a,b,c,d) ((a)<<24 | (b)<<16 | (c)<<8 | (d))
#define WOFF_SIGNATURE TAG('w','O','F','F')
#define SFNT_VERSION_CFF TAG('O','T','T','O')
#define SFNT_VERSION_TT 0x00010000
#define SFNT_VERSION_true TAG('t','r','u','e')
#define TABLE_TAG_DSIG TAG('D','S','I','G')
#define TABLE_TAG_head TAG('h','e','a','d')
#define TABLE_TAG_bhed TAG('b','h','e','d')
#define SFNT_CHECKSUM_CALC_CONST 0xB1B0AFBAU /* from the TT/OT spec */
#ifdef WOFF_MOZILLA_CLIENT
# include <prnetdb.h>
# define READ32BE(x) PR_ntohl(x)
# define READ16BE(x) PR_ntohs(x)
#else
/* These macros to read values as big-endian only work on "real" variables,
not general expressions, because of the use of &(x), but they are
designed to work on both BE and LE machines without the need for a
configure check. For production code, we might want to replace this
with something more efficient. */
/* read a 32-bit BigEndian value */
# define READ32BE(x) ( ( (uint32_t) ((uint8_t*)&(x))[0] << 24 ) + \
( (uint32_t) ((uint8_t*)&(x))[1] << 16 ) + \
( (uint32_t) ((uint8_t*)&(x))[2] << 8 ) + \
(uint32_t) ((uint8_t*)&(x))[3] )
/* read a 16-bit BigEndian value */
# define READ16BE(x) ( ( (uint16_t) ((uint8_t*)&(x))[0] << 8 ) + \
(uint16_t) ((uint8_t*)&(x))[1] )
#endif
#pragma pack(push,1)
typedef struct {
uint32_t version;
uint16_t numTables;
uint16_t searchRange;
uint16_t entrySelector;
uint16_t rangeShift;
} sfntHeader;
typedef struct {
uint32_t tag;
uint32_t checksum;
uint32_t offset;
uint32_t length;
} sfntDirEntry;
typedef struct {
uint32_t signature;
uint32_t flavor;
uint32_t length;
uint16_t numTables;
uint16_t reserved;
uint32_t totalSfntSize;
uint16_t majorVersion;
uint16_t minorVersion;
uint32_t metaOffset;
uint32_t metaCompLen;
uint32_t metaOrigLen;
uint32_t privOffset;
uint32_t privLen;
} woffHeader;
typedef struct {
uint32_t tag;
uint32_t offset;
uint32_t compLen;
uint32_t origLen;
uint32_t checksum;
} woffDirEntry;
typedef struct {
uint32_t version;
uint32_t fontRevision;
uint32_t checkSumAdjustment;
uint32_t magicNumber;
uint16_t flags;
uint16_t unitsPerEm;
uint32_t created[2];
uint32_t modified[2];
int16_t xMin;
int16_t yMin;
int16_t xMax;
int16_t yMax;
uint16_t macStyle;
uint16_t lowestRecPpem;
int16_t fontDirectionHint;
int16_t indexToLocFormat;
int16_t glyphDataFormat;
} sfntHeadTable;
#define HEAD_TABLE_SIZE 54 /* sizeof(sfntHeadTable) may report 56 because of alignment */
typedef struct {
uint32_t offset;
uint16_t oldIndex;
uint16_t newIndex;
} tableOrderRec;
#pragma pack(pop)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,211 @@
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is WOFF font packaging code.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jonathan Kew <jfkthame@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef WOFF_H_
#define WOFF_H_
/* API for the WOFF encoder and decoder */
#ifdef _MSC_VER /* MS VC lacks inttypes.h
but we can make do with a few definitons here */
typedef char int8_t;
typedef short int16_t;
typedef int int32_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#else
#include <inttypes.h>
#endif
#include <stdio.h> /* only for FILE, needed for woffPrintStatus */
/* error codes returned in the status parameter of WOFF functions */
enum {
/* Success */
eWOFF_ok = 0,
/* Errors: no valid result returned */
eWOFF_out_of_memory = 1, /* malloc or realloc failed */
eWOFF_invalid = 2, /* invalid input file (e.g., bad offset) */
eWOFF_compression_failure = 3, /* error in zlib call */
eWOFF_bad_signature = 4, /* unrecognized file signature */
eWOFF_buffer_too_small = 5, /* the provided buffer is too small */
eWOFF_bad_parameter = 6, /* bad parameter (e.g., null source ptr) */
eWOFF_illegal_order = 7, /* improperly ordered chunks in WOFF font */
/* Warnings: call succeeded but something odd was noticed.
Multiple warnings may be OR'd together. */
eWOFF_warn_unknown_version = 0x0100, /* unrecognized version of sfnt,
not standard TrueType or CFF */
eWOFF_warn_checksum_mismatch = 0x0200, /* bad checksum, use with caution;
any DSIG will be invalid */
eWOFF_warn_misaligned_table = 0x0400, /* table not long-aligned; fixing,
but DSIG will be invalid */
eWOFF_warn_trailing_data = 0x0800, /* trailing junk discarded,
any DSIG may be invalid */
eWOFF_warn_unpadded_table = 0x1000, /* sfnt not correctly padded,
any DSIG may be invalid */
eWOFF_warn_removed_DSIG = 0x2000 /* removed digital signature
while fixing checksum errors */
};
/* Note: status parameters must be initialized to eWOFF_ok before calling
WOFF functions. If the status parameter contains an error code,
functions will return immediately. */
#define WOFF_SUCCESS(status) (((uint32_t)(status) & 0xff) == eWOFF_ok)
#define WOFF_FAILURE(status) (!WOFF_SUCCESS(status))
#define WOFF_WARNING(status) ((uint32_t)(status) & ~0xff)
#ifdef __cplusplus
extern "C" {
#endif
#ifndef WOFF_DISABLE_ENCODING
/*****************************************************************************
* Returns a new malloc() block containing the encoded data, or NULL on error;
* caller should free() this when finished with it.
* Returns length of the encoded data in woffLen.
* The new WOFF has no metadata or private block;
* see the following functions to update these elements.
*/
const uint8_t * woffEncode(const uint8_t * sfntData, uint32_t sfntLen,
uint16_t majorVersion, uint16_t minorVersion,
uint32_t * woffLen, uint32_t * status);
/*****************************************************************************
* Add the given metadata block to the WOFF font, replacing any existing
* metadata block. The block will be zlib-compressed.
* Metadata is required to be valid XML (use of UTF-8 is recommended),
* though this function does not currently check this.
* The woffData pointer must be a malloc() block (typically from woffEncode);
* it will be freed by this function and a new malloc() block will be returned.
* Returns NULL if an error occurs, in which case the original WOFF is NOT freed.
*/
const uint8_t * woffSetMetadata(const uint8_t * woffData, uint32_t * woffLen,
const uint8_t * metaData, uint32_t metaLen,
uint32_t * status);
/*****************************************************************************
* Add the given private data block to the WOFF font, replacing any existing
* private block. The block will NOT be zlib-compressed.
* Private data may be any arbitrary block of bytes; it may be externally
* compressed by the client if desired.
* The woffData pointer must be a malloc() block (typically from woffEncode);
* it will be freed by this function and a new malloc() block will be returned.
* Returns NULL if an error occurs, in which case the original WOFF is NOT freed.
*/
const uint8_t * woffSetPrivateData(const uint8_t * woffData, uint32_t * woffLen,
const uint8_t * privData, uint32_t privLen,
uint32_t * status);
#endif /* WOFF_DISABLE_ENCODING */
/*****************************************************************************
* Returns the size of buffer needed to decode the font (or zero on error).
*/
uint32_t woffGetDecodedSize(const uint8_t * woffData, uint32_t woffLen,
uint32_t * pStatus);
/*****************************************************************************
* Decodes WOFF font to a caller-supplied buffer of size bufferLen.
* Returns the actual size of the decoded sfnt data in pActualSfntLen
* (must be <= bufferLen, otherwise an error will be returned).
*/
void woffDecodeToBuffer(const uint8_t * woffData, uint32_t woffLen,
uint8_t * sfntData, uint32_t bufferLen,
uint32_t * pActualSfntLen, uint32_t * pStatus);
/*****************************************************************************
* Returns a new malloc() block containing the decoded data, or NULL on error;
* caller should free() this when finished with it.
* Returns length of the decoded data in sfntLen.
*/
const uint8_t * woffDecode(const uint8_t * woffData, uint32_t woffLen,
uint32_t * sfntLen, uint32_t * status);
/*****************************************************************************
* Returns a new malloc() block containing the metadata from the WOFF font,
* or NULL if an error occurs or no metadata is present.
* Length of the metadata is returned in metaLen.
* The metadata is decompressed before returning.
*/
const uint8_t * woffGetMetadata(const uint8_t * woffData, uint32_t woffLen,
uint32_t * metaLen, uint32_t * status);
/*****************************************************************************
* Returns a new malloc() block containing the private data from the WOFF font,
* or NULL if an error occurs or no private data is present.
* Length of the private data is returned in privLen.
*/
const uint8_t * woffGetPrivateData(const uint8_t * woffData, uint32_t woffLen,
uint32_t * privLen, uint32_t * status);
/*****************************************************************************
* Returns the font version numbers from the WOFF font in the major and minor
* parameters.
* Check the status result to know if the function succeeded.
*/
void woffGetFontVersion(const uint8_t * woffData, uint32_t woffLen,
uint16_t * major, uint16_t * minor,
uint32_t * status);
/*****************************************************************************
* Utility to print warning and/or error status to the specified FILE*.
* The prefix string will be prepended to each line (ok to pass NULL if no
* prefix is wanted).
* (Provides terse English messages only, not intended for end-user display;
* user-friendly tools should map the status codes to their own messages.)
*/
void woffPrintStatus(FILE * f, uint32_t status, const char * prefix);
#ifdef __cplusplus
}
#endif
#endif