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 int __attribute__((noinline))
99 matrix_convert(gfxmatrix_t*in, const char*id, mymatrix_t*out, gfxmatrix_t*scalematrix, unsigned char alpha)
101 int 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;
129 typedef struct _matrixdata {
133 typedef struct _transformedfont {
141 static transformedfont_t* transformedfont_new(gfxfont_t*orig, mymatrix_t*m)
143 transformedfont_t*f = rfx_calloc(sizeof(transformedfont_t));
146 f->used = rfx_calloc(sizeof(f->used[0])*orig->num_glyphs);
148 for(t=0;t<orig->num_glyphs;t++) {
149 if(orig->glyphs[t].unicode==32 &&
150 (!orig->glyphs[t].line ||
151 !orig->glyphs[t].line->next ||
152 !orig->glyphs[t].line->next->next))
153 f->used[t]=1; //always preserve the space char in fonts
158 static void pass1_drawchar(gfxfilter_t*f, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix, gfxdevice_t*out)
160 internal_t*i = (internal_t*)f->internal;
163 msg("<error> Font has no ID");
164 if(!matrix_convert(matrix, font->id?font->id:"unknown", &m, 0, color->a))
166 transformedfont_t*fd = dict_lookup(i->matrices, &m);
168 fd = transformedfont_new(font, &m);
169 dict_put(i->matrices, &m, fd);
172 out->drawchar(out, font, glyphnr, color, matrix);
175 static void glyph_transform(gfxglyph_t*g, mymatrix_t*mm)
186 g->line = gfxline_clone(g->line);
187 gfxline_transform(g->line, &m);
190 static gfxresult_t* pass1_finish(gfxfilter_t*f, gfxdevice_t*out)
192 internal_t*i = (internal_t*)f->internal;
193 DICT_ITERATE_DATA(i->matrices, transformedfont_t*, fd) {
194 gfxfont_t*font = fd->font = rfx_calloc(sizeof(gfxfont_t));
196 static int fontcount=0;
197 sprintf(id, "font%d", fontcount++);
198 font->id = strdup(id);
201 for(t=0;t<fd->orig->num_glyphs;t++) {
205 font->num_glyphs = count;
206 font->glyphs = rfx_calloc(sizeof(gfxglyph_t)*font->num_glyphs);
208 for(t=0;t<fd->orig->num_glyphs;t++) {
210 font->glyphs[count] = fd->orig->glyphs[t];
211 glyph_transform(&font->glyphs[count], &fd->matrix);
212 fd->used[t] = count + 1;
217 /* adjust the origin so that every character is to the
218 right of the origin */
219 gfxbbox_t total = {0,0,0,0};
220 double average_xmax = 0;
221 for(t=0;t<count;t++) {
222 gfxline_t*line = font->glyphs[t].line;
223 gfxbbox_t b = gfxline_getbbox(line);
224 total = gfxbbox_expand_to_bbox(total, b);
227 average_xmax /= count;
229 fd->dx = 0;//-total.xmin;
231 font->ascent = total.ymax;
232 font->descent = -total.ymin;
234 for(t=0;t<count;t++) {
235 gfxglyph_t*g = &font->glyphs[t];
236 gfxline_t*line = font->glyphs[t].line;
238 if(fd->matrix.alpha) {
245 gfxline_free(g->line);
246 /* for OCR: remove the outlines of characters that are only
247 ever displayed with alpha=0 */
248 g->line = (gfxline_t*)rfx_calloc(sizeof(gfxline_t));
249 g->line->type = gfx_moveTo;
250 g->line->x = g->advance;
254 if(fd->matrix.m00>0) {
255 /* subset kerning table */
257 for(t=0;t<fd->orig->kerning_size;t++) {
258 int char1 = fd->used[fd->orig->kerning[t].c1]-1;
259 int char2 = fd->used[fd->orig->kerning[t].c2]-1;
260 if(char1>=0 && char2>=0) {
264 font->kerning = malloc(sizeof(font->kerning[0])*count);
265 font->kerning_size = count;
267 for(t=0;t<fd->orig->kerning_size;t++) {
268 int char1 = fd->used[fd->orig->kerning[t].c1]-1;
269 int char2 = fd->used[fd->orig->kerning[t].c2]-1;
270 if(char1>=0 && char2>=0) {
271 font->kerning[count].c1 = char1;
272 font->kerning[count].c2 = char2;
273 font->kerning[count].advance = fd->orig->kerning[t].advance * fd->matrix.m00;
278 gfxfont_fix_unicode(font);
280 return out->finish(out);
283 static void pass2_addfont(gfxfilter_t*f, gfxfont_t*font, gfxdevice_t*out)
285 /* we throw away original fonts, and do the addfont() for the transformed
286 fonts in the first drawchar() */
289 static void pass2_drawchar(gfxfilter_t*f, gfxfont_t*font, int glyphnr, gfxcolor_t*_color, gfxmatrix_t*matrix, gfxdevice_t*out)
291 internal_t*i = (internal_t*)f->internal;
292 gfxcolor_t color = *_color;
296 DICT_ITERATE_DATA(i->matrices, transformedfont_t*, fd) {
297 out->addfont(out, fd->font);
302 gfxmatrix_t scalematrix;
303 matrix_convert(matrix, font->id?font->id:"unknown", &m, &scalematrix, color.a);
304 transformedfont_t*d = dict_lookup(i->matrices, &m);
305 scalematrix.tx -= d->dx*scalematrix.m00;
307 /* if this character is invisible (alpha=0), then we will have removed the
308 outline, so we make set the alpha color channel to "fully visible" again to allow
309 output devices to be more performant (transparency is expensive) */
313 out->drawchar(out, d->font, d->used[glyphnr]-1, &color, &scalematrix);
316 static gfxresult_t* pass2_finish(gfxfilter_t*f, gfxdevice_t*out)
318 internal_t*i = (internal_t*)f->internal;
319 DICT_ITERATE_DATA(i->matrices, transformedfont_t*, fd) {
321 free(fd->used);fd->used=0;
325 dict_destroy(i->matrices);i->matrices=0;
326 return out->finish(out);
329 void gfxtwopassfilter_remove_font_transforms_init(gfxtwopassfilter_t*f)
331 internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
333 memset(f, 0, sizeof(gfxtwopassfilter_t));
334 f->type = gfxfilter_twopass;
336 f->pass1.name = "remove font transforms pass 1";
337 f->pass1.drawchar = pass1_drawchar;
338 f->pass1.finish = pass1_finish;
339 f->pass1.internal = i;
341 f->pass2.name = "remove font transforms pass 2";
342 f->pass2.addfont = pass2_addfont;
343 f->pass2.drawchar = pass2_drawchar;
344 f->pass2.finish = pass2_finish;
345 f->pass2.internal = i;
347 i->matrices = dict_new2(&mymatrix_type);