Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7640 views
1
#include "mupdf/fitz.h"
2
3
#define RLE_THRESHOLD 256
4
5
fz_glyph *
6
fz_keep_glyph(fz_context *ctx, fz_glyph *glyph)
7
{
8
return (fz_glyph *)fz_keep_storable(ctx, &glyph->storable);
9
}
10
11
void
12
fz_drop_glyph(fz_context *ctx, fz_glyph *glyph)
13
{
14
fz_drop_storable(ctx, &glyph->storable);
15
}
16
17
static void
18
fz_drop_glyph_imp(fz_context *ctx, fz_storable *glyph_)
19
{
20
fz_glyph *glyph = (fz_glyph *)glyph_;
21
22
if (glyph == NULL)
23
return;
24
fz_drop_pixmap(ctx, glyph->pixmap);
25
fz_free(ctx, glyph);
26
}
27
28
fz_irect *
29
fz_glyph_bbox(fz_context *ctx, fz_glyph *glyph, fz_irect *bbox)
30
{
31
bbox->x0 = glyph->x;
32
bbox->y0 = glyph->y;
33
bbox->x1 = glyph->x + glyph->w;
34
bbox->y1 = glyph->y + glyph->h;
35
return bbox;
36
}
37
38
fz_irect *
39
fz_glyph_bbox_no_ctx(fz_glyph *glyph, fz_irect *bbox)
40
{
41
bbox->x0 = glyph->x;
42
bbox->y0 = glyph->y;
43
bbox->x1 = glyph->x + glyph->w;
44
bbox->y1 = glyph->y + glyph->h;
45
return bbox;
46
}
47
48
int
49
fz_glyph_width(fz_context *ctx, fz_glyph *glyph)
50
{
51
return glyph->w;
52
}
53
54
int
55
fz_glyph_height(fz_context *ctx, fz_glyph *glyph)
56
{
57
return glyph->h;
58
}
59
60
#ifndef NDEBUG
61
void
62
fz_dump_glyph(fz_glyph *glyph)
63
{
64
int x, y;
65
66
if (glyph->pixmap)
67
{
68
printf("pixmap glyph\n");
69
return;
70
}
71
printf("glyph: %dx%d @ (%d,%d)\n", glyph->w, glyph->h, glyph->x, glyph->y);
72
73
for (y = 0; y < glyph->h; y++)
74
{
75
int offset = ((int *)(glyph->data))[y];
76
if (offset >= 0)
77
{
78
int extend = 0;
79
int eol = 0;
80
x = glyph->w;
81
do
82
{
83
int v = glyph->data[offset++];
84
int len;
85
char c;
86
switch(v&3)
87
{
88
case 0: /* extend */
89
extend = v>>2;
90
len = 0;
91
break;
92
case 1: /* Transparent pixels */
93
len = 1 + (v>>2) + (extend<<6);
94
extend = 0;
95
c = '.';
96
break;
97
case 2: /* Solid pixels */
98
len = 1 + (v>>3) + (extend<<5);
99
extend = 0;
100
eol = v & 4;
101
c = (eol ? '$' :'#');
102
break;
103
default: /* Intermediate pixels */
104
len = 1 + (v>>3) + (extend<<5);
105
extend = 0;
106
offset += len;
107
eol = v & 4;
108
c = (eol ? '!' : '?');
109
break;
110
}
111
x -= len;
112
while (len--)
113
fputc(c, stdout);
114
if (eol)
115
break;
116
}
117
while (x > 0);
118
}
119
printf("\n");
120
}
121
}
122
#endif
123
124
fz_glyph *
125
fz_new_glyph_from_pixmap(fz_context *ctx, fz_pixmap *pix)
126
{
127
fz_glyph *glyph = NULL;
128
129
if (pix == NULL)
130
return NULL;
131
132
fz_var(glyph);
133
134
fz_try(ctx)
135
{
136
if (pix->n != 1 || pix->w * pix->h < RLE_THRESHOLD)
137
{
138
glyph = fz_malloc_struct(ctx, fz_glyph);
139
FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
140
glyph->x = pix->x;
141
glyph->y = pix->y;
142
glyph->w = pix->w;
143
glyph->h = pix->h;
144
glyph->size = fz_pixmap_size(ctx, pix);
145
glyph->pixmap = fz_keep_pixmap(ctx, pix);
146
}
147
else
148
glyph = fz_new_glyph_from_8bpp_data(ctx, pix->x, pix->y, pix->w, pix->h, pix->samples, pix->w);
149
}
150
fz_always(ctx)
151
{
152
fz_drop_pixmap(ctx, pix);
153
}
154
fz_catch(ctx)
155
{
156
fz_rethrow(ctx);
157
}
158
159
return glyph;
160
}
161
162
fz_glyph *
163
fz_new_glyph_from_8bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
164
{
165
fz_glyph *glyph = NULL;
166
fz_pixmap *pix = NULL;
167
int size, fill, yy;
168
unsigned char *orig_sp = sp;
169
170
fz_var(glyph);
171
fz_var(pix);
172
173
fz_try(ctx)
174
{
175
/* We start out by allocating space as large as the pixmap.
176
* If we need more than that give up on using RLE. We can
177
* never hope to beat the pixmap for really small sizes. */
178
if (w <= 6 || w * h < RLE_THRESHOLD)
179
goto try_pixmap;
180
181
size = h * w;
182
fill = h * sizeof(int);
183
glyph = fz_malloc(ctx, sizeof(fz_glyph) + size);
184
FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
185
glyph->x = x;
186
glyph->y = y;
187
glyph->w = w;
188
glyph->h = h;
189
glyph->pixmap = NULL;
190
if (w == 0 || h == 0)
191
{
192
glyph->size = 0;
193
break;
194
}
195
for (yy=0; yy < h; yy++)
196
{
197
int nonblankfill = fill;
198
int nonblankfill_end = fill;
199
int linefill = fill;
200
int ww = w;
201
do
202
{
203
int code;
204
int len = ww;
205
int needed;
206
unsigned char *ep;
207
switch (*sp)
208
{
209
case 0:
210
if (len > 0x1000)
211
len = 0x1000;
212
ep = sp+len;
213
while (++sp != ep && *sp == 0);
214
code = 1;
215
len -= ep-sp;
216
ww -= len;
217
needed = fill + 1 + (len > 0x40);
218
break;
219
case 255:
220
if (len > 0x800)
221
len = 0x800;
222
ep = sp+len;
223
while (++sp != ep && *sp == 255);
224
code = 2;
225
len -= ep-sp;
226
ww -= len;
227
needed = fill + 1 + (len > 0x20);
228
break;
229
default:
230
{
231
unsigned char c;
232
if (len > 0x800)
233
len = 0x800;
234
ep = sp+len;
235
while (++sp != ep && (c = *sp) != 255 && c != 0);
236
len -= ep-sp;
237
ww -= len;
238
needed = fill + 1 + len + (len > 0x20);
239
code = 3;
240
}
241
}
242
if (needed > size)
243
goto try_pixmap;
244
if (code == 1)
245
{
246
if (len > 0x40)
247
glyph->data[fill++] = ((len-1)>>6)<<2;
248
glyph->data[fill++] = 1 | (((len-1)&63)<<2);
249
}
250
else
251
{
252
if (len > 0x20)
253
glyph->data[fill++] = ((len-1)>>5)<<2;
254
nonblankfill = fill;
255
glyph->data[fill++] = code | (((len-1)&31)<<3);
256
if (code == 3)
257
{
258
memcpy(&glyph->data[fill], sp - len, len);
259
fill += len;
260
}
261
nonblankfill_end = fill;
262
}
263
}
264
while (ww > 0);
265
if (nonblankfill_end == linefill)
266
{
267
((int *)(glyph->data))[yy] = -1;
268
fill = linefill;
269
}
270
else
271
{
272
glyph->data[nonblankfill] |= 4;
273
fill = nonblankfill_end;
274
((int *)(glyph->data))[yy] = linefill;
275
}
276
sp += span - w;
277
}
278
if (fill != size)
279
{
280
glyph = fz_resize_array(ctx, glyph, 1, sizeof(fz_glyph) + fill);
281
size = fill;
282
}
283
glyph->size = size;
284
break;
285
286
/* Nasty use of a goto here, but it saves us having to exit
287
* and reenter the try context, and this routine is speed
288
* critical. */
289
try_pixmap:
290
glyph = fz_resize_array(ctx, glyph, 1, sizeof(fz_glyph));
291
FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
292
pix = fz_new_pixmap_from_8bpp_data(ctx, x, y, w, h, orig_sp, span);
293
glyph->x = pix->x;
294
glyph->y = pix->y;
295
glyph->w = pix->w;
296
glyph->h = pix->h;
297
glyph->size = fz_pixmap_size(ctx, pix);
298
glyph->pixmap = pix;
299
}
300
fz_catch(ctx)
301
{
302
fz_drop_pixmap(ctx, pix);
303
fz_free(ctx, glyph);
304
fz_rethrow(ctx);
305
}
306
307
return glyph;
308
}
309
310
fz_glyph *
311
fz_new_glyph_from_1bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
312
{
313
fz_pixmap *pix = NULL;
314
fz_glyph *glyph = NULL;
315
int size, fill, yy;
316
unsigned char *orig_sp = sp;
317
318
fz_var(glyph);
319
fz_var(pix);
320
321
fz_try(ctx)
322
{
323
/* We start out by allocating space as large as the pixmap.
324
* If we need more than that give up on using RLE. We can
325
* never hope to beat the pixmap for really small sizes. */
326
if (w <= 6 || w * h < RLE_THRESHOLD)
327
goto try_pixmap;
328
329
size = h * w;
330
fill = h * sizeof(int);
331
glyph = fz_malloc(ctx, sizeof(fz_glyph) + size);
332
FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
333
glyph->x = x;
334
glyph->y = y;
335
glyph->w = w;
336
glyph->h = h;
337
glyph->pixmap = NULL;
338
if (w == 0 || h == 0)
339
{
340
glyph->size = 0;
341
break;
342
}
343
for (yy=0; yy < h; yy++)
344
{
345
int nonblankfill = fill;
346
int nonblankfill_end = fill;
347
int linefill = fill;
348
int ww = w;
349
int bit = 0x80;
350
do
351
{
352
int len = 0;
353
int needed;
354
int b = *sp & bit;
355
bit >>= 1;
356
if (bit == 0)
357
bit = 0x80, sp++;
358
ww--;
359
if (b == 0)
360
{
361
while (ww > 0 && len < 0xfff && (*sp & bit) == 0)
362
{
363
bit >>= 1;
364
if (bit == 0)
365
bit = 0x80, sp++;
366
len++;
367
ww--;
368
}
369
needed = fill + (len >= 0x40) + 1;
370
if (needed > size)
371
goto try_pixmap;
372
if (len >= 0x40)
373
glyph->data[fill++] = (len>>6)<<2;
374
glyph->data[fill++] = 1 | ((len&63)<<2);
375
}
376
else
377
{
378
while (ww > 0 && len < 0x7ff && (*sp & bit) != 0)
379
{
380
bit >>= 1;
381
if (bit == 0)
382
bit = 0x80, sp++;
383
len++;
384
ww--;
385
}
386
needed = fill + (len >= 0x20) + 1;
387
if (needed > size)
388
goto try_pixmap;
389
if (len >= 0x20)
390
glyph->data[fill++] = (len>>5)<<2;
391
nonblankfill = fill;
392
glyph->data[fill++] = 2 | ((len&31)<<3);
393
nonblankfill_end = fill;
394
}
395
}
396
while (ww > 0);
397
if (nonblankfill_end == linefill)
398
{
399
((int *)(glyph->data))[yy] = -1;
400
fill = linefill;
401
}
402
else
403
{
404
glyph->data[nonblankfill] |= 4;
405
fill = nonblankfill_end;
406
((int *)(glyph->data))[yy] = linefill;
407
}
408
sp += span - (w>>3);
409
}
410
if (fill != size)
411
{
412
glyph = fz_resize_array(ctx, glyph, 1, sizeof(fz_glyph) + fill);
413
size = fill;
414
}
415
glyph->size = size;
416
break;
417
418
/* Nasty use of a goto here, but it saves us having to exit
419
* and reenter the try context, and this routine is speed
420
* critical. */
421
try_pixmap:
422
glyph = fz_resize_array(ctx, glyph, 1, sizeof(fz_glyph));
423
FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp);
424
pix = fz_new_pixmap_from_1bpp_data(ctx, x, y, w, h, orig_sp, span);
425
glyph->x = pix->x;
426
glyph->y = pix->y;
427
glyph->w = pix->w;
428
glyph->h = pix->h;
429
glyph->size = fz_pixmap_size(ctx, pix);
430
glyph->pixmap = pix;
431
}
432
fz_catch(ctx)
433
{
434
fz_drop_pixmap(ctx, pix);
435
fz_free(ctx, glyph);
436
fz_rethrow(ctx);
437
}
438
439
return glyph;
440
}
441
442