1 /* remove_font_transform.c
3 Part of the swftools package.
5 Copyright (c) 2010 Matthias Kramm <kramm@quiss.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
24 #include "../gfxfilter.h"
25 #include "../gfxtools.h"
26 #include "../gfxfont.h"
32 typedef struct _mymatrix {
33 float m00,m01,m10,m11;
38 static void* mymatrix_clone(const void*_m) {
41 const mymatrix_t*m1=_m;
42 mymatrix_t*m2 = malloc(sizeof(mymatrix_t));
44 m2->id = strdup(m1->id);
47 static unsigned int mymatrix_hash(const void*_m) {
50 const mymatrix_t*m = (mymatrix_t*)_m;
52 h = crc32_add_bytes(h, (char*)&m->m00, sizeof(m->m00));
53 h = crc32_add_bytes(h, (char*)&m->m01, sizeof(m->m01));
54 h = crc32_add_bytes(h, (char*)&m->m10, sizeof(m->m10));
55 h = crc32_add_bytes(h, (char*)&m->m11, sizeof(m->m11));
56 h = crc32_add_bytes(h, (char*)&m->alpha, 1);
57 h = crc32_add_string(h, m->id);
60 static void mymatrix_destroy(void*_m) {
61 mymatrix_t*m = (mymatrix_t*)_m;
65 static char mymatrix_equals(const void*_m1, const void*_m2) {
66 const mymatrix_t*m1=_m1;
67 const mymatrix_t*m2=_m2;
71 /* we do a binary comparison of the float32
72 bits here instead of a numerical comparison
73 to prevent the compiler from e.g. removing the
74 (float) cast during optimization, which would break
75 the equivalence between equals() and hash() (as
76 the hash is derived from the float32 values) */
77 return *(U32*)&m1->m00 == *(U32*)&m2->m00 &&
78 *(U32*)&m1->m01 == *(U32*)&m2->m01 &&
79 *(U32*)&m1->m10 == *(U32*)&m2->m10 &&
80 *(U32*)&m1->m11 == *(U32*)&m2->m11 &&
81 m1->alpha == m2->alpha &&
82 !strcmp(m1->id, m2->id);
84 type_t mymatrix_type = {
87 free: mymatrix_destroy,
88 equals: mymatrix_equals
91 typedef struct _internal {
98 void __attribute__((noinline))
99 matrix_convert(gfxmatrix_t*in, const char*id, mymatrix_t*out, gfxmatrix_t*scalematrix, unsigned char alpha)
101 void matrix_convert(gfxmatrix_t*in, const char*id, mymatrix_t*out, gfxmatrix_t*scalematrix, unsigned char alpha)
104 double l1 = sqrt(in->m00 * in->m00 + in->m01 * in->m01);
105 double l2 = sqrt(in->m10 * in->m10 + in->m11 * in->m11);
106 double l = (l1+l2)/2.0;
108 memset(out, 0, sizeof(*out));
111 out->m00 = in->m00 / l;
112 out->m10 = in->m10 / l;
113 out->m01 = -in->m01 / l;
114 out->m11 = -in->m11 / l;
116 out->alpha = alpha?1:0;
119 scalematrix->m00 = l;
120 scalematrix->m01 = 0;
121 scalematrix->m10 = 0;
122 scalematrix->m11 = -l;
123 scalematrix->tx = in->tx;
124 scalematrix->ty = in->ty;
128 typedef struct _matrixdata {
132 typedef struct _transformedfont {
140 static transformedfont_t* transformedfont_new(gfxfont_t*orig, mymatrix_t*m)
142 transformedfont_t*f = rfx_calloc(sizeof(transformedfont_t));
145 f->used = rfx_calloc(sizeof(f->used[0])*orig->num_glyphs);
147 for(t=0;t<orig->num_glyphs;t++) {
148 if(orig->glyphs[t].unicode==32 &&
149 (!orig->glyphs[t].line ||
150 !orig->glyphs[t].line->next ||
151 !orig->glyphs[t].line->next->next))
152 f->used[t]=1; //always preserve the space char in fonts
157 static void pass1_drawchar(gfxfilter_t*f, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix, gfxdevice_t*out)
159 internal_t*i = (internal_t*)f->internal;
162 msg("<error> Font has no ID");
163 matrix_convert(matrix, font->id?font->id:"unknown", &m, 0, color->a);
164 transformedfont_t*fd = dict_lookup(i->matrices, &m);
166 fd = transformedfont_new(font, &m);
167 dict_put(i->matrices, &m, fd);
170 out->drawchar(out, font, glyphnr, color, matrix);
173 static void glyph_transform(gfxglyph_t*g, mymatrix_t*mm)
184 g->line = gfxline_clone(g->line);
185 gfxline_transform(g->line, &m);
188 static gfxresult_t* pass1_finish(gfxfilter_t*f, gfxdevice_t*out)
190 internal_t*i = (internal_t*)f->internal;
191 DICT_ITERATE_DATA(i->matrices, transformedfont_t*, fd) {
192 gfxfont_t*font = fd->font = rfx_calloc(sizeof(gfxfont_t));
194 static int fontcount=0;
195 sprintf(id, "font%d", fontcount++);
196 font->id = strdup(id);
199 for(t=0;t<fd->orig->num_glyphs;t++) {
203 font->num_glyphs = count;
204 font->glyphs = rfx_calloc(sizeof(gfxglyph_t)*font->num_glyphs);
206 for(t=0;t<fd->orig->num_glyphs;t++) {
208 font->glyphs[count] = fd->orig->glyphs[t];
209 glyph_transform(&font->glyphs[count], &fd->matrix);
210 fd->used[t] = count + 1;
215 /* adjust the origin so that every character is to the
216 right of the origin */
217 gfxbbox_t total = {0,0,0,0};
218 double average_xmax = 0;
219 for(t=0;t<count;t++) {
220 gfxline_t*line = font->glyphs[t].line;
221 gfxbbox_t b = gfxline_getbbox(line);
222 total = gfxbbox_expand_to_bbox(total, b);
225 average_xmax /= count;
227 fd->dx = -total.xmin;
229 font->ascent = total.ymax;
230 font->descent = -total.ymin;
232 for(t=0;t<count;t++) {
233 gfxglyph_t*g = &font->glyphs[t];
234 gfxline_t*line = font->glyphs[t].line;
236 if(fd->matrix.alpha) {
243 gfxline_free(g->line);
244 /* for OCR: remove the outlines of characters that are only
245 ever displayed with alpha=0 */
246 g->line = (gfxline_t*)rfx_calloc(sizeof(gfxline_t));
247 g->line->type = gfx_moveTo;
248 g->line->x = g->advance;
252 if(fd->matrix.m00>0) {
253 /* subset kerning table */
255 for(t=0;t<fd->orig->kerning_size;t++) {
256 int char1 = fd->used[fd->orig->kerning[t].c1]-1;
257 int char2 = fd->used[fd->orig->kerning[t].c2]-1;
258 if(char1>=0 && char2>=0) {
262 font->kerning = malloc(sizeof(font->kerning[0])*count);
263 font->kerning_size = count;
265 for(t=0;t<fd->orig->kerning_size;t++) {
266 int char1 = fd->used[fd->orig->kerning[t].c1]-1;
267 int char2 = fd->used[fd->orig->kerning[t].c2]-1;
268 if(char1>=0 && char2>=0) {
269 font->kerning[count].c1 = char1;
270 font->kerning[count].c2 = char2;
271 font->kerning[count].advance = fd->orig->kerning[t].advance * fd->matrix.m00;
276 gfxfont_fix_unicode(font);
278 return out->finish(out);
281 static void pass2_addfont(gfxfilter_t*f, gfxfont_t*font, gfxdevice_t*out)
283 /* we throw away original fonts, and do the addfont() for the transformed
284 fonts in the first drawchar() */
287 static void pass2_drawchar(gfxfilter_t*f, gfxfont_t*font, int glyphnr, gfxcolor_t*_color, gfxmatrix_t*matrix, gfxdevice_t*out)
289 internal_t*i = (internal_t*)f->internal;
290 gfxcolor_t color = *_color;
294 DICT_ITERATE_DATA(i->matrices, transformedfont_t*, fd) {
295 out->addfont(out, fd->font);
300 gfxmatrix_t scalematrix;
301 matrix_convert(matrix, font->id?font->id:"unknown", &m, &scalematrix, color.a);
302 transformedfont_t*d = dict_lookup(i->matrices, &m);
303 scalematrix.tx -= d->dx*scalematrix.m00;
305 /* if this character is invisible (alpha=0), then we will have removed the
306 outline, so we make set the alpha color channel to "fully visible" again to allow
307 output devices to be more performant (transparency is expensive) */
311 out->drawchar(out, d->font, d->used[glyphnr]-1, &color, &scalematrix);
314 static gfxresult_t* pass2_finish(gfxfilter_t*f, gfxdevice_t*out)
316 internal_t*i = (internal_t*)f->internal;
317 DICT_ITERATE_DATA(i->matrices, transformedfont_t*, fd) {
319 free(fd->used);fd->used=0;
323 dict_destroy(i->matrices);i->matrices=0;
324 return out->finish(out);
327 void gfxtwopassfilter_remove_font_transforms_init(gfxtwopassfilter_t*f)
329 internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
331 memset(f, 0, sizeof(gfxtwopassfilter_t));
332 f->type = gfxfilter_twopass;
334 f->pass1.name = "remove font transforms pass 1";
335 f->pass1.drawchar = pass1_drawchar;
336 f->pass1.finish = pass1_finish;
337 f->pass1.internal = i;
339 f->pass2.name = "remove font transforms pass 2";
340 f->pass2.addfont = pass2_addfont;
341 f->pass2.drawchar = pass2_drawchar;
342 f->pass2.finish = pass2_finish;
343 f->pass2.internal = i;
345 i->matrices = dict_new2(&mymatrix_type);