/src/ghostpdl/base/gxccache.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2025 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Fast case character cache routines for Ghostscript library */ |
18 | | #include "memory_.h" |
19 | | #include "gx.h" |
20 | | #include "gpcheck.h" |
21 | | #include "gserrors.h" |
22 | | #include "gsstruct.h" |
23 | | #include "gscencs.h" |
24 | | #include "gxfixed.h" |
25 | | #include "gxmatrix.h" |
26 | | #include "gzstate.h" |
27 | | #include "gzpath.h" |
28 | | #include "gxdevice.h" |
29 | | #include "gxdevmem.h" |
30 | | #include "gzcpath.h" |
31 | | #include "gxchar.h" |
32 | | #include "gxfont.h" |
33 | | #include "gxfcache.h" |
34 | | #include "gxxfont.h" |
35 | | #include "gximask.h" |
36 | | #include "gscspace.h" /* for gsimage.h */ |
37 | | #include "gsimage.h" |
38 | | #include "gxhttile.h" |
39 | | #include "gsptype1.h" /* for gx_dc_is_pattern1_color_with_trans */ |
40 | | |
41 | | /* Forward references */ |
42 | | static byte *compress_alpha_bits(const cached_char *, gs_memory_t *); |
43 | | |
44 | | /* Define a scale factor of 1. */ |
45 | | static const gs_log2_scale_point scale_log2_1 = |
46 | | {0, 0}; |
47 | | |
48 | | void |
49 | | gx_compute_char_matrix(const gs_matrix *char_tm, const gs_log2_scale_point *log2_scale, |
50 | | float *mxx, float *mxy, float *myx, float *myy) |
51 | 26.5M | { |
52 | 26.5M | int scale_x = 1 << log2_scale->x; |
53 | 26.5M | int scale_y = 1 << log2_scale->y; |
54 | | |
55 | 26.5M | *mxx = char_tm->xx * scale_x; |
56 | 26.5M | *mxy = char_tm->xy * scale_x; |
57 | 26.5M | *myx = char_tm->yx * scale_y; |
58 | 26.5M | *myy = char_tm->yy * scale_y; |
59 | 26.5M | } |
60 | | |
61 | | void |
62 | | gx_compute_ccache_key(gs_font * pfont, const gs_matrix *char_tm, |
63 | | const gs_log2_scale_point *log2_scale, bool design_grid, |
64 | | float *mxx, float *mxy, float *myx, float *myy) |
65 | 26.6M | { |
66 | 26.6M | if (design_grid && |
67 | 26.6M | (pfont->FontType == ft_TrueType || pfont->FontType == ft_CID_TrueType)) { |
68 | | /* |
69 | | * We need a special face for this case, because the TT interpreter |
70 | | * can't generate both grid_fitted and non-grid-fitted outlines |
71 | | * with a same face instance. This happens due to control |
72 | | * values in 'cvt' must be different. |
73 | | * Since a single face satisfies all font sizes, |
74 | | * we use a zero matrix as the cache entry key. |
75 | | */ |
76 | 66.0k | *mxx = *mxy = *myx = *myy = 0; |
77 | 66.0k | } else |
78 | 26.5M | gx_compute_char_matrix(char_tm, log2_scale, mxx, mxy, myx, myy); |
79 | 26.6M | } |
80 | | |
81 | | /* Look up, and if necessary add, a font/matrix pair in the cache */ |
82 | | int |
83 | | gx_lookup_fm_pair(gs_font * pfont, const gs_matrix *char_tm, |
84 | | const gs_log2_scale_point *log2_scale, bool design_grid, cached_fm_pair **ppair) |
85 | 24.8M | { |
86 | 24.8M | float mxx, mxy, myx, myy; |
87 | 24.8M | gs_font *font = pfont; |
88 | 24.8M | register gs_font_dir *dir = font->dir; |
89 | 24.8M | register cached_fm_pair *pair = dir->fmcache.mdata + dir->fmcache.used; |
90 | 24.8M | int count = dir->fmcache.msize; |
91 | 24.8M | gs_uid uid; |
92 | | |
93 | 24.8M | gx_compute_ccache_key(pfont, char_tm, log2_scale, design_grid, |
94 | 24.8M | &mxx, &mxy, &myx, &myy); |
95 | 24.8M | if (font->FontType == ft_composite || font->PaintType != 0) { /* We can't cache by UID alone. */ |
96 | 0 | uid_set_invalid(&uid); |
97 | 24.8M | } else { |
98 | 24.8M | uid = ((gs_font_base *) font)->UID; |
99 | 24.8M | if (uid_is_valid(&uid)) |
100 | 8.20M | font = 0; |
101 | 24.8M | } |
102 | 224M | for (;count--; pair = dir->fmcache.mdata + pair->next) { |
103 | | /* We have either a non-zero font and an invalid UID, */ |
104 | | /* or a zero font and a valid UID. */ |
105 | | /* We have to break up the test */ |
106 | | /* because of a bug in the Zortech compiler. */ |
107 | 223M | if (font != 0) { |
108 | 210M | if (pair->font != font) |
109 | 6.36M | continue; |
110 | 210M | } else { |
111 | 12.2M | if (!uid_equal(&pair->UID, &uid) || |
112 | 12.2M | pair->FontType != pfont->FontType |
113 | 12.2M | ) |
114 | 2.02M | continue; |
115 | 12.2M | } |
116 | 214M | if (pair->mxx == mxx && pair->mxy == mxy && |
117 | 214M | pair->myx == myx && pair->myy == myy |
118 | 214M | && pair->design_grid == design_grid) { |
119 | 23.0M | int code; |
120 | | |
121 | 23.0M | if (pair->font == 0) { |
122 | 82 | pair->font = pfont; |
123 | 82 | if_debug2m('k', pfont->memory, "[k]updating pair "PRI_INTPTR" with font "PRI_INTPTR"\n", |
124 | 82 | (intptr_t)pair, (intptr_t)pfont); |
125 | 23.0M | } else { |
126 | 23.0M | if_debug2m('k', pfont->memory, "[k]found pair "PRI_INTPTR": font="PRI_INTPTR"\n", |
127 | 23.0M | (intptr_t)pair, (intptr_t)pair->font); |
128 | 23.0M | } |
129 | 23.0M | code = gx_touch_fm_pair(dir, pair); |
130 | 23.0M | if (code < 0) |
131 | 0 | return code; |
132 | 23.0M | code = gx_provide_fm_pair_attributes(dir, pfont, pair, |
133 | 23.0M | char_tm, log2_scale, design_grid); |
134 | 23.0M | if (code < 0) |
135 | 0 | return code; |
136 | 23.0M | *ppair = pair; |
137 | 23.0M | return 0; |
138 | 23.0M | } |
139 | 214M | } |
140 | 1.80M | return gx_add_fm_pair(dir, pfont, &uid, char_tm, log2_scale, design_grid, ppair); |
141 | 24.8M | } |
142 | | |
143 | | /* Look up a glyph with the right depth in the cache. */ |
144 | | /* Return the cached_char or 0. */ |
145 | | cached_char * |
146 | | gx_lookup_cached_char(const gs_font * pfont, const cached_fm_pair * pair, |
147 | | gs_glyph glyph, int wmode, int depth, |
148 | | gs_fixed_point *subpix_origin) |
149 | 61.3M | { |
150 | 61.3M | gs_font_dir *dir = pfont->dir; |
151 | 61.3M | uint chi = chars_head_index(glyph, pair); |
152 | 61.3M | register cached_char *cc; |
153 | | |
154 | 61.7M | while ((cc = dir->ccache.table[chi & dir->ccache.table_mask]) != 0) { |
155 | 46.3M | if (cc->code == glyph && cc_pair(cc) == pair && |
156 | 46.3M | cc->subpix_origin.x == subpix_origin->x && |
157 | 46.3M | cc->subpix_origin.y == subpix_origin->y && |
158 | 46.3M | cc->wmode == wmode && cc_depth(cc) == depth |
159 | 46.3M | ) { |
160 | 45.9M | if_debug4m('K', pfont->memory, |
161 | 45.9M | "[K]found "PRI_INTPTR" (depth=%d) for glyph=0x%lx, wmode=%d\n", |
162 | 45.9M | (intptr_t)cc, cc_depth(cc), (ulong)glyph, wmode); |
163 | 45.9M | return cc; |
164 | 45.9M | } |
165 | 431k | chi++; |
166 | 431k | } |
167 | 61.3M | if_debug3m('K', pfont->memory, "[K]not found: glyph=0x%lx, wmode=%d, depth=%d\n", |
168 | 15.3M | (ulong) glyph, wmode, depth); |
169 | 15.3M | return 0; |
170 | 61.3M | } |
171 | | |
172 | | /* Copy a cached character to the screen. */ |
173 | | /* Assume the caller has already done gx_color_load. */ |
174 | | /* Return 0 if OK, 1 if we couldn't do the operation but no error */ |
175 | | /* should be signalled, or a negative error code. */ |
176 | | int |
177 | | gx_image_cached_char(register gs_show_enum * penum, register cached_char * cc) |
178 | 51.9M | { |
179 | 51.9M | register gs_gstate *pgs = penum->pgs; |
180 | 51.9M | gx_device_color *pdevc = gs_currentdevicecolor_inline(pgs); |
181 | 51.9M | int x, y, w, h, depth; |
182 | 51.9M | int code; |
183 | 51.9M | gs_fixed_point pt; |
184 | 51.9M | gx_device *dev = penum->dev; |
185 | 51.9M | gx_device *imaging_dev = penum->imaging_dev ? penum->imaging_dev : dev; |
186 | 51.9M | gx_device *orig_dev = imaging_dev; |
187 | 51.9M | gx_device_clip cdev; |
188 | 51.9M | gx_xglyph xg = cc->xglyph; |
189 | 51.9M | gx_xfont *xf; |
190 | 51.9M | byte *bits; |
191 | | |
192 | | /* This is only to silence a Coverity warning */ |
193 | 51.9M | cdev.target = NULL; |
194 | 51.9M | cdev.cpath = NULL; |
195 | | |
196 | 51.9M | top:code = gx_path_current_point_inline(pgs, &pt); |
197 | 51.9M | if (code < 0) |
198 | 0 | return code; |
199 | | /* |
200 | | * If the character doesn't lie entirely within the inner |
201 | | * clipping rectangle, we set up an intermediate clipping device. |
202 | | * Note that if the original device implements fill_mask, we may |
203 | | * never actually use the clipping device. |
204 | | */ |
205 | 51.9M | pt.x -= cc->offset.x + cc->subpix_origin.x; |
206 | 51.9M | x = fixed2int_var_rounded(pt.x) + penum->ftx; |
207 | 51.9M | pt.y -= cc->offset.y + cc->subpix_origin.y; |
208 | 51.9M | y = fixed2int_var_rounded(pt.y) + penum->fty; |
209 | 51.9M | w = cc->width; |
210 | 51.9M | h = cc->height; |
211 | | #ifdef DEBUG |
212 | | if (gs_debug_c('K')) { |
213 | | if (cc_has_bits(cc)) |
214 | | debug_dump_bitmap(penum->memory, cc_bits(cc), cc_raster(cc), h, |
215 | | "[K]bits"); |
216 | | else |
217 | | dmputs(penum->memory, "[K]no bits\n"); |
218 | | dmlprintf3(penum->memory, "[K]copying "PRI_INTPTR", offset=(%g,%g)\n", |
219 | | (intptr_t) cc, |
220 | | fixed2float(-cc->offset.x), |
221 | | fixed2float(-cc->offset.y)); |
222 | | dmlprintf6(penum->memory, " at (%g,%g)+(%d,%d)->(%d,%d)\n", |
223 | | fixed2float(pt.x), fixed2float(pt.y), |
224 | | penum->ftx, penum->fty, x, y); |
225 | | } |
226 | | #endif |
227 | 51.9M | if ((x < penum->ibox.p.x || x + w > penum->ibox.q.x || |
228 | 51.9M | y < penum->ibox.p.y || y + h > penum->ibox.q.y) && |
229 | 51.9M | imaging_dev != (gx_device *) & cdev /* might be 2nd time around */ |
230 | 51.9M | ) { /* Check for the character falling entirely outside */ |
231 | | /* the clipping region. */ |
232 | 6.32M | gx_clip_path *pcpath; |
233 | | |
234 | 6.32M | if (x >= penum->obox.q.x || x + w <= penum->obox.p.x || |
235 | 6.32M | y >= penum->obox.q.y || y + h <= penum->obox.p.y |
236 | 6.32M | ) |
237 | 5.83M | return 0; /* nothing to do */ |
238 | 482k | code = gx_effective_clip_path(pgs, &pcpath); |
239 | 482k | if (code < 0) |
240 | 0 | return code; |
241 | 482k | gx_make_clip_device_on_stack(&cdev, pcpath, imaging_dev); |
242 | 482k | imaging_dev = (gx_device *) & cdev; |
243 | 482k | if_debug0m('K', penum->memory, "[K](clipping)\n"); |
244 | 482k | } |
245 | 46.1M | code = gx_set_dev_color(pgs); |
246 | 46.1M | if (code != 0) { |
247 | 0 | if (imaging_dev == (gx_device *) & cdev) |
248 | 0 | gx_destroy_clip_device_on_stack(&cdev); |
249 | 0 | return code; |
250 | 0 | } |
251 | | /* If an xfont can render this character, use it. */ |
252 | 46.1M | if (xg != gx_no_xglyph && (xf = cc_pair(cc)->xfont) != 0) { |
253 | 0 | int cx = x + fixed2int(cc->offset.x); |
254 | 0 | int cy = y + fixed2int(cc->offset.y); |
255 | | |
256 | | /* |
257 | | * Note that we prefer a 1-bit xfont implementation over |
258 | | * a multi-bit cached bitmap. Eventually we should change |
259 | | * the xfont interface so it can deliver multi-bit bitmaps, |
260 | | * or else implement oversampling for xfonts. |
261 | | */ |
262 | 0 | if (gs_color_writes_pure(pgs)) { |
263 | 0 | code = (*xf->common.procs->render_char) (xf, xg, |
264 | 0 | imaging_dev, cx, cy, |
265 | 0 | pdevc->colors.pure, 0); |
266 | 0 | if_debug8m('K', penum->memory, |
267 | 0 | "[K]render_char display: xfont="PRI_INTPTR", glyph=0x%lx\n\tdev="PRI_INTPTR"(%s) x,y=%d,%d, color=0x%lx => %d\n", |
268 | 0 | (intptr_t)xf, (ulong)xg, (intptr_t)imaging_dev, |
269 | 0 | imaging_dev->dname, cx, cy, |
270 | 0 | (ulong) pdevc->colors.pure, code); |
271 | 0 | if (code == 0) { |
272 | 0 | if (imaging_dev == (gx_device *) & cdev) |
273 | 0 | gx_destroy_clip_device_on_stack(&cdev); |
274 | 0 | return_check_interrupt(penum->memory, 0); |
275 | 0 | } |
276 | 0 | } |
277 | | /* Can't render directly. If we don't have a bitmap yet, */ |
278 | | /* get it from the xfont now. */ |
279 | 0 | if (!cc_has_bits(cc)) { |
280 | 0 | gx_device_memory mdev; |
281 | |
|
282 | 0 | gs_make_mem_mono_device(&mdev, dev->memory, imaging_dev); |
283 | 0 | gx_open_cache_device(&mdev, cc); |
284 | 0 | code = (*xf->common.procs->render_char) (xf, xg, |
285 | 0 | (gx_device *) & mdev, cx - x, cy - y, |
286 | 0 | (gx_color_index) 1, 1); |
287 | 0 | if_debug7m('K', penum->memory, |
288 | 0 | "[K]render_char to bits: xfont="PRI_INTPTR", glyph=0x%lx\n\tdev="PRI_INTPTR"(%s) x,y=%d,%d => %d\n", |
289 | 0 | (intptr_t)xf, (ulong) xg, (intptr_t)&mdev, |
290 | 0 | mdev.dname, cx - x, cy - y, code); |
291 | 0 | if (code != 0) { |
292 | 0 | if (imaging_dev == (gx_device *) & cdev) |
293 | 0 | gx_destroy_clip_device_on_stack(&cdev); |
294 | 0 | return_check_interrupt(penum->memory, 1); |
295 | 0 | } |
296 | 0 | gx_add_char_bits(cc_pair(cc)->font->dir, |
297 | 0 | cc, &scale_log2_1); |
298 | | /* gx_add_char_bits may change width, height, */ |
299 | | /* raster, and/or offset. It's easiest to */ |
300 | | /* start over from the top. Clear xg so that */ |
301 | | /* we don't waste time trying render_char again. */ |
302 | 0 | xg = gx_no_xglyph; |
303 | 0 | goto top; |
304 | 0 | } |
305 | 0 | } |
306 | | /* |
307 | | * No xfont. Render from the cached bits. If the cached bits |
308 | | * have more than 1 bit of alpha, and the color isn't pure or |
309 | | * the copy_alpha operation fails, construct a single-bit mask |
310 | | * by taking the high-order alpha bit. |
311 | | */ |
312 | 46.1M | bits = cc_bits(cc); |
313 | | /* With 4x2 scale, depth == 3. |
314 | | * An example is -dTextAlphaBits=4 comparefiles/fonttest.pdf . |
315 | | * We need to map 4 bitmap bits to 2 alpha bits. |
316 | | */ |
317 | 46.1M | depth = (cc_depth(cc) == 3 ? 2 : cc_depth(cc)); |
318 | 46.1M | if ((dev_proc(orig_dev, fill_mask) != gx_default_fill_mask || |
319 | 46.1M | !lop_no_S_is_T(pgs->log_op))) { |
320 | | |
321 | 44.9M | gx_clip_path *pcpath; |
322 | | |
323 | 44.9M | penum->use_wxy_float = false; |
324 | 44.9M | penum->wxy_float.x = penum->wxy_float.y = 0.0; |
325 | 44.9M | penum->wxy = cc->wxy; |
326 | | |
327 | 44.9M | code = gx_effective_clip_path(pgs, &pcpath); |
328 | 44.9M | if (code >= 0) { |
329 | 44.9M | code = gx_image_fill_masked |
330 | 44.9M | (orig_dev, bits, 0, cc_raster(cc), cc->id, |
331 | 44.9M | x, y, w, h, pdevc, depth, pgs->log_op, pcpath); |
332 | 44.9M | if (code >= 0) |
333 | 44.9M | goto done; |
334 | 44.9M | } |
335 | 44.9M | } else if (gs_color_writes_pure(pgs)) { |
336 | 1.20M | gx_color_index color = pdevc->colors.pure; |
337 | | |
338 | 1.20M | if (depth > 1) { |
339 | 0 | code = (*dev_proc(imaging_dev, copy_alpha)) |
340 | 0 | (imaging_dev, bits, 0, cc_raster(cc), cc->id, |
341 | 0 | x, y, w, h, color, depth); |
342 | 0 | if (code >= 0) |
343 | 0 | return_check_interrupt(penum->memory, 0); |
344 | | /* copy_alpha failed, construct a monobit mask. */ |
345 | 0 | bits = compress_alpha_bits(cc, penum->memory->non_gc_memory); |
346 | 0 | if (bits == 0) { |
347 | 0 | if (imaging_dev == (gx_device *) & cdev) |
348 | 0 | gx_destroy_clip_device_on_stack(&cdev); |
349 | 0 | return 1; /* VMerror, but recoverable */ |
350 | 0 | } |
351 | 0 | } |
352 | 1.20M | code = (*dev_proc(imaging_dev, copy_mono)) |
353 | 1.20M | (imaging_dev, bits, 0, bitmap_raster(w), gs_no_id, |
354 | 1.20M | x, y, w, h, gx_no_color_index, color); |
355 | 1.20M | goto done; |
356 | 1.20M | } |
357 | 1.23k | if (depth > 1) { /* Complex color or fill_mask / copy_alpha failed, */ |
358 | | /* construct a monobit mask. */ |
359 | 0 | bits = compress_alpha_bits(cc, penum->memory->non_gc_memory); |
360 | 0 | if (bits == 0) { |
361 | 0 | if (imaging_dev == (gx_device *) & cdev) |
362 | 0 | gx_destroy_clip_device_on_stack(&cdev); |
363 | 0 | return 1; /* VMerror, but recoverable */ |
364 | 0 | } |
365 | 1.23k | } { /* Use imagemask to render the character. */ |
366 | 1.23k | gs_memory_t *mem = penum->memory->non_gc_memory; |
367 | 1.23k | gs_image_enum *pie = |
368 | 1.23k | gs_image_enum_alloc(mem, "image_char(image_enum)"); |
369 | 1.23k | gs_image_t image; |
370 | 1.23k | int iy; |
371 | 1.23k | uint used, raster = (bits == cc_bits(cc) ? cc_raster(cc) |
372 | 1.23k | : bitmap_raster(cc->width) ); |
373 | 1.23k | int code1; |
374 | | |
375 | 1.23k | if (pie == 0) { |
376 | 0 | if (bits != cc_bits(cc)) |
377 | 0 | gs_free_object(mem, bits, |
378 | 0 | "compress_alpha_bits"); |
379 | 0 | if (imaging_dev == (gx_device *) & cdev) |
380 | 0 | gx_destroy_clip_device_on_stack(&cdev); |
381 | 0 | return 1; /* VMerror, but recoverable */ |
382 | 0 | } |
383 | | /* Make a matrix that will place the image */ |
384 | | /* at (x,y) with no transformation. */ |
385 | 1.23k | gs_image_t_init_mask(&image, true); |
386 | 1.23k | gs_make_translation((double) - x, (double) - y, &image.ImageMatrix); |
387 | 1.23k | gs_matrix_multiply(&ctm_only(pgs), &image.ImageMatrix, &image.ImageMatrix); |
388 | 1.23k | image.Width = w; |
389 | 1.23k | image.Height = h; |
390 | 1.23k | image.adjust = false; |
391 | 1.23k | code = gs_image_init(pie, &image, false, true, pgs); |
392 | 1.23k | switch (code) { |
393 | 127 | case 1: /* empty image */ |
394 | 127 | code = 0; |
395 | 127 | default: |
396 | 127 | break; |
397 | 1.10k | case 0: |
398 | 62.9k | for (iy = 0; iy < h && code >= 0; iy++) |
399 | 61.8k | code = gs_image_next(pie, bits + iy * raster, |
400 | 61.8k | (w + 7) >> 3, &used); |
401 | 1.23k | } |
402 | 1.23k | code1 = gs_image_cleanup_and_free_enum(pie, pgs); |
403 | 1.23k | if (code >= 0 && code1 < 0) |
404 | 12 | code = code1; |
405 | 1.23k | } |
406 | 46.1M | done:if (bits != cc_bits(cc)) |
407 | 0 | gs_free_object(penum->memory->non_gc_memory, bits, "compress_alpha_bits"); |
408 | 46.1M | if (code > 0) |
409 | 1.09k | code = 0; |
410 | 46.1M | if (imaging_dev == (gx_device *) & cdev) |
411 | 482k | gx_destroy_clip_device_on_stack(&cdev); |
412 | 46.1M | return_check_interrupt(penum->memory, code); |
413 | 1.23k | } |
414 | | |
415 | | /* ------ Image manipulation ------ */ |
416 | | |
417 | | /* |
418 | | * Compress a mask with 2 or 4 bits of alpha to a monobit mask. |
419 | | * Allocate and return the address of the monobit mask. |
420 | | */ |
421 | | static byte * |
422 | | compress_alpha_bits(const cached_char * cc, gs_memory_t * mem) |
423 | 0 | { |
424 | 0 | const byte *data = cc_const_bits(cc); |
425 | 0 | uint width = cc->width; |
426 | 0 | uint height = cc->height; |
427 | | /* With 4x2 scale, depth == 3. |
428 | | * An example is -dTextAlphaBits=4 comparefiles/fonttest.pdf . |
429 | | * We need to map 4 bitmap bits to 2 alpha bits. |
430 | | */ |
431 | 0 | int depth = (cc_depth(cc) == 3 ? 2 : cc_depth(cc)); |
432 | 0 | uint sraster = cc_raster(cc); |
433 | 0 | uint sskip = sraster - ((width * depth + 7) >> 3); |
434 | 0 | uint draster = bitmap_raster(width); |
435 | 0 | uint dskip = draster - ((width + 7) >> 3); |
436 | 0 | byte *mask = gs_alloc_bytes(mem, (size_t)draster * height, |
437 | 0 | "compress_alpha_bits"); |
438 | 0 | const byte *sptr = data; |
439 | 0 | byte *dptr = mask; |
440 | 0 | uint h; |
441 | |
|
442 | 0 | if (mask == 0) |
443 | 0 | return 0; |
444 | 0 | for (h = height; h; --h) { |
445 | 0 | byte sbit = 0x80; |
446 | 0 | byte d = 0; |
447 | 0 | byte dbit = 0x80; |
448 | 0 | uint w; |
449 | |
|
450 | 0 | for (w = width; w; --w) { |
451 | 0 | if (*sptr & sbit) |
452 | 0 | d += dbit; |
453 | 0 | if (!(sbit >>= depth)) |
454 | 0 | sbit = 0x80, sptr++; |
455 | 0 | if (!(dbit >>= 1)) { |
456 | 0 | *dptr++ = d; |
457 | 0 | dbit = 0x80, d = 0; |
458 | 0 | } |
459 | 0 | } |
460 | 0 | if (dbit != 0x80) |
461 | 0 | *dptr++ = d; |
462 | 0 | for (w = dskip; w != 0; --w) |
463 | 0 | *dptr++ = 0; |
464 | 0 | if (sbit != 0x80) |
465 | 0 | ++sptr; |
466 | 0 | sptr += sskip; |
467 | 0 | } |
468 | 0 | return mask; |
469 | 0 | } |