ttf2eot 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require "rake"
2
+ require "rake/extensiontask"
3
+
4
+ Rake::ExtensionTask.new('ttf2eot_ext')
@@ -0,0 +1,334 @@
1
+ /* Modified for use with ttf2eot, originally from WebKit. */
2
+
3
+ /*
4
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions
8
+ * are met:
9
+ * 1. Redistributions of source code must retain the above copyright
10
+ * notice, this list of conditions and the following disclaimer.
11
+ * 2. Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in the
13
+ * documentation and/or other materials provided with the distribution.
14
+ *
15
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ */
27
+
28
+ #include <string.h>
29
+ #include <vector>
30
+
31
+ #ifndef _MSC_VER
32
+ # include <stdint.h>
33
+ #else
34
+ typedef unsigned char uint8_t;
35
+ #endif
36
+
37
+ #include "OpenTypeUtilities.h"
38
+
39
+
40
+ using std::vector;
41
+
42
+ typedef unsigned Fixed;
43
+
44
+ #define DEFAULT_CHARSET 1
45
+
46
+ struct BigEndianUShort {
47
+ operator unsigned short() const { return (v & 0x00ff) << 8 | v >> 8; }
48
+ BigEndianUShort(unsigned short u) : v((u & 0x00ff) << 8 | u >> 8) { }
49
+ unsigned short v;
50
+ };
51
+
52
+ struct BigEndianULong {
53
+ operator unsigned() const { return (v & 0xff) << 24 | (v & 0xff00) << 8 | (v & 0xff0000) >> 8 | v >> 24; }
54
+ BigEndianULong(unsigned u) : v((u & 0xff) << 24 | (u & 0xff00) << 8 | (u & 0xff0000) >> 8 | u >> 24) { }
55
+ unsigned v;
56
+ };
57
+
58
+ #pragma pack(1)
59
+
60
+ struct EOTPrefix {
61
+ unsigned eotSize;
62
+ unsigned fontDataSize;
63
+ unsigned version;
64
+ unsigned flags;
65
+ uint8_t fontPANOSE[10];
66
+ uint8_t charset;
67
+ uint8_t italic;
68
+ unsigned weight;
69
+ unsigned short fsType;
70
+ unsigned short magicNumber;
71
+ unsigned unicodeRange[4];
72
+ unsigned codePageRange[2];
73
+ unsigned checkSumAdjustment;
74
+ unsigned reserved[4];
75
+ unsigned short padding1;
76
+ };
77
+
78
+ struct TableDirectoryEntry {
79
+ BigEndianULong tag;
80
+ BigEndianULong checkSum;
81
+ BigEndianULong offset;
82
+ BigEndianULong length;
83
+ };
84
+
85
+ struct sfntHeader {
86
+ Fixed version;
87
+ BigEndianUShort numTables;
88
+ BigEndianUShort searchRange;
89
+ BigEndianUShort entrySelector;
90
+ BigEndianUShort rangeShift;
91
+ TableDirectoryEntry tables[1];
92
+ };
93
+
94
+ struct OS2Table {
95
+ BigEndianUShort version;
96
+ BigEndianUShort avgCharWidth;
97
+ BigEndianUShort weightClass;
98
+ BigEndianUShort widthClass;
99
+ BigEndianUShort fsType;
100
+ BigEndianUShort subscriptXSize;
101
+ BigEndianUShort subscriptYSize;
102
+ BigEndianUShort subscriptXOffset;
103
+ BigEndianUShort subscriptYOffset;
104
+ BigEndianUShort superscriptXSize;
105
+ BigEndianUShort superscriptYSize;
106
+ BigEndianUShort superscriptXOffset;
107
+ BigEndianUShort superscriptYOffset;
108
+ BigEndianUShort strikeoutSize;
109
+ BigEndianUShort strikeoutPosition;
110
+ BigEndianUShort familyClass;
111
+ uint8_t panose[10];
112
+ BigEndianULong unicodeRange[4];
113
+ uint8_t vendID[4];
114
+ BigEndianUShort fsSelection;
115
+ BigEndianUShort firstCharIndex;
116
+ BigEndianUShort lastCharIndex;
117
+ BigEndianUShort typoAscender;
118
+ BigEndianUShort typoDescender;
119
+ BigEndianUShort typoLineGap;
120
+ BigEndianUShort winAscent;
121
+ BigEndianUShort winDescent;
122
+ BigEndianULong codePageRange[2];
123
+ BigEndianUShort xHeight;
124
+ BigEndianUShort capHeight;
125
+ BigEndianUShort defaultChar;
126
+ BigEndianUShort breakChar;
127
+ BigEndianUShort maxContext;
128
+ };
129
+
130
+ struct headTable {
131
+ Fixed version;
132
+ Fixed fontRevision;
133
+ BigEndianULong checkSumAdjustment;
134
+ BigEndianULong magicNumber;
135
+ BigEndianUShort flags;
136
+ BigEndianUShort unitsPerEm;
137
+ long long created;
138
+ long long modified;
139
+ BigEndianUShort xMin;
140
+ BigEndianUShort xMax;
141
+ BigEndianUShort yMin;
142
+ BigEndianUShort yMax;
143
+ BigEndianUShort macStyle;
144
+ BigEndianUShort lowestRectPPEM;
145
+ BigEndianUShort fontDirectionHint;
146
+ BigEndianUShort indexToLocFormat;
147
+ BigEndianUShort glyphDataFormat;
148
+ };
149
+
150
+ struct nameRecord {
151
+ BigEndianUShort platformID;
152
+ BigEndianUShort encodingID;
153
+ BigEndianUShort languageID;
154
+ BigEndianUShort nameID;
155
+ BigEndianUShort length;
156
+ BigEndianUShort offset;
157
+ };
158
+
159
+ struct nameTable {
160
+ BigEndianUShort format;
161
+ BigEndianUShort count;
162
+ BigEndianUShort stringOffset;
163
+ nameRecord nameRecords[1];
164
+ };
165
+
166
+ #pragma pack()
167
+
168
+ static void appendBigEndianStringToEOTHeader(vector<uint8_t>&eotHeader, const BigEndianUShort* string, unsigned short length)
169
+ {
170
+ size_t size = eotHeader.size();
171
+ eotHeader.resize(size + length + 2 * sizeof(unsigned short));
172
+ unsigned short* dst = reinterpret_cast<unsigned short*>(&eotHeader[0] + size);
173
+ unsigned i = 0;
174
+ dst[i++] = length;
175
+ unsigned numCharacters = length / 2;
176
+ for (unsigned j = 0; j < numCharacters; j++)
177
+ dst[i++] = string[j];
178
+ dst[i] = 0;
179
+ }
180
+
181
+ bool getEOTHeader(unsigned char* fontData, size_t fontSize, vector<uint8_t>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength)
182
+ {
183
+ overlayDst = 0;
184
+ overlaySrc = 0;
185
+ overlayLength = 0;
186
+
187
+ size_t dataLength = fontSize;
188
+ const char* data = (const char *) fontData;
189
+
190
+ eotHeader.resize(sizeof(EOTPrefix));
191
+ EOTPrefix* prefix = reinterpret_cast<EOTPrefix*>(&eotHeader[0]);
192
+
193
+ prefix->fontDataSize = dataLength;
194
+ prefix->version = 0x00020001;
195
+ prefix->flags = 0;
196
+
197
+ if (dataLength < offsetof(sfntHeader, tables))
198
+ return false;
199
+
200
+ const sfntHeader* sfnt = reinterpret_cast<const sfntHeader*>(data);
201
+
202
+ if (dataLength < offsetof(sfntHeader, tables) + sfnt->numTables * sizeof(TableDirectoryEntry))
203
+ return false;
204
+
205
+ bool haveOS2 = false;
206
+ bool haveHead = false;
207
+ bool haveName = false;
208
+
209
+ const BigEndianUShort* familyName = 0;
210
+ unsigned short familyNameLength = 0;
211
+ const BigEndianUShort* subfamilyName = 0;
212
+ unsigned short subfamilyNameLength = 0;
213
+ const BigEndianUShort* fullName = 0;
214
+ unsigned short fullNameLength = 0;
215
+ const BigEndianUShort* versionString = 0;
216
+ unsigned short versionStringLength = 0;
217
+
218
+ for (unsigned i = 0; i < sfnt->numTables; i++) {
219
+ unsigned tableOffset = sfnt->tables[i].offset;
220
+ unsigned tableLength = sfnt->tables[i].length;
221
+
222
+ if (dataLength < tableOffset || dataLength < tableLength || dataLength < tableOffset + tableLength)
223
+ return false;
224
+
225
+ unsigned tableTag = sfnt->tables[i].tag;
226
+ switch (tableTag) {
227
+ case 'OS/2':
228
+ {
229
+ if (dataLength < tableOffset + sizeof(OS2Table))
230
+ return false;
231
+
232
+ haveOS2 = true;
233
+ const OS2Table* OS2 = reinterpret_cast<const OS2Table*>(data + tableOffset);
234
+ for (unsigned j = 0; j < 10; j++)
235
+ prefix->fontPANOSE[j] = OS2->panose[j];
236
+ prefix->italic = OS2->fsSelection & 0x01;
237
+ prefix->weight = OS2->weightClass;
238
+ // FIXME: Should use OS2->fsType, but some TrueType fonts set it to an over-restrictive value.
239
+ // Since ATS does not enforce this on Mac OS X, we do not enforce it either.
240
+ prefix->fsType = 0;
241
+ for (unsigned j = 0; j < 4; j++)
242
+ prefix->unicodeRange[j] = OS2->unicodeRange[j];
243
+ for (unsigned j = 0; j < 2; j++)
244
+ prefix->codePageRange[j] = OS2->codePageRange[j];
245
+ break;
246
+ }
247
+ case 'head':
248
+ {
249
+ if (dataLength < tableOffset + sizeof(headTable))
250
+ return false;
251
+
252
+ haveHead = true;
253
+ const headTable* head = reinterpret_cast<const headTable*>(data + tableOffset);
254
+ prefix->checkSumAdjustment = head->checkSumAdjustment;
255
+ break;
256
+ }
257
+ case 'name':
258
+ {
259
+ if (dataLength < tableOffset + offsetof(nameTable, nameRecords))
260
+ return false;
261
+
262
+ haveName = true;
263
+ const nameTable* name = reinterpret_cast<const nameTable*>(data + tableOffset);
264
+ for (int j = 0; j < name->count; j++) {
265
+ if (dataLength < tableOffset + offsetof(nameTable, nameRecords) + (j + 1) * sizeof(nameRecord))
266
+ return false;
267
+ if (name->nameRecords[j].platformID == 3 && name->nameRecords[j].encodingID == 1 && name->nameRecords[j].languageID == 0x0409) {
268
+ if (dataLength < tableOffset + name->stringOffset + name->nameRecords[j].offset + name->nameRecords[j].length)
269
+ return false;
270
+
271
+ unsigned short nameLength = name->nameRecords[j].length;
272
+ const BigEndianUShort* nameString = reinterpret_cast<const BigEndianUShort*>(data + tableOffset + name->stringOffset + name->nameRecords[j].offset);
273
+
274
+ switch (name->nameRecords[j].nameID) {
275
+ case 1:
276
+ familyNameLength = nameLength;
277
+ familyName = nameString;
278
+ break;
279
+ case 2:
280
+ subfamilyNameLength = nameLength;
281
+ subfamilyName = nameString;
282
+ break;
283
+ case 4:
284
+ fullNameLength = nameLength;
285
+ fullName = nameString;
286
+ break;
287
+ case 5:
288
+ versionStringLength = nameLength;
289
+ versionString = nameString;
290
+ break;
291
+ default:
292
+ break;
293
+ }
294
+ }
295
+ }
296
+ break;
297
+ }
298
+ default:
299
+ break;
300
+ }
301
+ if (haveOS2 && haveHead && haveName)
302
+ break;
303
+ }
304
+
305
+ prefix->charset = DEFAULT_CHARSET;
306
+ prefix->magicNumber = 0x504c;
307
+ prefix->reserved[0] = 0;
308
+ prefix->reserved[1] = 0;
309
+ prefix->reserved[2] = 0;
310
+ prefix->reserved[3] = 0;
311
+ prefix->padding1 = 0;
312
+
313
+ appendBigEndianStringToEOTHeader(eotHeader, familyName, familyNameLength);
314
+ appendBigEndianStringToEOTHeader(eotHeader, subfamilyName, subfamilyNameLength);
315
+ appendBigEndianStringToEOTHeader(eotHeader, versionString, versionStringLength);
316
+
317
+ // If possible, ensure that the family name is a prefix of the full name.
318
+ if (fullNameLength >= familyNameLength && memcmp(familyName, fullName, familyNameLength)) {
319
+ overlaySrc = reinterpret_cast<const char*>(fullName) - data;
320
+ overlayDst = reinterpret_cast<const char*>(familyName) - data;
321
+ overlayLength = familyNameLength;
322
+ }
323
+
324
+ appendBigEndianStringToEOTHeader(eotHeader, fullName, fullNameLength);
325
+
326
+ unsigned short padding = 0;
327
+ eotHeader.push_back(padding);
328
+ eotHeader.push_back(padding);
329
+
330
+ prefix = reinterpret_cast<EOTPrefix*>(&eotHeader[0]);
331
+ prefix->eotSize = eotHeader.size() + fontSize;
332
+
333
+ return true;
334
+ }
@@ -0,0 +1,36 @@
1
+ /* Modified for use with ttf2eot, originally from WebKit. */
2
+
3
+ /*
4
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions
8
+ * are met:
9
+ * 1. Redistributions of source code must retain the above copyright
10
+ * notice, this list of conditions and the following disclaimer.
11
+ * 2. Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in the
13
+ * documentation and/or other materials provided with the distribution.
14
+ *
15
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ */
27
+
28
+ #ifndef OpenTypeUtilities_h
29
+ #define OpenTypeUtilities_h
30
+
31
+ using std::vector;
32
+
33
+ bool getEOTHeader(unsigned char * fontData, size_t fontSize, vector<uint8_t>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength);
34
+
35
+
36
+ #endif // OpenTypeUtilities_h
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+
3
+ create_makefile 'ttf2eot_ext'
@@ -0,0 +1,54 @@
1
+ #include <stdlib.h>
2
+ #include <stdio.h>
3
+ #include <assert.h>
4
+ #include <limits.h>
5
+ #include <string.h>
6
+ #include <ruby.h>
7
+
8
+ #include <vector>
9
+
10
+ #ifndef _MSC_VER
11
+ # include <stdint.h>
12
+ #else
13
+ typedef unsigned char uint8_t;
14
+ #endif
15
+
16
+ #include "OpenTypeUtilities.h"
17
+
18
+ VALUE eTTFConversionError;
19
+
20
+ static VALUE mTTF2EOT_eot_header(VALUE self, VALUE input) {
21
+ vector<uint8_t> eotHeader(512);
22
+ bool success;
23
+ size_t overlayDst = 0;
24
+ size_t overlaySrc = 0;
25
+ size_t overlayLength = 0;
26
+
27
+ if ( TYPE(input) != T_STRING )
28
+ rb_raise(rb_eTypeError, "TTF2EOT.eot_header expects a string as input");
29
+
30
+ success = getEOTHeader(
31
+ (unsigned char *) RSTRING_PTR(input),
32
+ RSTRING_LEN(input),
33
+ eotHeader,
34
+ overlayDst,
35
+ overlaySrc,
36
+ overlayLength
37
+ );
38
+
39
+ if ( success ) {
40
+ return rb_str_new((char *) &eotHeader[0], eotHeader.size());
41
+ } else {
42
+ rb_raise(
43
+ eTTFConversionError,
44
+ "could not get EOT header - ensure input contains valid TTF font data"
45
+ );
46
+ }
47
+ }
48
+
49
+ extern "C" void Init_ttf2eot_ext() {
50
+ VALUE mTTF2EOT = rb_const_get(rb_cObject, rb_intern("TTF2EOT"));
51
+ eTTFConversionError = rb_define_class_under(mTTF2EOT, "ConversionError", rb_eStandardError);
52
+
53
+ rb_define_module_function(mTTF2EOT, "eot_header", (VALUE(*)(...))mTTF2EOT_eot_header, 1);
54
+ }
data/lib/ttf2eot.rb ADDED
@@ -0,0 +1,47 @@
1
+ module TTF2EOT
2
+ # Public: Converts a TTF font file to an EOT font.
3
+ #
4
+ # input - the input TTF font as a String (representing a path) or IO object
5
+ # (responding to #read).
6
+ # output - the output destination as a String (representing a path) or IO
7
+ # object where the EOT font will be written.
8
+ #
9
+ # Examples:
10
+ #
11
+ # TTF2EOT.convert("input.ttf", "output.eot")
12
+ # # => #<File:output.eot>
13
+ #
14
+ # input = StringIO.new(File.read("input.ttf"))
15
+ # output = StringIO.new
16
+ # TTF2EOT.convert(input, output)
17
+ # # => #<StringIO:0x007f815a83a210>
18
+ #
19
+ # Returns the output IO object.
20
+ # Raises TTF2EOT::ConversionError if the input data is invalid.
21
+ def convert(input, output)
22
+ input = File.open(input, "rb") unless input.respond_to?(:read)
23
+ output = File.open(output, "wb") unless output.respond_to?(:write)
24
+
25
+ source = input.read
26
+ header = eot_header(source)
27
+
28
+ output.write header
29
+ output.write source
30
+ output.flush
31
+
32
+ output
33
+ end
34
+ module_function :convert
35
+
36
+ # Internal: Get an EOT header for a TTF font.
37
+ #
38
+ # font_data - a String containing valid TTF font data.
39
+ #
40
+ # Returns a String with the EOT header for the input data.
41
+ # Raises TTF2EOT::ConversionError if the input data is invalid.
42
+ def eot_header(font_data)
43
+ raise NotImlementedError, "this method is defined by the ttf2eot c extension"
44
+ end
45
+ end
46
+
47
+ require "ttf2eot_ext"
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ttf2eot
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Bernerd Schaefer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-09 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake-compiler
16
+ requirement: &70362718527040 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70362718527040
25
+ description: Convert TTF fonts to EOT fonts
26
+ email: bj.schaefer@gmail.com
27
+ executables: []
28
+ extensions:
29
+ - ext/ttf2eot_ext/extconf.rb
30
+ extra_rdoc_files: []
31
+ files:
32
+ - Rakefile
33
+ - lib/ttf2eot.rb
34
+ - ext/ttf2eot_ext/OpenTypeUtilities.cpp
35
+ - ext/ttf2eot_ext/ttf2eot.cpp
36
+ - ext/ttf2eot_ext/OpenTypeUtilities.h
37
+ - ext/ttf2eot_ext/extconf.rb
38
+ homepage:
39
+ licenses: []
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ! '>='
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubyforge_project:
58
+ rubygems_version: 1.8.11
59
+ signing_key:
60
+ specification_version: 3
61
+ summary: Convert TTF fonts to EOT fonts
62
+ test_files: []
63
+ has_rdoc: