Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/source/fitz/glyph.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 // Copyright (C) 2004-2021 Artifex Software, Inc. | |
| 2 // | |
| 3 // This file is part of MuPDF. | |
| 4 // | |
| 5 // MuPDF is free software: you can redistribute it and/or modify it under the | |
| 6 // terms of the GNU Affero General Public License as published by the Free | |
| 7 // Software Foundation, either version 3 of the License, or (at your option) | |
| 8 // any later version. | |
| 9 // | |
| 10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY | |
| 11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
| 12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more | |
| 13 // details. | |
| 14 // | |
| 15 // You should have received a copy of the GNU Affero General Public License | |
| 16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> | |
| 17 // | |
| 18 // Alternative licensing terms are available from the licensor. | |
| 19 // For commercial licensing, see <https://www.artifex.com/> or contact | |
| 20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, | |
| 21 // CA 94129, USA, for further information. | |
| 22 | |
| 23 #include "mupdf/fitz.h" | |
| 24 | |
| 25 #include "glyph-imp.h" | |
| 26 #include "pixmap-imp.h" | |
| 27 | |
| 28 #include <string.h> | |
| 29 | |
| 30 #define RLE_THRESHOLD 256 | |
| 31 | |
| 32 fz_glyph * | |
| 33 fz_keep_glyph(fz_context *ctx, fz_glyph *glyph) | |
| 34 { | |
| 35 return fz_keep_storable(ctx, &glyph->storable); | |
| 36 } | |
| 37 | |
| 38 void | |
| 39 fz_drop_glyph(fz_context *ctx, fz_glyph *glyph) | |
| 40 { | |
| 41 fz_drop_storable(ctx, &glyph->storable); | |
| 42 } | |
| 43 | |
| 44 static void | |
| 45 fz_drop_glyph_imp(fz_context *ctx, fz_storable *glyph_) | |
| 46 { | |
| 47 fz_glyph *glyph = (fz_glyph *)glyph_; | |
| 48 fz_drop_pixmap(ctx, glyph->pixmap); | |
| 49 fz_free(ctx, glyph); | |
| 50 } | |
| 51 | |
| 52 fz_irect | |
| 53 fz_glyph_bbox(fz_context *ctx, fz_glyph *glyph) | |
| 54 { | |
| 55 fz_irect bbox; | |
| 56 bbox.x0 = glyph->x; | |
| 57 bbox.y0 = glyph->y; | |
| 58 bbox.x1 = glyph->x + glyph->w; | |
| 59 bbox.y1 = glyph->y + glyph->h; | |
| 60 return bbox; | |
| 61 } | |
| 62 | |
| 63 fz_irect | |
| 64 fz_glyph_bbox_no_ctx(fz_glyph *glyph) | |
| 65 { | |
| 66 fz_irect bbox; | |
| 67 bbox.x0 = glyph->x; | |
| 68 bbox.y0 = glyph->y; | |
| 69 bbox.x1 = glyph->x + glyph->w; | |
| 70 bbox.y1 = glyph->y + glyph->h; | |
| 71 return bbox; | |
| 72 } | |
| 73 | |
| 74 int | |
| 75 fz_glyph_width(fz_context *ctx, fz_glyph *glyph) | |
| 76 { | |
| 77 return glyph->w; | |
| 78 } | |
| 79 | |
| 80 int | |
| 81 fz_glyph_height(fz_context *ctx, fz_glyph *glyph) | |
| 82 { | |
| 83 return glyph->h; | |
| 84 } | |
| 85 | |
| 86 #ifndef NDEBUG | |
| 87 #include <stdio.h> | |
| 88 | |
| 89 void | |
| 90 fz_dump_glyph(fz_glyph *glyph) | |
| 91 { | |
| 92 int x, y; | |
| 93 | |
| 94 if (glyph->pixmap) | |
| 95 { | |
| 96 printf("pixmap glyph\n"); | |
| 97 return; | |
| 98 } | |
| 99 printf("glyph: %dx%d @ (%d,%d)\n", glyph->w, glyph->h, glyph->x, glyph->y); | |
| 100 | |
| 101 for (y = 0; y < glyph->h; y++) | |
| 102 { | |
| 103 int offset = ((int *)(glyph->data))[y]; | |
| 104 if (offset >= 0) | |
| 105 { | |
| 106 int extend = 0; | |
| 107 int eol = 0; | |
| 108 x = glyph->w; | |
| 109 do | |
| 110 { | |
| 111 int v = glyph->data[offset++]; | |
| 112 int len; | |
| 113 char c; | |
| 114 switch(v&3) | |
| 115 { | |
| 116 case 0: /* extend */ | |
| 117 extend = v>>2; | |
| 118 len = 0; | |
| 119 break; | |
| 120 case 1: /* Transparent pixels */ | |
| 121 len = 1 + (v>>2) + (extend<<6); | |
| 122 extend = 0; | |
| 123 c = '.'; | |
| 124 break; | |
| 125 case 2: /* Solid pixels */ | |
| 126 len = 1 + (v>>3) + (extend<<5); | |
| 127 extend = 0; | |
| 128 eol = v & 4; | |
| 129 c = (eol ? '$' :'#'); | |
| 130 break; | |
| 131 default: /* Intermediate pixels */ | |
| 132 len = 1 + (v>>3) + (extend<<5); | |
| 133 extend = 0; | |
| 134 offset += len; | |
| 135 eol = v & 4; | |
| 136 c = (eol ? '!' : '?'); | |
| 137 break; | |
| 138 } | |
| 139 x -= len; | |
| 140 while (len--) | |
| 141 fputc(c, stdout); | |
| 142 if (eol) | |
| 143 break; | |
| 144 } | |
| 145 while (x > 0); | |
| 146 } | |
| 147 printf("\n"); | |
| 148 } | |
| 149 } | |
| 150 #endif | |
| 151 | |
| 152 fz_glyph * | |
| 153 fz_new_glyph_from_pixmap(fz_context *ctx, fz_pixmap *pix) | |
| 154 { | |
| 155 fz_glyph *glyph = NULL; | |
| 156 | |
| 157 if (pix == NULL) | |
| 158 return NULL; | |
| 159 | |
| 160 fz_var(glyph); | |
| 161 | |
| 162 fz_try(ctx) | |
| 163 { | |
| 164 if (pix->n != 1 || pix->w * pix->h < RLE_THRESHOLD) | |
| 165 { | |
| 166 glyph = fz_malloc_struct(ctx, fz_glyph); | |
| 167 FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp); | |
| 168 glyph->x = pix->x; | |
| 169 glyph->y = pix->y; | |
| 170 glyph->w = pix->w; | |
| 171 glyph->h = pix->h; | |
| 172 glyph->size = fz_pixmap_size(ctx, pix); | |
| 173 glyph->pixmap = fz_keep_pixmap(ctx, pix); | |
| 174 } | |
| 175 else | |
| 176 glyph = fz_new_glyph_from_8bpp_data(ctx, pix->x, pix->y, pix->w, pix->h, pix->samples, pix->stride); | |
| 177 } | |
| 178 fz_always(ctx) | |
| 179 { | |
| 180 fz_drop_pixmap(ctx, pix); | |
| 181 } | |
| 182 fz_catch(ctx) | |
| 183 { | |
| 184 fz_rethrow(ctx); | |
| 185 } | |
| 186 | |
| 187 return glyph; | |
| 188 } | |
| 189 | |
| 190 fz_glyph * | |
| 191 fz_new_glyph_from_8bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span) | |
| 192 { | |
| 193 fz_glyph *glyph = NULL; | |
| 194 fz_pixmap *pix = NULL; | |
| 195 int size, fill, yy; | |
| 196 unsigned char *orig_sp = sp; | |
| 197 | |
| 198 fz_var(glyph); | |
| 199 fz_var(pix); | |
| 200 | |
| 201 fz_try(ctx) | |
| 202 { | |
| 203 /* We start out by allocating space as large as the pixmap. | |
| 204 * If we need more than that give up on using RLE. We can | |
| 205 * never hope to beat the pixmap for really small sizes. */ | |
| 206 if (w <= 6 || w * h < RLE_THRESHOLD) | |
| 207 goto try_pixmap; | |
| 208 | |
| 209 size = h * w; | |
| 210 fill = h * sizeof(int); | |
| 211 glyph = Memento_label(fz_malloc(ctx, sizeof(fz_glyph) + size), "fz_glyph(8)"); | |
| 212 FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp); | |
| 213 glyph->x = x; | |
| 214 glyph->y = y; | |
| 215 glyph->w = w; | |
| 216 glyph->h = h; | |
| 217 glyph->pixmap = NULL; | |
| 218 if (h == 0) | |
| 219 { | |
| 220 glyph->size = 0; | |
| 221 break; | |
| 222 } | |
| 223 for (yy=0; yy < h; yy++) | |
| 224 { | |
| 225 int nonblankfill = fill; | |
| 226 int nonblankfill_end = fill; | |
| 227 int linefill = fill; | |
| 228 int ww = w; | |
| 229 do | |
| 230 { | |
| 231 int code; | |
| 232 int len = ww; | |
| 233 int needed; | |
| 234 unsigned char *ep; | |
| 235 switch (*sp) | |
| 236 { | |
| 237 case 0: | |
| 238 if (len > 0x1000) | |
| 239 len = 0x1000; | |
| 240 ep = sp+len; | |
| 241 while (++sp != ep && *sp == 0); | |
| 242 code = 1; | |
| 243 len -= ep-sp; | |
| 244 ww -= len; | |
| 245 needed = fill + 1 + (len > 0x40); | |
| 246 break; | |
| 247 case 255: | |
| 248 if (len > 0x800) | |
| 249 len = 0x800; | |
| 250 ep = sp+len; | |
| 251 while (++sp != ep && *sp == 255); | |
| 252 code = 2; | |
| 253 len -= ep-sp; | |
| 254 ww -= len; | |
| 255 needed = fill + 1 + (len > 0x20); | |
| 256 break; | |
| 257 default: | |
| 258 { | |
| 259 unsigned char c; | |
| 260 if (len > 0x800) | |
| 261 len = 0x800; | |
| 262 ep = sp+len; | |
| 263 while (++sp != ep && (c = *sp) != 255 && c != 0); | |
| 264 len -= ep-sp; | |
| 265 ww -= len; | |
| 266 needed = fill + 1 + len + (len > 0x20); | |
| 267 code = 3; | |
| 268 } | |
| 269 } | |
| 270 if (needed > size) | |
| 271 goto try_pixmap; | |
| 272 if (code == 1) | |
| 273 { | |
| 274 if (len > 0x40) | |
| 275 glyph->data[fill++] = ((len-1)>>6)<<2; | |
| 276 glyph->data[fill++] = 1 | (((len-1)&63)<<2); | |
| 277 } | |
| 278 else | |
| 279 { | |
| 280 if (len > 0x20) | |
| 281 glyph->data[fill++] = ((len-1)>>5)<<2; | |
| 282 nonblankfill = fill; | |
| 283 glyph->data[fill++] = code | (((len-1)&31)<<3); | |
| 284 if (code == 3) | |
| 285 { | |
| 286 memcpy(&glyph->data[fill], sp - len, len); | |
| 287 fill += len; | |
| 288 } | |
| 289 nonblankfill_end = fill; | |
| 290 } | |
| 291 } | |
| 292 while (ww > 0); | |
| 293 if (nonblankfill_end == linefill) | |
| 294 { | |
| 295 ((int *)(glyph->data))[yy] = -1; | |
| 296 fill = linefill; | |
| 297 } | |
| 298 else | |
| 299 { | |
| 300 glyph->data[nonblankfill] |= 4; | |
| 301 fill = nonblankfill_end; | |
| 302 ((int *)(glyph->data))[yy] = linefill; | |
| 303 } | |
| 304 sp += span - w; | |
| 305 } | |
| 306 if (fill != size) | |
| 307 { | |
| 308 glyph = fz_realloc(ctx, glyph, sizeof(fz_glyph) + fill); | |
| 309 size = fill; | |
| 310 } | |
| 311 glyph->size = size; | |
| 312 break; | |
| 313 | |
| 314 /* Nasty use of a goto here, but it saves us having to exit | |
| 315 * and reenter the try context, and this routine is speed | |
| 316 * critical. */ | |
| 317 try_pixmap: | |
| 318 glyph = Memento_label(fz_realloc(ctx, glyph, sizeof(fz_glyph)), "fz_glyph(8r)"); | |
| 319 FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp); | |
| 320 pix = fz_new_pixmap_from_8bpp_data(ctx, x, y, w, h, orig_sp, span); | |
| 321 glyph->x = pix->x; | |
| 322 glyph->y = pix->y; | |
| 323 glyph->w = pix->w; | |
| 324 glyph->h = pix->h; | |
| 325 glyph->size = fz_pixmap_size(ctx, pix); | |
| 326 glyph->pixmap = pix; | |
| 327 } | |
| 328 fz_catch(ctx) | |
| 329 { | |
| 330 fz_drop_pixmap(ctx, pix); | |
| 331 fz_free(ctx, glyph); | |
| 332 fz_rethrow(ctx); | |
| 333 } | |
| 334 | |
| 335 return glyph; | |
| 336 } | |
| 337 | |
| 338 fz_glyph * | |
| 339 fz_new_glyph_from_1bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span) | |
| 340 { | |
| 341 fz_pixmap *pix = NULL; | |
| 342 fz_glyph *glyph = NULL; | |
| 343 int size, fill, yy; | |
| 344 unsigned char *orig_sp = sp; | |
| 345 | |
| 346 fz_var(glyph); | |
| 347 fz_var(pix); | |
| 348 | |
| 349 fz_try(ctx) | |
| 350 { | |
| 351 /* We start out by allocating space as large as the pixmap. | |
| 352 * If we need more than that give up on using RLE. We can | |
| 353 * never hope to beat the pixmap for really small sizes. */ | |
| 354 if (w <= 6 || w * h < RLE_THRESHOLD) | |
| 355 goto try_pixmap; | |
| 356 | |
| 357 size = h * w; | |
| 358 fill = h * sizeof(int); | |
| 359 glyph = Memento_label(fz_malloc(ctx, sizeof(fz_glyph) + size), "fz_glyph(1)"); | |
| 360 FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp); | |
| 361 glyph->x = x; | |
| 362 glyph->y = y; | |
| 363 glyph->w = w; | |
| 364 glyph->h = h; | |
| 365 glyph->pixmap = NULL; | |
| 366 if (h == 0) | |
| 367 { | |
| 368 glyph->size = 0; | |
| 369 break; | |
| 370 } | |
| 371 for (yy=0; yy < h; yy++) | |
| 372 { | |
| 373 int nonblankfill = fill; | |
| 374 int nonblankfill_end = fill; | |
| 375 int linefill = fill; | |
| 376 int ww = w; | |
| 377 int bit = 0x80; | |
| 378 do | |
| 379 { | |
| 380 int len = 0; | |
| 381 int needed; | |
| 382 int b = *sp & bit; | |
| 383 bit >>= 1; | |
| 384 if (bit == 0) | |
| 385 bit = 0x80, sp++; | |
| 386 ww--; | |
| 387 if (b == 0) | |
| 388 { | |
| 389 while (ww > 0 && len < 0xfff && (*sp & bit) == 0) | |
| 390 { | |
| 391 bit >>= 1; | |
| 392 if (bit == 0) | |
| 393 bit = 0x80, sp++; | |
| 394 len++; | |
| 395 ww--; | |
| 396 } | |
| 397 needed = fill + (len >= 0x40) + 1; | |
| 398 if (needed > size) | |
| 399 goto try_pixmap; | |
| 400 if (len >= 0x40) | |
| 401 glyph->data[fill++] = (len>>6)<<2; | |
| 402 glyph->data[fill++] = 1 | ((len&63)<<2); | |
| 403 } | |
| 404 else | |
| 405 { | |
| 406 while (ww > 0 && len < 0x7ff && (*sp & bit) != 0) | |
| 407 { | |
| 408 bit >>= 1; | |
| 409 if (bit == 0) | |
| 410 bit = 0x80, sp++; | |
| 411 len++; | |
| 412 ww--; | |
| 413 } | |
| 414 needed = fill + (len >= 0x20) + 1; | |
| 415 if (needed > size) | |
| 416 goto try_pixmap; | |
| 417 if (len >= 0x20) | |
| 418 glyph->data[fill++] = (len>>5)<<2; | |
| 419 nonblankfill = fill; | |
| 420 glyph->data[fill++] = 2 | ((len&31)<<3); | |
| 421 nonblankfill_end = fill; | |
| 422 } | |
| 423 } | |
| 424 while (ww > 0); | |
| 425 if (nonblankfill_end == linefill) | |
| 426 { | |
| 427 ((int *)(glyph->data))[yy] = -1; | |
| 428 fill = linefill; | |
| 429 } | |
| 430 else | |
| 431 { | |
| 432 glyph->data[nonblankfill] |= 4; | |
| 433 fill = nonblankfill_end; | |
| 434 ((int *)(glyph->data))[yy] = linefill; | |
| 435 } | |
| 436 sp += span - (w>>3); | |
| 437 } | |
| 438 if (fill != size) | |
| 439 { | |
| 440 glyph = fz_realloc(ctx, glyph, sizeof(fz_glyph) + fill); | |
| 441 size = fill; | |
| 442 } | |
| 443 glyph->size = size; | |
| 444 break; | |
| 445 | |
| 446 /* Nasty use of a goto here, but it saves us having to exit | |
| 447 * and reenter the try context, and this routine is speed | |
| 448 * critical. */ | |
| 449 try_pixmap: | |
| 450 glyph = fz_realloc(ctx, glyph, sizeof(fz_glyph)); | |
| 451 FZ_INIT_STORABLE(glyph, 1, fz_drop_glyph_imp); | |
| 452 pix = fz_new_pixmap_from_1bpp_data(ctx, x, y, w, h, orig_sp, span); | |
| 453 glyph->x = pix->x; | |
| 454 glyph->y = pix->y; | |
| 455 glyph->w = pix->w; | |
| 456 glyph->h = pix->h; | |
| 457 glyph->size = fz_pixmap_size(ctx, pix); | |
| 458 glyph->pixmap = pix; | |
| 459 } | |
| 460 fz_catch(ctx) | |
| 461 { | |
| 462 fz_drop_pixmap(ctx, pix); | |
| 463 fz_free(ctx, glyph); | |
| 464 fz_rethrow(ctx); | |
| 465 } | |
| 466 | |
| 467 return glyph; | |
| 468 } |
