Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/source/fitz/image.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-2025 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 "context-imp.h" | |
| 26 #include "image-imp.h" | |
| 27 #include "pixmap-imp.h" | |
| 28 | |
| 29 #include <string.h> | |
| 30 #include <math.h> | |
| 31 #include <assert.h> | |
| 32 | |
| 33 /* TODO: here or public? */ | |
| 34 static int | |
| 35 fz_key_storable_needs_reaping(fz_context *ctx, const fz_key_storable *ks) | |
| 36 { | |
| 37 return ks == NULL ? 0 : (ks->store_key_refs == ks->storable.refs); | |
| 38 } | |
| 39 | |
| 40 #define SANE_DPI 72.0f | |
| 41 #define INSANE_DPI 4800.0f | |
| 42 | |
| 43 #define SCALABLE_IMAGE_DPI 96 | |
| 44 | |
| 45 struct fz_compressed_image | |
| 46 { | |
| 47 fz_image super; | |
| 48 fz_compressed_buffer *buffer; | |
| 49 }; | |
| 50 | |
| 51 struct fz_pixmap_image | |
| 52 { | |
| 53 fz_image super; | |
| 54 fz_pixmap *tile; | |
| 55 }; | |
| 56 | |
| 57 typedef struct | |
| 58 { | |
| 59 int refs; | |
| 60 fz_image *image; | |
| 61 int l2factor; | |
| 62 fz_irect rect; | |
| 63 } fz_image_key; | |
| 64 | |
| 65 fz_image * | |
| 66 fz_keep_image(fz_context *ctx, fz_image *image) | |
| 67 { | |
| 68 return fz_keep_key_storable(ctx, &image->key_storable); | |
| 69 } | |
| 70 | |
| 71 fz_image * | |
| 72 fz_keep_image_store_key(fz_context *ctx, fz_image *image) | |
| 73 { | |
| 74 return fz_keep_key_storable_key(ctx, &image->key_storable); | |
| 75 } | |
| 76 | |
| 77 void | |
| 78 fz_drop_image_store_key(fz_context *ctx, fz_image *image) | |
| 79 { | |
| 80 fz_drop_key_storable_key(ctx, &image->key_storable); | |
| 81 } | |
| 82 | |
| 83 static int | |
| 84 fz_make_hash_image_key(fz_context *ctx, fz_store_hash *hash, void *key_) | |
| 85 { | |
| 86 fz_image_key *key = (fz_image_key *)key_; | |
| 87 hash->u.pir.ptr = key->image; | |
| 88 hash->u.pir.i = key->l2factor; | |
| 89 hash->u.pir.r = key->rect; | |
| 90 return 1; | |
| 91 } | |
| 92 | |
| 93 static void * | |
| 94 fz_keep_image_key(fz_context *ctx, void *key_) | |
| 95 { | |
| 96 fz_image_key *key = (fz_image_key *)key_; | |
| 97 return fz_keep_imp(ctx, key, &key->refs); | |
| 98 } | |
| 99 | |
| 100 static void | |
| 101 fz_drop_image_key(fz_context *ctx, void *key_) | |
| 102 { | |
| 103 fz_image_key *key = (fz_image_key *)key_; | |
| 104 if (fz_drop_imp(ctx, key, &key->refs)) | |
| 105 { | |
| 106 fz_drop_image_store_key(ctx, key->image); | |
| 107 fz_free(ctx, key); | |
| 108 } | |
| 109 } | |
| 110 | |
| 111 static int | |
| 112 fz_cmp_image_key(fz_context *ctx, void *k0_, void *k1_) | |
| 113 { | |
| 114 fz_image_key *k0 = (fz_image_key *)k0_; | |
| 115 fz_image_key *k1 = (fz_image_key *)k1_; | |
| 116 return k0->image == k1->image && k0->l2factor == k1->l2factor && k0->rect.x0 == k1->rect.x0 && k0->rect.y0 == k1->rect.y0 && k0->rect.x1 == k1->rect.x1 && k0->rect.y1 == k1->rect.y1; | |
| 117 } | |
| 118 | |
| 119 static void | |
| 120 fz_format_image_key(fz_context *ctx, char *s, size_t n, void *key_) | |
| 121 { | |
| 122 fz_image_key *key = (fz_image_key *)key_; | |
| 123 fz_snprintf(s, n, "(image %d x %d sf=%d)", key->image->w, key->image->h, key->l2factor); | |
| 124 } | |
| 125 | |
| 126 static int | |
| 127 fz_needs_reap_image_key(fz_context *ctx, void *key_) | |
| 128 { | |
| 129 fz_image_key *key = (fz_image_key *)key_; | |
| 130 | |
| 131 return fz_key_storable_needs_reaping(ctx, &key->image->key_storable); | |
| 132 } | |
| 133 | |
| 134 static const fz_store_type fz_image_store_type = | |
| 135 { | |
| 136 "fz_image", | |
| 137 fz_make_hash_image_key, | |
| 138 fz_keep_image_key, | |
| 139 fz_drop_image_key, | |
| 140 fz_cmp_image_key, | |
| 141 fz_format_image_key, | |
| 142 fz_needs_reap_image_key | |
| 143 }; | |
| 144 | |
| 145 void | |
| 146 fz_drop_image(fz_context *ctx, fz_image *image) | |
| 147 { | |
| 148 fz_drop_key_storable(ctx, &image->key_storable); | |
| 149 } | |
| 150 | |
| 151 static void | |
| 152 fz_mask_color_key(fz_context *ctx, fz_pixmap *pix, int n, int bpc, const int *colorkey_in, int indexed) | |
| 153 { | |
| 154 unsigned char *p = pix->samples; | |
| 155 int w; | |
| 156 int k, t; | |
| 157 int h = pix->h; | |
| 158 size_t stride = pix->stride - pix->w * (size_t)pix->n; | |
| 159 int colorkey[FZ_MAX_COLORS * 2]; | |
| 160 int scale, shift, max; | |
| 161 | |
| 162 if (pix->w == 0) | |
| 163 return; | |
| 164 | |
| 165 if (indexed) | |
| 166 { | |
| 167 /* no upscaling or downshifting needed for indexed images */ | |
| 168 scale = 1; | |
| 169 shift = 0; | |
| 170 } | |
| 171 else | |
| 172 { | |
| 173 switch (bpc) | |
| 174 { | |
| 175 case 1: scale = 255; shift = 0; break; | |
| 176 case 2: scale = 85; shift = 0; break; | |
| 177 case 4: scale = 17; shift = 0; break; | |
| 178 default: | |
| 179 case 8: scale = 1; shift = 0; break; | |
| 180 case 16: scale = 1; shift = 8; break; | |
| 181 case 24: scale = 1; shift = 16; break; | |
| 182 case 32: scale = 1; shift = 24; break; | |
| 183 } | |
| 184 } | |
| 185 | |
| 186 switch (bpc) | |
| 187 { | |
| 188 case 1: max = 1; break; | |
| 189 case 2: max = 3; break; | |
| 190 case 4: max = 15; break; | |
| 191 default: | |
| 192 case 8: max = 0xff; break; | |
| 193 case 16: max = 0xffff; break; | |
| 194 case 24: max = 0xffffff; break; | |
| 195 case 32: max = 0xffffffff; break; | |
| 196 } | |
| 197 | |
| 198 for (k = 0; k < 2 * n; k++) | |
| 199 { | |
| 200 colorkey[k] = colorkey_in[k]; | |
| 201 | |
| 202 if (colorkey[k] > max) | |
| 203 { | |
| 204 if (indexed && bpc == 1) | |
| 205 { | |
| 206 if (k == 0) | |
| 207 { | |
| 208 fz_warn(ctx, "first color key masking value out of range in 1bpc indexed image, ignoring color key masking"); | |
| 209 return; | |
| 210 } | |
| 211 fz_warn(ctx, "later color key masking value out of range in 1bpc indexed image, assumed to be 1"); | |
| 212 colorkey[k] = 1; | |
| 213 } | |
| 214 else if (bpc != 1) | |
| 215 { | |
| 216 fz_warn(ctx, "color key masking value out of range, masking to valid range"); | |
| 217 colorkey[k] &= max; | |
| 218 } | |
| 219 } | |
| 220 | |
| 221 if (colorkey[k] < 0 || colorkey[k] > max) | |
| 222 { | |
| 223 fz_warn(ctx, "color key masking value out of range, clamping to valid range"); | |
| 224 colorkey[k] = fz_clampi(colorkey[k], 0, max); | |
| 225 } | |
| 226 | |
| 227 if (scale > 1) | |
| 228 { | |
| 229 /* scale up color key masking value so it can be compared with samples. */ | |
| 230 colorkey[k] *= scale; | |
| 231 } | |
| 232 else if (shift > 0) | |
| 233 { | |
| 234 /* shifting down color key masking value so it can be compared with samples. */ | |
| 235 colorkey[k] >>= shift; | |
| 236 } | |
| 237 } | |
| 238 | |
| 239 while (h--) | |
| 240 { | |
| 241 w = pix->w; | |
| 242 do | |
| 243 { | |
| 244 t = 1; | |
| 245 for (k = 0; k < n; k++) | |
| 246 if (p[k] < colorkey[k * 2] || p[k] > colorkey[k * 2 + 1]) | |
| 247 t = 0; | |
| 248 if (t) | |
| 249 for (k = 0; k < pix->n; k++) | |
| 250 p[k] = 0; | |
| 251 p += pix->n; | |
| 252 } | |
| 253 while (--w); | |
| 254 p += stride; | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 static void | |
| 259 fz_unblend_masked_tile(fz_context *ctx, fz_pixmap *tile, fz_image *image, const fz_irect *isa) | |
| 260 { | |
| 261 fz_pixmap *mask; | |
| 262 unsigned char *s, *d = tile->samples; | |
| 263 int n = tile->n; | |
| 264 int k; | |
| 265 size_t sstride, dstride = tile->stride - tile->w * (size_t)tile->n; | |
| 266 int h; | |
| 267 fz_irect subarea; | |
| 268 | |
| 269 /* We need at least as much of the mask as there was of the tile. */ | |
| 270 if (isa) | |
| 271 subarea = *isa; | |
| 272 else | |
| 273 { | |
| 274 subarea.x0 = 0; | |
| 275 subarea.y0 = 0; | |
| 276 subarea.x1 = tile->w; | |
| 277 subarea.y1 = tile->h; | |
| 278 } | |
| 279 | |
| 280 mask = fz_get_pixmap_from_image(ctx, image->mask, &subarea, NULL, NULL, NULL); | |
| 281 s = mask->samples; | |
| 282 /* RJW: Urgh, bit of nastiness here. fz_pixmap_from_image will either return | |
| 283 * an exact match for the subarea we asked for, or the full image, and the | |
| 284 * normal way to know is that the matrix will be updated. That doesn't help | |
| 285 * us here. */ | |
| 286 if (image->mask->w == mask->w && image->mask->h == mask->h) { | |
| 287 subarea.x0 = 0; | |
| 288 subarea.y0 = 0; | |
| 289 } | |
| 290 if (isa) | |
| 291 s += (isa->x0 - subarea.x0) * (size_t)mask->n + (isa->y0 - subarea.y0) * (size_t)mask->stride; | |
| 292 sstride = mask->stride - tile->w * (size_t)mask->n; | |
| 293 h = tile->h; | |
| 294 | |
| 295 if (tile->w != 0) | |
| 296 { | |
| 297 while (h--) | |
| 298 { | |
| 299 int w = tile->w; | |
| 300 do | |
| 301 { | |
| 302 if (*s == 0) | |
| 303 for (k = 0; k < image->n; k++) | |
| 304 d[k] = image->colorkey[k]; | |
| 305 else | |
| 306 for (k = 0; k < image->n; k++) | |
| 307 d[k] = fz_clampi(image->colorkey[k] + (d[k] - image->colorkey[k]) * 255 / *s, 0, 255); | |
| 308 s++; | |
| 309 d += n; | |
| 310 } | |
| 311 while (--w); | |
| 312 s += sstride; | |
| 313 d += dstride; | |
| 314 } | |
| 315 } | |
| 316 | |
| 317 fz_drop_pixmap(ctx, mask); | |
| 318 } | |
| 319 | |
| 320 static void fz_adjust_image_subarea(fz_context *ctx, fz_image *image, fz_irect *subarea, int l2factor) | |
| 321 { | |
| 322 int f = 1<<l2factor; | |
| 323 int bpp = image->bpc * image->n; | |
| 324 int mask; | |
| 325 | |
| 326 switch (bpp) | |
| 327 { | |
| 328 case 1: mask = 8*f; break; | |
| 329 case 2: mask = 4*f; break; | |
| 330 case 4: mask = 2*f; break; | |
| 331 default: mask = (bpp & 7) == 0 ? f : 0; break; | |
| 332 } | |
| 333 | |
| 334 if (mask != 0) | |
| 335 { | |
| 336 subarea->x0 &= ~(mask - 1); | |
| 337 subarea->x1 = (subarea->x1 + mask - 1) & ~(mask - 1); | |
| 338 } | |
| 339 else | |
| 340 { | |
| 341 /* Awkward case - mask cannot be a power of 2. */ | |
| 342 mask = bpp*f; | |
| 343 switch (bpp) | |
| 344 { | |
| 345 case 3: | |
| 346 case 5: | |
| 347 case 7: | |
| 348 case 9: | |
| 349 case 11: | |
| 350 case 13: | |
| 351 case 15: | |
| 352 default: | |
| 353 mask *= 8; | |
| 354 break; | |
| 355 case 6: | |
| 356 case 10: | |
| 357 case 14: | |
| 358 mask *= 4; | |
| 359 break; | |
| 360 case 12: | |
| 361 mask *= 2; | |
| 362 break; | |
| 363 } | |
| 364 subarea->x0 = (subarea->x0 / mask) * mask; | |
| 365 subarea->x1 = ((subarea->x1 + mask - 1) / mask) * mask; | |
| 366 } | |
| 367 | |
| 368 subarea->y0 &= ~(f - 1); | |
| 369 if (subarea->x1 > image->w) | |
| 370 subarea->x1 = image->w; | |
| 371 subarea->y1 = (subarea->y1 + f - 1) & ~(f - 1); | |
| 372 if (subarea->y1 > image->h) | |
| 373 subarea->y1 = image->h; | |
| 374 } | |
| 375 | |
| 376 static void fz_compute_image_key(fz_context *ctx, fz_image *image, fz_matrix *ctm, | |
| 377 fz_image_key *key, const fz_irect *subarea, int l2factor, int *w, int *h, int *dw, int *dh) | |
| 378 { | |
| 379 key->refs = 1; | |
| 380 key->image = image; | |
| 381 key->l2factor = l2factor; | |
| 382 | |
| 383 if (subarea == NULL) | |
| 384 { | |
| 385 key->rect.x0 = 0; | |
| 386 key->rect.y0 = 0; | |
| 387 key->rect.x1 = image->w; | |
| 388 key->rect.y1 = image->h; | |
| 389 } | |
| 390 else | |
| 391 { | |
| 392 key->rect = *subarea; | |
| 393 ctx->tuning->image_decode(ctx->tuning->image_decode_arg, image->w, image->h, key->l2factor, &key->rect); | |
| 394 fz_adjust_image_subarea(ctx, image, &key->rect, key->l2factor); | |
| 395 } | |
| 396 | |
| 397 /* Based on that subarea, recalculate the extents */ | |
| 398 if (ctm) | |
| 399 { | |
| 400 float frac_w = (float) (key->rect.x1 - key->rect.x0) / image->w; | |
| 401 float frac_h = (float) (key->rect.y1 - key->rect.y0) / image->h; | |
| 402 float a = ctm->a * frac_w; | |
| 403 float b = ctm->b * frac_w; | |
| 404 float c = ctm->c * frac_h; | |
| 405 float d = ctm->d * frac_h; | |
| 406 *w = sqrtf(a * a + b * b); | |
| 407 *h = sqrtf(c * c + d * d); | |
| 408 } | |
| 409 else | |
| 410 { | |
| 411 *w = image->w; | |
| 412 *h = image->h; | |
| 413 } | |
| 414 | |
| 415 /* Return the true sizes to the caller */ | |
| 416 if (dw) | |
| 417 *dw = *w; | |
| 418 if (dh) | |
| 419 *dh = *h; | |
| 420 if (*w > image->w) | |
| 421 *w = image->w; | |
| 422 if (*h > image->h) | |
| 423 *h = image->h; | |
| 424 | |
| 425 if (*w == 0 || *h == 0) | |
| 426 key->l2factor = 0; | |
| 427 } | |
| 428 | |
| 429 typedef struct { | |
| 430 fz_stream *src; | |
| 431 size_t l_skip; /* Number of bytes to skip on the left. */ | |
| 432 size_t r_skip; /* Number of bytes to skip on the right. */ | |
| 433 size_t b_skip; /* Number of bytes to skip on the bottom. */ | |
| 434 int lines; /* Number of lines left to copy. */ | |
| 435 size_t stride; /* Number of bytes to read in the image. */ | |
| 436 size_t nskip; /* Number of bytes left to skip on this line. */ | |
| 437 size_t nread; /* Number of bytes left to read on this line. */ | |
| 438 } subarea_state; | |
| 439 | |
| 440 static int | |
| 441 subarea_next(fz_context *ctx, fz_stream *stm, size_t len) | |
| 442 { | |
| 443 subarea_state *state = stm->state; | |
| 444 size_t n; | |
| 445 | |
| 446 stm->wp = stm->rp = NULL; | |
| 447 | |
| 448 while (state->nskip > 0) | |
| 449 { | |
| 450 n = fz_skip(ctx, state->src, state->nskip); | |
| 451 if (n == 0) | |
| 452 return EOF; | |
| 453 state->nskip -= n; | |
| 454 } | |
| 455 if (state->lines == 0) | |
| 456 return EOF; | |
| 457 n = fz_available(ctx, state->src, state->nread); | |
| 458 if (n > state->nread) | |
| 459 n = state->nread; | |
| 460 if (n == 0) | |
| 461 return EOF; | |
| 462 stm->rp = state->src->rp; | |
| 463 stm->wp = stm->rp + n; | |
| 464 stm->pos += n; | |
| 465 state->src->rp = stm->wp; | |
| 466 state->nread -= n; | |
| 467 if (state->nread == 0) | |
| 468 { | |
| 469 state->lines--; | |
| 470 if (state->lines == 0) | |
| 471 state->nskip = state->r_skip + state->b_skip; | |
| 472 else | |
| 473 state->nskip = state->l_skip + state->r_skip; | |
| 474 state->nread = state->stride; | |
| 475 } | |
| 476 return *stm->rp++; | |
| 477 } | |
| 478 | |
| 479 static void | |
| 480 subarea_drop(fz_context *ctx, void *state) | |
| 481 { | |
| 482 fz_free(ctx, state); | |
| 483 } | |
| 484 | |
| 485 static fz_stream * | |
| 486 subarea_stream(fz_context *ctx, fz_stream *stm, fz_image *image, const fz_irect *subarea, int l2factor) | |
| 487 { | |
| 488 subarea_state *state; | |
| 489 int f = 1<<l2factor; | |
| 490 int stream_w = (image->w + f - 1)>>l2factor; | |
| 491 size_t stream_stride = (stream_w * (size_t)image->n * image->bpc + 7) / 8; | |
| 492 int l_margin = subarea->x0 >> l2factor; | |
| 493 int t_margin = subarea->y0 >> l2factor; | |
| 494 int r_margin = (image->w + f - 1 - subarea->x1) >> l2factor; | |
| 495 int b_margin = (image->h + f - 1 - subarea->y1) >> l2factor; | |
| 496 size_t l_skip = (l_margin * (size_t)image->n * image->bpc)/8; | |
| 497 size_t r_skip = (r_margin * (size_t)image->n * image->bpc + 7)/8; | |
| 498 size_t t_skip = t_margin * stream_stride; | |
| 499 size_t b_skip = b_margin * stream_stride; | |
| 500 int h = (subarea->y1 - subarea->y0 + f - 1) >> l2factor; | |
| 501 int w = (subarea->x1 - subarea->x0 + f - 1) >> l2factor; | |
| 502 size_t stride = (w * (size_t)image->n * image->bpc + 7) / 8; | |
| 503 | |
| 504 state = fz_malloc_struct(ctx, subarea_state); | |
| 505 state->src = stm; | |
| 506 state->l_skip = l_skip; | |
| 507 state->r_skip = r_skip; | |
| 508 state->b_skip = b_skip; | |
| 509 state->lines = h; | |
| 510 state->nskip = l_skip+t_skip; | |
| 511 state->stride = stride; | |
| 512 state->nread = stride; | |
| 513 | |
| 514 return fz_new_stream(ctx, state, subarea_next, subarea_drop); | |
| 515 } | |
| 516 | |
| 517 typedef struct | |
| 518 { | |
| 519 fz_stream *src; | |
| 520 int w; /* Width in source pixels. */ | |
| 521 int h; /* Height (remaining) in scanlines. */ | |
| 522 int n; /* Number of components. */ | |
| 523 int f; /* Fill level (how many scanlines we've copied in). */ | |
| 524 size_t r; /* How many samples Remain to be filled in this line. */ | |
| 525 int l2; /* The amount of subsampling we're doing. */ | |
| 526 unsigned char data[1]; | |
| 527 } l2sub_state; | |
| 528 | |
| 529 static void | |
| 530 subsample_drop(fz_context *ctx, void *state) | |
| 531 { | |
| 532 fz_free(ctx, state); | |
| 533 } | |
| 534 | |
| 535 static int | |
| 536 subsample_next(fz_context *ctx, fz_stream *stm, size_t len) | |
| 537 { | |
| 538 l2sub_state *state = (l2sub_state *)stm->state; | |
| 539 size_t fill; | |
| 540 | |
| 541 stm->rp = stm->wp = &state->data[0]; | |
| 542 if (state->h == 0) | |
| 543 return EOF; | |
| 544 | |
| 545 /* Copy in data */ | |
| 546 do | |
| 547 { | |
| 548 if (state->r == 0) | |
| 549 state->r = state->w * (size_t)state->n; | |
| 550 | |
| 551 while (state->r > 0) | |
| 552 { | |
| 553 size_t a; | |
| 554 a = fz_available(ctx, state->src, state->r); | |
| 555 if (a == 0) | |
| 556 return EOF; | |
| 557 if (a > state->r) | |
| 558 a = state->r; | |
| 559 memcpy(&state->data[state->w * (size_t)state->n * (state->f+1) - state->r], | |
| 560 state->src->rp, a); | |
| 561 state->src->rp += a; | |
| 562 state->r -= a; | |
| 563 } | |
| 564 state->f++; | |
| 565 state->h--; | |
| 566 } | |
| 567 while (state->h > 0 && state->f != (1<<state->l2)); | |
| 568 | |
| 569 /* Perform the subsample */ | |
| 570 fz_subsample_pixblock(state->data, state->w, state->f, state->n, state->l2, state->w * (size_t)state->n); | |
| 571 state->f = 0; | |
| 572 | |
| 573 /* Update data pointers. */ | |
| 574 fill = ((state->w + (1<<state->l2) - 1)>>state->l2) * (size_t)state->n; | |
| 575 stm->pos += fill; | |
| 576 stm->rp = &state->data[0]; | |
| 577 stm->wp = &state->data[fill]; | |
| 578 | |
| 579 return *stm->rp++; | |
| 580 } | |
| 581 | |
| 582 static fz_stream * | |
| 583 subsample_stream(fz_context *ctx, fz_stream *src, int w, int h, int n, int l2extra) | |
| 584 { | |
| 585 l2sub_state *state = fz_malloc(ctx, sizeof(l2sub_state) + w*(size_t)(n<<l2extra)); | |
| 586 | |
| 587 state->src = src; | |
| 588 state->w = w; | |
| 589 state->h = h; | |
| 590 state->n = n; | |
| 591 state->f = 0; | |
| 592 state->r = 0; | |
| 593 state->l2 = l2extra; | |
| 594 | |
| 595 return fz_new_stream(ctx, state, subsample_next, subsample_drop); | |
| 596 } | |
| 597 | |
| 598 /* l2factor is the amount of subsampling that the decoder is going to be | |
| 599 * doing for us already. (So for JPEG 0,1,2,3 corresponding to 1, 2, 4, | |
| 600 * 8. For other formats, probably 0.). l2extra is the additional amount | |
| 601 * of subsampling we should perform here. */ | |
| 602 fz_pixmap * | |
| 603 fz_decomp_image_from_stream(fz_context *ctx, fz_stream *stm, fz_compressed_image *cimg, fz_irect *subarea, int indexed, int l2factor, int *l2extra) | |
| 604 { | |
| 605 fz_image *image = &cimg->super; | |
| 606 fz_pixmap *tile = NULL; | |
| 607 size_t stride, len, i; | |
| 608 unsigned char *samples = NULL; | |
| 609 int f = 1<<l2factor; | |
| 610 int w = image->w; | |
| 611 int h = image->h; | |
| 612 int matte = image->use_colorkey && image->mask; | |
| 613 fz_stream *read_stream = stm; | |
| 614 fz_stream *sstream = NULL; | |
| 615 fz_stream *l2stream = NULL; | |
| 616 fz_stream *unpstream = NULL; | |
| 617 | |
| 618 if (matte) | |
| 619 { | |
| 620 /* Can't do l2factor decoding */ | |
| 621 if (image->w != image->mask->w || image->h != image->mask->h) | |
| 622 { | |
| 623 fz_warn(ctx, "mask must be of same size as image for /Matte"); | |
| 624 matte = 0; | |
| 625 } | |
| 626 assert(l2factor == 0); | |
| 627 } | |
| 628 if (subarea) | |
| 629 { | |
| 630 if (subarea->x0 == 0 && subarea->x1 == image->w && | |
| 631 subarea->y0 == 0 && subarea->y1 == image->h) | |
| 632 subarea = NULL; | |
| 633 else | |
| 634 { | |
| 635 fz_adjust_image_subarea(ctx, image, subarea, l2factor); | |
| 636 w = (subarea->x1 - subarea->x0); | |
| 637 h = (subarea->y1 - subarea->y0); | |
| 638 } | |
| 639 } | |
| 640 w = (w + f - 1) >> l2factor; | |
| 641 h = (h + f - 1) >> l2factor; | |
| 642 | |
| 643 fz_var(tile); | |
| 644 fz_var(samples); | |
| 645 fz_var(sstream); | |
| 646 fz_var(unpstream); | |
| 647 fz_var(l2stream); | |
| 648 | |
| 649 fz_try(ctx) | |
| 650 { | |
| 651 int alpha = (image->colorspace == NULL); | |
| 652 if (image->use_colorkey) | |
| 653 alpha = 1; | |
| 654 | |
| 655 if (subarea) | |
| 656 read_stream = sstream = subarea_stream(ctx, stm, image, subarea, l2factor); | |
| 657 if (image->bpc != 8 || image->use_colorkey) | |
| 658 read_stream = unpstream = fz_unpack_stream(ctx, read_stream, image->bpc, w, h, image->n, indexed, image->use_colorkey, 0); | |
| 659 if (l2extra && *l2extra && !indexed) | |
| 660 { | |
| 661 read_stream = l2stream = subsample_stream(ctx, read_stream, w, h, image->n + image->use_colorkey, *l2extra); | |
| 662 w = (w + (1<<*l2extra) - 1)>>*l2extra; | |
| 663 h = (h + (1<<*l2extra) - 1)>>*l2extra; | |
| 664 *l2extra = 0; | |
| 665 } | |
| 666 | |
| 667 tile = fz_new_pixmap(ctx, image->colorspace, w, h, NULL, alpha); | |
| 668 if (image->interpolate & FZ_PIXMAP_FLAG_INTERPOLATE) | |
| 669 tile->flags |= FZ_PIXMAP_FLAG_INTERPOLATE; | |
| 670 else | |
| 671 tile->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE; | |
| 672 | |
| 673 samples = tile->samples; | |
| 674 stride = tile->stride; | |
| 675 | |
| 676 len = fz_read(ctx, read_stream, samples, h * stride); | |
| 677 | |
| 678 /* Pad truncated images */ | |
| 679 if (len < stride * h) | |
| 680 { | |
| 681 fz_warn(ctx, "padding truncated image"); | |
| 682 memset(samples + len, 0, stride * h - len); | |
| 683 } | |
| 684 | |
| 685 /* Invert 1-bit image masks */ | |
| 686 if (image->imagemask) | |
| 687 { | |
| 688 /* 0=opaque and 1=transparent so we need to invert */ | |
| 689 unsigned char *p = samples; | |
| 690 len = h * stride; | |
| 691 for (i = 0; i < len; i++) | |
| 692 p[i] = ~p[i]; | |
| 693 } | |
| 694 | |
| 695 /* color keyed transparency */ | |
| 696 if (image->use_colorkey && !image->mask) | |
| 697 fz_mask_color_key(ctx, tile, image->n, image->bpc, image->colorkey, indexed); | |
| 698 | |
| 699 if (indexed) | |
| 700 { | |
| 701 fz_pixmap *conv; | |
| 702 fz_decode_indexed_tile(ctx, tile, image->decode, (1 << image->bpc) - 1); | |
| 703 conv = fz_convert_indexed_pixmap_to_base(ctx, tile); | |
| 704 fz_drop_pixmap(ctx, tile); | |
| 705 tile = conv; | |
| 706 } | |
| 707 else if (image->use_decode) | |
| 708 { | |
| 709 fz_decode_tile(ctx, tile, image->decode); | |
| 710 } | |
| 711 | |
| 712 /* pre-blended matte color */ | |
| 713 if (matte) | |
| 714 fz_unblend_masked_tile(ctx, tile, image, subarea); | |
| 715 } | |
| 716 fz_always(ctx) | |
| 717 { | |
| 718 fz_drop_stream(ctx, sstream); | |
| 719 fz_drop_stream(ctx, unpstream); | |
| 720 fz_drop_stream(ctx, l2stream); | |
| 721 } | |
| 722 fz_catch(ctx) | |
| 723 { | |
| 724 fz_drop_pixmap(ctx, tile); | |
| 725 fz_rethrow(ctx); | |
| 726 } | |
| 727 | |
| 728 return tile; | |
| 729 } | |
| 730 | |
| 731 void | |
| 732 fz_drop_image_base(fz_context *ctx, fz_image *image) | |
| 733 { | |
| 734 fz_drop_colorspace(ctx, image->colorspace); | |
| 735 fz_drop_image(ctx, image->mask); | |
| 736 fz_free(ctx, image); | |
| 737 } | |
| 738 | |
| 739 void | |
| 740 fz_drop_image_imp(fz_context *ctx, fz_storable *image_) | |
| 741 { | |
| 742 fz_image *image = (fz_image *)image_; | |
| 743 | |
| 744 image->drop_image(ctx, image); | |
| 745 fz_drop_image_base(ctx, image); | |
| 746 } | |
| 747 | |
| 748 static void | |
| 749 drop_compressed_image(fz_context *ctx, fz_image *image_) | |
| 750 { | |
| 751 fz_compressed_image *image = (fz_compressed_image *)image_; | |
| 752 | |
| 753 fz_drop_compressed_buffer(ctx, image->buffer); | |
| 754 } | |
| 755 | |
| 756 static void | |
| 757 drop_pixmap_image(fz_context *ctx, fz_image *image_) | |
| 758 { | |
| 759 fz_pixmap_image *image = (fz_pixmap_image *)image_; | |
| 760 | |
| 761 fz_drop_pixmap(ctx, image->tile); | |
| 762 } | |
| 763 | |
| 764 int | |
| 765 fz_is_lossy_image(fz_context *ctx, fz_image *image) | |
| 766 { | |
| 767 fz_compressed_buffer *cbuf = fz_compressed_image_buffer(ctx, image); | |
| 768 if (cbuf) | |
| 769 { | |
| 770 switch (cbuf->params.type) | |
| 771 { | |
| 772 case FZ_IMAGE_JPEG: | |
| 773 case FZ_IMAGE_JPX: | |
| 774 case FZ_IMAGE_JXR: | |
| 775 return 1; | |
| 776 } | |
| 777 } | |
| 778 return 0; | |
| 779 } | |
| 780 | |
| 781 static fz_pixmap * | |
| 782 compressed_image_get_pixmap(fz_context *ctx, fz_image *image_, fz_irect *subarea, int w, int h, int *l2factor) | |
| 783 { | |
| 784 fz_compressed_image *image = (fz_compressed_image *)image_; | |
| 785 int native_l2factor; | |
| 786 fz_stream *stm; | |
| 787 int indexed; | |
| 788 fz_pixmap *tile; | |
| 789 int can_sub = 0; | |
| 790 int local_l2factor; | |
| 791 | |
| 792 /* If we are using matte, then the decode code requires both image and tile sizes | |
| 793 * to match. The simplest way to ensure this is to do no native l2factor decoding. | |
| 794 */ | |
| 795 if (image->super.use_colorkey && image->super.mask) | |
| 796 { | |
| 797 local_l2factor = 0; | |
| 798 l2factor = &local_l2factor; | |
| 799 } | |
| 800 | |
| 801 /* We need to make a new one. */ | |
| 802 /* First check for ones that we can't decode using streams */ | |
| 803 switch (image->buffer->params.type) | |
| 804 { | |
| 805 case FZ_IMAGE_PNG: | |
| 806 tile = fz_load_png(ctx, image->buffer->buffer->data, image->buffer->buffer->len); | |
| 807 break; | |
| 808 case FZ_IMAGE_GIF: | |
| 809 tile = fz_load_gif(ctx, image->buffer->buffer->data, image->buffer->buffer->len); | |
| 810 break; | |
| 811 case FZ_IMAGE_BMP: | |
| 812 tile = fz_load_bmp(ctx, image->buffer->buffer->data, image->buffer->buffer->len); | |
| 813 break; | |
| 814 case FZ_IMAGE_TIFF: | |
| 815 tile = fz_load_tiff(ctx, image->buffer->buffer->data, image->buffer->buffer->len); | |
| 816 break; | |
| 817 case FZ_IMAGE_PNM: | |
| 818 tile = fz_load_pnm(ctx, image->buffer->buffer->data, image->buffer->buffer->len); | |
| 819 break; | |
| 820 case FZ_IMAGE_JXR: | |
| 821 tile = fz_load_jxr(ctx, image->buffer->buffer->data, image->buffer->buffer->len); | |
| 822 break; | |
| 823 case FZ_IMAGE_JPX: | |
| 824 tile = fz_load_jpx(ctx, image->buffer->buffer->data, image->buffer->buffer->len, image->super.colorspace); | |
| 825 break; | |
| 826 case FZ_IMAGE_PSD: | |
| 827 tile = fz_load_psd(ctx, image->buffer->buffer->data, image->buffer->buffer->len); | |
| 828 break; | |
| 829 case FZ_IMAGE_JPEG: | |
| 830 /* Scan JPEG stream and patch missing height values in header */ | |
| 831 { | |
| 832 unsigned char *s = image->buffer->buffer->data; | |
| 833 unsigned char *e = s + image->buffer->buffer->len; | |
| 834 unsigned char *d; | |
| 835 for (d = s + 2; s < d && d + 9 < e && d[0] == 0xFF; d += (d[2] << 8 | d[3]) + 2) | |
| 836 { | |
| 837 if (d[1] < 0xC0 || (0xC3 < d[1] && d[1] < 0xC9) || 0xCB < d[1]) | |
| 838 continue; | |
| 839 if ((d[5] == 0 && d[6] == 0) || ((d[5] << 8) | d[6]) > image->super.h) | |
| 840 { | |
| 841 d[5] = (image->super.h >> 8) & 0xFF; | |
| 842 d[6] = image->super.h & 0xFF; | |
| 843 } | |
| 844 } | |
| 845 } | |
| 846 /* fall through */ | |
| 847 | |
| 848 default: | |
| 849 native_l2factor = l2factor ? *l2factor : 0; | |
| 850 stm = fz_open_image_decomp_stream_from_buffer(ctx, image->buffer, l2factor); | |
| 851 fz_try(ctx) | |
| 852 { | |
| 853 if (l2factor) | |
| 854 native_l2factor -= *l2factor; | |
| 855 indexed = fz_colorspace_is_indexed(ctx, image->super.colorspace); | |
| 856 can_sub = 1; | |
| 857 tile = fz_decomp_image_from_stream(ctx, stm, image, subarea, indexed, native_l2factor, l2factor); | |
| 858 } | |
| 859 fz_always(ctx) | |
| 860 fz_drop_stream(ctx, stm); | |
| 861 fz_catch(ctx) | |
| 862 fz_rethrow(ctx); | |
| 863 | |
| 864 break; | |
| 865 } | |
| 866 | |
| 867 if (can_sub == 0 && subarea != NULL) | |
| 868 { | |
| 869 subarea->x0 = 0; | |
| 870 subarea->y0 = 0; | |
| 871 subarea->x1 = image->super.w; | |
| 872 subarea->y1 = image->super.h; | |
| 873 } | |
| 874 | |
| 875 return tile; | |
| 876 } | |
| 877 | |
| 878 static fz_pixmap * | |
| 879 pixmap_image_get_pixmap(fz_context *ctx, fz_image *image_, fz_irect *subarea, int w, int h, int *l2factor) | |
| 880 { | |
| 881 fz_pixmap_image *image = (fz_pixmap_image *)image_; | |
| 882 | |
| 883 /* 'Simple' images created direct from pixmaps will have no buffer | |
| 884 * of compressed data. We cannot do any better than just returning | |
| 885 * a pointer to the original 'tile'. | |
| 886 */ | |
| 887 return fz_keep_pixmap(ctx, image->tile); /* That's all we can give you! */ | |
| 888 } | |
| 889 | |
| 890 static void | |
| 891 update_ctm_for_subarea(fz_matrix *ctm, const fz_irect *subarea, int w, int h) | |
| 892 { | |
| 893 fz_matrix m; | |
| 894 | |
| 895 if (ctm == NULL || (subarea->x0 == 0 && subarea->y0 == 0 && subarea->x1 == w && subarea->y1 == h)) | |
| 896 return; | |
| 897 | |
| 898 m.a = (float) (subarea->x1 - subarea->x0) / w; | |
| 899 m.b = 0; | |
| 900 m.c = 0; | |
| 901 m.d = (float) (subarea->y1 - subarea->y0) / h; | |
| 902 m.e = (float) subarea->x0 / w; | |
| 903 m.f = (float) subarea->y0 / h; | |
| 904 *ctm = fz_concat(m, *ctm); | |
| 905 } | |
| 906 | |
| 907 void fz_default_image_decode(void *arg, int w, int h, int l2factor, fz_irect *subarea) | |
| 908 { | |
| 909 (void)arg; | |
| 910 | |
| 911 if ((subarea->x1-subarea->x0)*(subarea->y1-subarea->y0) >= (w*h/10)*9) | |
| 912 { | |
| 913 /* Either no subarea specified, or a subarea 90% or more of the | |
| 914 * whole area specified. Use the whole image. */ | |
| 915 subarea->x0 = 0; | |
| 916 subarea->y0 = 0; | |
| 917 subarea->x1 = w; | |
| 918 subarea->y1 = h; | |
| 919 } | |
| 920 else | |
| 921 { | |
| 922 /* Clip to the edges if they are within 1% */ | |
| 923 if (subarea->x0 <= w/100) | |
| 924 subarea->x0 = 0; | |
| 925 if (subarea->y0 <= h/100) | |
| 926 subarea->y0 = 0; | |
| 927 if (subarea->x1 >= w*99/100) | |
| 928 subarea->x1 = w; | |
| 929 if (subarea->y1 >= h*99/100) | |
| 930 subarea->y1 = h; | |
| 931 } | |
| 932 } | |
| 933 | |
| 934 static fz_pixmap * | |
| 935 fz_find_image_tile(fz_context *ctx, fz_image *image, fz_image_key *key, fz_matrix *ctm) | |
| 936 { | |
| 937 fz_pixmap *tile; | |
| 938 do | |
| 939 { | |
| 940 tile = fz_find_item(ctx, fz_drop_pixmap_imp, key, &fz_image_store_type); | |
| 941 if (tile) | |
| 942 { | |
| 943 update_ctm_for_subarea(ctm, &key->rect, image->w, image->h); | |
| 944 return tile; | |
| 945 } | |
| 946 key->l2factor--; | |
| 947 } | |
| 948 while (key->l2factor >= 0); | |
| 949 return NULL; | |
| 950 } | |
| 951 | |
| 952 fz_pixmap * | |
| 953 fz_get_pixmap_from_image(fz_context *ctx, fz_image *image, const fz_irect *subarea, fz_matrix *ctm, int *dw, int *dh) | |
| 954 { | |
| 955 fz_pixmap *tile; | |
| 956 int l2factor, l2factor_remaining; | |
| 957 fz_image_key key; | |
| 958 fz_image_key *keyp = NULL; | |
| 959 int w; | |
| 960 int h; | |
| 961 | |
| 962 fz_var(keyp); | |
| 963 | |
| 964 if (!image) | |
| 965 return NULL; | |
| 966 | |
| 967 /* Figure out the extent. */ | |
| 968 if (ctm) | |
| 969 { | |
| 970 w = sqrtf(ctm->a * ctm->a + ctm->b * ctm->b); | |
| 971 h = sqrtf(ctm->c * ctm->c + ctm->d * ctm->d); | |
| 972 } | |
| 973 else | |
| 974 { | |
| 975 w = image->w; | |
| 976 h = image->h; | |
| 977 } | |
| 978 | |
| 979 if (image->scalable) | |
| 980 { | |
| 981 /* If the image is scalable, we always want to re-render and never cache. */ | |
| 982 fz_irect subarea_copy; | |
| 983 if (subarea) | |
| 984 subarea_copy = *subarea; | |
| 985 l2factor_remaining = 0; | |
| 986 if (dw) *dw = w; | |
| 987 if (dh) *dh = h; | |
| 988 return image->get_pixmap(ctx, image, subarea ? &subarea_copy : NULL, image->w, image->h, &l2factor_remaining); | |
| 989 } | |
| 990 | |
| 991 /* Clamp requested image size, since we never want to magnify images here. */ | |
| 992 if (w > image->w) | |
| 993 w = image->w; | |
| 994 if (h > image->h) | |
| 995 h = image->h; | |
| 996 | |
| 997 if (image->decoded) | |
| 998 { | |
| 999 /* If the image is already decoded, then we can't offer a subarea, | |
| 1000 * or l2factor, and we don't want to cache. */ | |
| 1001 l2factor_remaining = 0; | |
| 1002 if (dw) *dw = w; | |
| 1003 if (dh) *dh = h; | |
| 1004 return image->get_pixmap(ctx, image, NULL, image->w, image->h, &l2factor_remaining); | |
| 1005 } | |
| 1006 | |
| 1007 /* What is our ideal factor? We search for the largest factor where | |
| 1008 * we can subdivide and stay larger than the required size. We add | |
| 1009 * a fudge factor of +2 here to allow for the possibility of | |
| 1010 * expansion due to grid fitting. */ | |
| 1011 l2factor = 0; | |
| 1012 if (w > 0 && h > 0) | |
| 1013 { | |
| 1014 while (image->w>>(l2factor+1) >= w+2 && image->h>>(l2factor+1) >= h+2 && l2factor < 6) | |
| 1015 l2factor++; | |
| 1016 } | |
| 1017 | |
| 1018 /* First, look through the store for existing tiles */ | |
| 1019 if (subarea) | |
| 1020 { | |
| 1021 fz_compute_image_key(ctx, image, ctm, &key, subarea, l2factor, &w, &h, dw, dh); | |
| 1022 tile = fz_find_image_tile(ctx, image, &key, ctm); | |
| 1023 if (tile) | |
| 1024 return tile; | |
| 1025 } | |
| 1026 | |
| 1027 /* No subarea given, or no tile for subarea found; try entire image */ | |
| 1028 fz_compute_image_key(ctx, image, ctm, &key, NULL, l2factor, &w, &h, dw, dh); | |
| 1029 tile = fz_find_image_tile(ctx, image, &key, ctm); | |
| 1030 if (tile) | |
| 1031 return tile; | |
| 1032 | |
| 1033 /* Neither subarea nor full image tile found; prepare the subarea key again */ | |
| 1034 if (subarea) | |
| 1035 fz_compute_image_key(ctx, image, ctm, &key, subarea, l2factor, &w, &h, dw, dh); | |
| 1036 | |
| 1037 /* We'll have to decode the image; request the correct amount of downscaling. */ | |
| 1038 l2factor_remaining = l2factor; | |
| 1039 tile = image->get_pixmap(ctx, image, &key.rect, w, h, &l2factor_remaining); | |
| 1040 | |
| 1041 /* Update the ctm to allow for subareas. */ | |
| 1042 update_ctm_for_subarea(ctm, &key.rect, image->w, image->h); | |
| 1043 | |
| 1044 /* l2factor_remaining is updated to the amount of subscaling left to do */ | |
| 1045 assert(l2factor_remaining >= 0 && l2factor_remaining <= 6); | |
| 1046 if (l2factor_remaining) | |
| 1047 { | |
| 1048 fz_try(ctx) | |
| 1049 fz_subsample_pixmap(ctx, tile, l2factor_remaining); | |
| 1050 fz_catch(ctx) | |
| 1051 { | |
| 1052 fz_drop_pixmap(ctx, tile); | |
| 1053 fz_rethrow(ctx); | |
| 1054 } | |
| 1055 } | |
| 1056 | |
| 1057 fz_try(ctx) | |
| 1058 { | |
| 1059 fz_pixmap *existing_tile; | |
| 1060 | |
| 1061 /* Now we try to cache the pixmap. Any failure here will just result | |
| 1062 * in us not caching. */ | |
| 1063 keyp = fz_malloc_struct(ctx, fz_image_key); | |
| 1064 keyp->refs = 1; | |
| 1065 keyp->image = fz_keep_image_store_key(ctx, image); | |
| 1066 keyp->l2factor = l2factor; | |
| 1067 keyp->rect = key.rect; | |
| 1068 | |
| 1069 existing_tile = fz_store_item(ctx, keyp, tile, fz_pixmap_size(ctx, tile), &fz_image_store_type); | |
| 1070 if (existing_tile) | |
| 1071 { | |
| 1072 /* We already have a tile. This must have been produced by a | |
| 1073 * racing thread. We'll throw away ours and use that one. */ | |
| 1074 fz_drop_pixmap(ctx, tile); | |
| 1075 tile = existing_tile; | |
| 1076 } | |
| 1077 } | |
| 1078 fz_always(ctx) | |
| 1079 { | |
| 1080 fz_drop_image_key(ctx, keyp); | |
| 1081 } | |
| 1082 fz_catch(ctx) | |
| 1083 { | |
| 1084 /* Do nothing */ | |
| 1085 fz_rethrow_if(ctx, FZ_ERROR_SYSTEM); | |
| 1086 fz_report_error(ctx); | |
| 1087 } | |
| 1088 | |
| 1089 return tile; | |
| 1090 } | |
| 1091 | |
| 1092 fz_pixmap * | |
| 1093 fz_get_unscaled_pixmap_from_image(fz_context *ctx, fz_image *image) | |
| 1094 { | |
| 1095 return fz_get_pixmap_from_image(ctx, image, NULL /*subarea*/, NULL /*ctm*/, NULL /*dw*/, NULL /*dh*/); | |
| 1096 } | |
| 1097 | |
| 1098 static size_t | |
| 1099 pixmap_image_get_size(fz_context *ctx, fz_image *image) | |
| 1100 { | |
| 1101 fz_pixmap_image *im = (fz_pixmap_image *)image; | |
| 1102 | |
| 1103 if (image == NULL) | |
| 1104 return 0; | |
| 1105 | |
| 1106 return sizeof(fz_pixmap_image) + fz_pixmap_size(ctx, im->tile); | |
| 1107 } | |
| 1108 | |
| 1109 size_t fz_image_size(fz_context *ctx, fz_image *im) | |
| 1110 { | |
| 1111 if (im == NULL) | |
| 1112 return 0; | |
| 1113 | |
| 1114 return im->get_size(ctx, im); | |
| 1115 } | |
| 1116 | |
| 1117 fz_image * | |
| 1118 fz_new_image_from_pixmap(fz_context *ctx, fz_pixmap *pixmap, fz_image *mask) | |
| 1119 { | |
| 1120 fz_pixmap_image *image; | |
| 1121 | |
| 1122 image = fz_new_derived_image(ctx, pixmap->w, pixmap->h, 8, pixmap->colorspace, | |
| 1123 pixmap->xres, pixmap->yres, 0, 0, | |
| 1124 NULL, NULL, mask, fz_pixmap_image, | |
| 1125 pixmap_image_get_pixmap, | |
| 1126 pixmap_image_get_size, | |
| 1127 drop_pixmap_image); | |
| 1128 image->tile = fz_keep_pixmap(ctx, pixmap); | |
| 1129 image->super.decoded = 1; | |
| 1130 | |
| 1131 return &image->super; | |
| 1132 } | |
| 1133 | |
| 1134 fz_image * | |
| 1135 fz_new_image_of_size(fz_context *ctx, int w, int h, int bpc, fz_colorspace *colorspace, | |
| 1136 int xres, int yres, int interpolate, int imagemask, const float *decode, | |
| 1137 const int *colorkey, fz_image *mask, size_t size, | |
| 1138 fz_image_get_pixmap_fn *get_pixmap, | |
| 1139 fz_image_get_size_fn *get_size, | |
| 1140 fz_drop_image_fn *drop) | |
| 1141 { | |
| 1142 fz_image *image; | |
| 1143 int i; | |
| 1144 | |
| 1145 assert(mask == NULL || mask->mask == NULL); | |
| 1146 assert(size >= sizeof(fz_image)); | |
| 1147 | |
| 1148 image = Memento_label(fz_calloc(ctx, 1, size), "fz_image"); | |
| 1149 FZ_INIT_KEY_STORABLE(image, 1, fz_drop_image_imp); | |
| 1150 image->drop_image = drop; | |
| 1151 image->get_pixmap = get_pixmap; | |
| 1152 image->get_size = get_size; | |
| 1153 image->w = w; | |
| 1154 image->h = h; | |
| 1155 image->xres = xres; | |
| 1156 image->yres = yres; | |
| 1157 image->bpc = bpc; | |
| 1158 image->n = (colorspace ? fz_colorspace_n(ctx, colorspace) : 1); | |
| 1159 image->colorspace = fz_keep_colorspace(ctx, colorspace); | |
| 1160 image->interpolate = interpolate; | |
| 1161 image->imagemask = imagemask; | |
| 1162 image->intent = 0; | |
| 1163 image->has_intent = 0; | |
| 1164 image->use_colorkey = (colorkey != NULL); | |
| 1165 if (colorkey) | |
| 1166 memcpy(image->colorkey, colorkey, sizeof(int)*image->n*2); | |
| 1167 image->use_decode = 0; | |
| 1168 if (decode) | |
| 1169 { | |
| 1170 memcpy(image->decode, decode, sizeof(float)*image->n*2); | |
| 1171 } | |
| 1172 else | |
| 1173 { | |
| 1174 float maxval = fz_colorspace_is_indexed(ctx, colorspace) ? (1 << bpc) - 1 : 1; | |
| 1175 for (i = 0; i < image->n; i++) | |
| 1176 { | |
| 1177 image->decode[2*i] = 0; | |
| 1178 image->decode[2*i+1] = maxval; | |
| 1179 } | |
| 1180 } | |
| 1181 /* ICC spaces have the default decode arrays pickled into them. | |
| 1182 * For most spaces this is fine, because [ 0 1 0 1 0 1 ] is | |
| 1183 * idempotent. For Lab, however, we need to adjust it. */ | |
| 1184 if (fz_colorspace_is_lab_icc(ctx, colorspace)) | |
| 1185 { | |
| 1186 /* Undo the default decode array of [0 100 -128 127 -128 127] */ | |
| 1187 image->decode[0] = image->decode[0]/100.0f; | |
| 1188 image->decode[1] = image->decode[1]/100.0f; | |
| 1189 image->decode[2] = (image->decode[2]+128)/255.0f; | |
| 1190 image->decode[3] = (image->decode[3]+128)/255.0f; | |
| 1191 image->decode[4] = (image->decode[4]+128)/255.0f; | |
| 1192 image->decode[5] = (image->decode[5]+128)/255.0f; | |
| 1193 } | |
| 1194 for (i = 0; i < image->n; i++) | |
| 1195 { | |
| 1196 if (image->decode[i * 2] != 0 || image->decode[i * 2 + 1] != 1) | |
| 1197 break; | |
| 1198 } | |
| 1199 if (i != image->n) | |
| 1200 image->use_decode = 1; | |
| 1201 image->mask = fz_keep_image(ctx, mask); | |
| 1202 | |
| 1203 return image; | |
| 1204 } | |
| 1205 | |
| 1206 static size_t | |
| 1207 compressed_image_get_size(fz_context *ctx, fz_image *image) | |
| 1208 { | |
| 1209 fz_compressed_image *im = (fz_compressed_image *)image; | |
| 1210 | |
| 1211 if (image == NULL) | |
| 1212 return 0; | |
| 1213 | |
| 1214 return sizeof(fz_pixmap_image) + (im->buffer && im->buffer->buffer ? im->buffer->buffer->cap : 0); | |
| 1215 } | |
| 1216 | |
| 1217 fz_image * | |
| 1218 fz_new_image_from_compressed_buffer(fz_context *ctx, int w, int h, | |
| 1219 int bpc, fz_colorspace *colorspace, | |
| 1220 int xres, int yres, int interpolate, int imagemask, const float *decode, | |
| 1221 const int *colorkey, fz_compressed_buffer *buffer, fz_image *mask) | |
| 1222 { | |
| 1223 fz_compressed_image *image; | |
| 1224 | |
| 1225 fz_try(ctx) | |
| 1226 { | |
| 1227 image = fz_new_derived_image(ctx, w, h, bpc, | |
| 1228 colorspace, xres, yres, | |
| 1229 interpolate, imagemask, decode, | |
| 1230 colorkey, mask, fz_compressed_image, | |
| 1231 compressed_image_get_pixmap, | |
| 1232 compressed_image_get_size, | |
| 1233 drop_compressed_image); | |
| 1234 image->buffer = buffer; | |
| 1235 } | |
| 1236 fz_catch(ctx) | |
| 1237 { | |
| 1238 fz_drop_compressed_buffer(ctx, buffer); | |
| 1239 fz_rethrow(ctx); | |
| 1240 } | |
| 1241 | |
| 1242 return &image->super; | |
| 1243 } | |
| 1244 | |
| 1245 fz_compressed_buffer *fz_compressed_image_buffer(fz_context *ctx, fz_image *image) | |
| 1246 { | |
| 1247 if (image == NULL || image->get_pixmap != compressed_image_get_pixmap) | |
| 1248 return NULL; | |
| 1249 return ((fz_compressed_image *)image)->buffer; | |
| 1250 } | |
| 1251 | |
| 1252 void fz_set_compressed_image_buffer(fz_context *ctx, fz_compressed_image *image, fz_compressed_buffer *buf) | |
| 1253 { | |
| 1254 assert(image != NULL && image->super.get_pixmap == compressed_image_get_pixmap); | |
| 1255 ((fz_compressed_image *)image)->buffer = buf; /* Note: compressed buffers are not reference counted */ | |
| 1256 } | |
| 1257 | |
| 1258 fz_pixmap *fz_pixmap_image_tile(fz_context *ctx, fz_pixmap_image *image) | |
| 1259 { | |
| 1260 if (image == NULL || image->super.get_pixmap != pixmap_image_get_pixmap) | |
| 1261 return NULL; | |
| 1262 return ((fz_pixmap_image *)image)->tile; | |
| 1263 } | |
| 1264 | |
| 1265 void fz_set_pixmap_image_tile(fz_context *ctx, fz_pixmap_image *image, fz_pixmap *pix) | |
| 1266 { | |
| 1267 assert(image != NULL && image->super.get_pixmap == pixmap_image_get_pixmap); | |
| 1268 ((fz_pixmap_image *)image)->tile = pix; | |
| 1269 } | |
| 1270 | |
| 1271 const char * | |
| 1272 fz_image_type_name(int type) | |
| 1273 { | |
| 1274 switch (type) | |
| 1275 { | |
| 1276 default: | |
| 1277 case FZ_IMAGE_UNKNOWN: return "unknown"; | |
| 1278 case FZ_IMAGE_RAW: return "raw"; | |
| 1279 case FZ_IMAGE_FAX: return "fax"; | |
| 1280 case FZ_IMAGE_FLATE: return "flate"; | |
| 1281 case FZ_IMAGE_LZW: return "lzw"; | |
| 1282 case FZ_IMAGE_RLD: return "rld"; | |
| 1283 case FZ_IMAGE_BROTLI: return "brotli"; | |
| 1284 case FZ_IMAGE_BMP: return "bmp"; | |
| 1285 case FZ_IMAGE_GIF: return "gif"; | |
| 1286 case FZ_IMAGE_JBIG2: return "jbig2"; | |
| 1287 case FZ_IMAGE_JPEG: return "jpeg"; | |
| 1288 case FZ_IMAGE_JPX: return "jpx"; | |
| 1289 case FZ_IMAGE_JXR: return "jxr"; | |
| 1290 case FZ_IMAGE_PNG: return "png"; | |
| 1291 case FZ_IMAGE_PNM: return "pnm"; | |
| 1292 case FZ_IMAGE_TIFF: return "tiff"; | |
| 1293 } | |
| 1294 } | |
| 1295 | |
| 1296 int | |
| 1297 fz_lookup_image_type(const char *type) | |
| 1298 { | |
| 1299 if (type == NULL) return FZ_IMAGE_UNKNOWN; | |
| 1300 if (!strcmp(type, "raw")) return FZ_IMAGE_RAW; | |
| 1301 if (!strcmp(type, "fax")) return FZ_IMAGE_FAX; | |
| 1302 if (!strcmp(type, "flate")) return FZ_IMAGE_FLATE; | |
| 1303 if (!strcmp(type, "lzw")) return FZ_IMAGE_LZW; | |
| 1304 if (!strcmp(type, "rld")) return FZ_IMAGE_RLD; | |
| 1305 if (!strcmp(type, "brotli")) return FZ_IMAGE_BROTLI; | |
| 1306 if (!strcmp(type, "bmp")) return FZ_IMAGE_BMP; | |
| 1307 if (!strcmp(type, "gif")) return FZ_IMAGE_GIF; | |
| 1308 if (!strcmp(type, "jbig2")) return FZ_IMAGE_JBIG2; | |
| 1309 if (!strcmp(type, "jpeg")) return FZ_IMAGE_JPEG; | |
| 1310 if (!strcmp(type, "jpx")) return FZ_IMAGE_JPX; | |
| 1311 if (!strcmp(type, "jxr")) return FZ_IMAGE_JXR; | |
| 1312 if (!strcmp(type, "png")) return FZ_IMAGE_PNG; | |
| 1313 if (!strcmp(type, "pnm")) return FZ_IMAGE_PNM; | |
| 1314 if (!strcmp(type, "tiff")) return FZ_IMAGE_TIFF; | |
| 1315 return FZ_IMAGE_UNKNOWN; | |
| 1316 } | |
| 1317 | |
| 1318 int | |
| 1319 fz_recognize_image_format(fz_context *ctx, unsigned char p[8]) | |
| 1320 { | |
| 1321 if (p[0] == 'P' && p[1] >= '1' && p[1] <= '7') | |
| 1322 return FZ_IMAGE_PNM; | |
| 1323 if (p[0] == 'P' && (p[1] == 'F' || p[1] == 'f')) | |
| 1324 return FZ_IMAGE_PNM; | |
| 1325 if (p[0] == 0xff && p[1] == 0x4f) | |
| 1326 return FZ_IMAGE_JPX; | |
| 1327 if (p[0] == 0x00 && p[1] == 0x00 && p[2] == 0x00 && p[3] == 0x0c && | |
| 1328 p[4] == 0x6a && p[5] == 0x50 && p[6] == 0x20 && p[7] == 0x20) | |
| 1329 return FZ_IMAGE_JPX; | |
| 1330 if (p[0] == 0xff && p[1] == 0xd8) | |
| 1331 return FZ_IMAGE_JPEG; | |
| 1332 if (p[0] == 137 && p[1] == 80 && p[2] == 78 && p[3] == 71 && | |
| 1333 p[4] == 13 && p[5] == 10 && p[6] == 26 && p[7] == 10) | |
| 1334 return FZ_IMAGE_PNG; | |
| 1335 if (p[0] == 'I' && p[1] == 'I' && p[2] == 0xBC) | |
| 1336 return FZ_IMAGE_JXR; | |
| 1337 if (p[0] == 'I' && p[1] == 'I' && p[2] == 42 && p[3] == 0) | |
| 1338 return FZ_IMAGE_TIFF; | |
| 1339 if (p[0] == 'M' && p[1] == 'M' && p[2] == 0 && p[3] == 42) | |
| 1340 return FZ_IMAGE_TIFF; | |
| 1341 if (p[0] == 'G' && p[1] == 'I' && p[2] == 'F') | |
| 1342 return FZ_IMAGE_GIF; | |
| 1343 if (p[0] == 'B' && p[1] == 'M') | |
| 1344 return FZ_IMAGE_BMP; | |
| 1345 if (p[0] == 'B' && p[1] == 'A') | |
| 1346 return FZ_IMAGE_BMP; | |
| 1347 if (p[0] == 0x97 && p[1] == 'J' && p[2] == 'B' && p[3] == '2' && | |
| 1348 p[4] == '\r' && p[5] == '\n' && p[6] == 0x1a && p[7] == '\n') | |
| 1349 return FZ_IMAGE_JBIG2; | |
| 1350 if (p[0] == '8' && p[1] == 'B' && p[2] == 'P' && p[3] == 'S') | |
| 1351 return FZ_IMAGE_PSD; | |
| 1352 return FZ_IMAGE_UNKNOWN; | |
| 1353 } | |
| 1354 | |
| 1355 fz_image * | |
| 1356 fz_new_image_from_buffer(fz_context *ctx, fz_buffer *buffer) | |
| 1357 { | |
| 1358 fz_compressed_buffer *bc; | |
| 1359 int w, h, xres, yres; | |
| 1360 fz_colorspace *cspace; | |
| 1361 size_t len = buffer->len; | |
| 1362 unsigned char *buf = buffer->data; | |
| 1363 fz_image *image = NULL; | |
| 1364 int type; | |
| 1365 int bpc; | |
| 1366 uint8_t orientation = 0; | |
| 1367 | |
| 1368 if (len < 8) | |
| 1369 fz_throw(ctx, FZ_ERROR_FORMAT, "unknown image file format"); | |
| 1370 | |
| 1371 type = fz_recognize_image_format(ctx, buf); | |
| 1372 bpc = 8; | |
| 1373 switch (type) | |
| 1374 { | |
| 1375 case FZ_IMAGE_PNM: | |
| 1376 fz_load_pnm_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace); | |
| 1377 break; | |
| 1378 case FZ_IMAGE_JPX: | |
| 1379 fz_load_jpx_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace); | |
| 1380 break; | |
| 1381 case FZ_IMAGE_JPEG: | |
| 1382 fz_load_jpeg_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace, &orientation); | |
| 1383 break; | |
| 1384 case FZ_IMAGE_PNG: | |
| 1385 fz_load_png_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace); | |
| 1386 break; | |
| 1387 case FZ_IMAGE_PSD: | |
| 1388 fz_load_psd_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace); | |
| 1389 break; | |
| 1390 case FZ_IMAGE_JXR: | |
| 1391 fz_load_jxr_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace); | |
| 1392 break; | |
| 1393 case FZ_IMAGE_TIFF: | |
| 1394 fz_load_tiff_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace); | |
| 1395 break; | |
| 1396 case FZ_IMAGE_GIF: | |
| 1397 fz_load_gif_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace); | |
| 1398 break; | |
| 1399 case FZ_IMAGE_BMP: | |
| 1400 fz_load_bmp_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace); | |
| 1401 break; | |
| 1402 case FZ_IMAGE_JBIG2: | |
| 1403 fz_load_jbig2_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace); | |
| 1404 bpc = 1; | |
| 1405 break; | |
| 1406 default: | |
| 1407 fz_throw(ctx, FZ_ERROR_FORMAT, "unknown image file format"); | |
| 1408 } | |
| 1409 | |
| 1410 fz_try(ctx) | |
| 1411 { | |
| 1412 bc = fz_new_compressed_buffer(ctx); | |
| 1413 bc->buffer = fz_keep_buffer(ctx, buffer); | |
| 1414 bc->params.type = type; | |
| 1415 if (type == FZ_IMAGE_JPEG) | |
| 1416 { | |
| 1417 bc->params.u.jpeg.color_transform = -1; | |
| 1418 bc->params.u.jpeg.invert_cmyk = 1; | |
| 1419 } | |
| 1420 image = fz_new_image_from_compressed_buffer(ctx, w, h, bpc, cspace, xres, yres, 0, 0, NULL, NULL, bc, NULL); | |
| 1421 image->orientation = orientation; | |
| 1422 } | |
| 1423 fz_always(ctx) | |
| 1424 fz_drop_colorspace(ctx, cspace); | |
| 1425 fz_catch(ctx) | |
| 1426 fz_rethrow(ctx); | |
| 1427 | |
| 1428 return image; | |
| 1429 } | |
| 1430 | |
| 1431 int | |
| 1432 fz_compressed_image_type(fz_context *ctx, fz_image *image) | |
| 1433 { | |
| 1434 fz_compressed_image *cim; | |
| 1435 | |
| 1436 if (image == NULL || image->drop_image != drop_compressed_image) | |
| 1437 return FZ_IMAGE_UNKNOWN; | |
| 1438 | |
| 1439 cim = (fz_compressed_image *)image; | |
| 1440 | |
| 1441 return cim->buffer->params.type; | |
| 1442 } | |
| 1443 | |
| 1444 fz_image * | |
| 1445 fz_new_image_from_file(fz_context *ctx, const char *path) | |
| 1446 { | |
| 1447 fz_buffer *buffer; | |
| 1448 fz_image *image = NULL; | |
| 1449 | |
| 1450 buffer = fz_read_file(ctx, path); | |
| 1451 fz_try(ctx) | |
| 1452 image = fz_new_image_from_buffer(ctx, buffer); | |
| 1453 fz_always(ctx) | |
| 1454 fz_drop_buffer(ctx, buffer); | |
| 1455 fz_catch(ctx) | |
| 1456 fz_rethrow(ctx); | |
| 1457 | |
| 1458 return image; | |
| 1459 } | |
| 1460 | |
| 1461 void | |
| 1462 fz_image_resolution(fz_image *image, int *xres, int *yres) | |
| 1463 { | |
| 1464 *xres = image->xres; | |
| 1465 *yres = image->yres; | |
| 1466 if (*xres < 0 || *yres < 0 || (*xres == 0 && *yres == 0)) | |
| 1467 { | |
| 1468 /* If neither xres or yres is sane, pick a sane value */ | |
| 1469 *xres = SANE_DPI; *yres = SANE_DPI; | |
| 1470 } | |
| 1471 else if (*xres == 0) | |
| 1472 { | |
| 1473 *xres = *yres; | |
| 1474 } | |
| 1475 else if (*yres == 0) | |
| 1476 { | |
| 1477 *yres = *xres; | |
| 1478 } | |
| 1479 | |
| 1480 /* Scale xres and yres up until we get believable values */ | |
| 1481 if (*xres < SANE_DPI || *yres < SANE_DPI || *xres > INSANE_DPI || *yres > INSANE_DPI) | |
| 1482 { | |
| 1483 if (*xres < *yres) | |
| 1484 { | |
| 1485 *yres = *yres * SANE_DPI / *xres; | |
| 1486 *xres = SANE_DPI; | |
| 1487 } | |
| 1488 else | |
| 1489 { | |
| 1490 *xres = *xres * SANE_DPI / *yres; | |
| 1491 *yres = SANE_DPI; | |
| 1492 } | |
| 1493 | |
| 1494 if (*xres == *yres || *xres < SANE_DPI || *yres < SANE_DPI || *xres > INSANE_DPI || *yres > INSANE_DPI) | |
| 1495 { | |
| 1496 *xres = SANE_DPI; | |
| 1497 *yres = SANE_DPI; | |
| 1498 } | |
| 1499 } | |
| 1500 } | |
| 1501 | |
| 1502 uint8_t fz_image_orientation(fz_context *ctx, fz_image *image) | |
| 1503 { | |
| 1504 return image ? image->orientation : 0; | |
| 1505 } | |
| 1506 | |
| 1507 fz_matrix fz_image_orientation_matrix(fz_context *ctx, fz_image *image) | |
| 1508 { | |
| 1509 fz_matrix m; | |
| 1510 | |
| 1511 switch (image ? image->orientation : 0) | |
| 1512 { | |
| 1513 case 0: | |
| 1514 case 1: /* 0 degree rotation */ | |
| 1515 m.a = 1; m.b = 0; | |
| 1516 m.c = 0; m.d = 1; | |
| 1517 m.e = 0; m.f = 0; | |
| 1518 break; | |
| 1519 case 2: /* 90 degree ccw */ | |
| 1520 m.a = 0; m.b = -1; | |
| 1521 m.c = 1; m.d = 0; | |
| 1522 m.e = 0; m.f = 1; | |
| 1523 break; | |
| 1524 case 3: /* 180 degree ccw */ | |
| 1525 m.a = -1; m.b = 0; | |
| 1526 m.c = 0; m.d = -1; | |
| 1527 m.e = 1; m.f = 1; | |
| 1528 break; | |
| 1529 case 4: /* 270 degree ccw */ | |
| 1530 m.a = 0; m.b = 1; | |
| 1531 m.c = -1; m.d = 0; | |
| 1532 m.e = 1; m.f = 0; | |
| 1533 break; | |
| 1534 case 5: /* flip on X */ | |
| 1535 m.a = -1; m.b = 0; | |
| 1536 m.c = 0; m.d = 1; | |
| 1537 m.e = 1; m.f = 0; | |
| 1538 break; | |
| 1539 case 6: /* flip on X, then rotate ccw by 90 degrees */ | |
| 1540 m.a = 0; m.b = 1; | |
| 1541 m.c = 1; m.d = 0; | |
| 1542 m.e = 0; m.f = 0; | |
| 1543 break; | |
| 1544 case 7: /* flip on X, then rotate ccw by 180 degrees */ | |
| 1545 m.a = 1; m.b = 0; | |
| 1546 m.c = 0; m.d = -1; | |
| 1547 m.e = 0; m.f = 1; | |
| 1548 break; | |
| 1549 case 8: /* flip on X, then rotate ccw by 270 degrees */ | |
| 1550 m.a = 0; m.b = -1; | |
| 1551 m.c = -1; m.d = 0; | |
| 1552 m.e = 1; m.f = 1; | |
| 1553 break; | |
| 1554 } | |
| 1555 | |
| 1556 return m; | |
| 1557 } | |
| 1558 | |
| 1559 typedef struct fz_display_list_image_s | |
| 1560 { | |
| 1561 fz_image super; | |
| 1562 fz_matrix transform; | |
| 1563 fz_display_list *list; | |
| 1564 } fz_display_list_image; | |
| 1565 | |
| 1566 static fz_pixmap * | |
| 1567 display_list_image_get_pixmap(fz_context *ctx, fz_image *image_, fz_irect *subarea, int w, int h, int *l2factor) | |
| 1568 { | |
| 1569 fz_display_list_image *image = (fz_display_list_image *)image_; | |
| 1570 fz_matrix ctm; | |
| 1571 fz_device *dev; | |
| 1572 fz_pixmap *pix; | |
| 1573 | |
| 1574 fz_var(dev); | |
| 1575 | |
| 1576 if (subarea) | |
| 1577 { | |
| 1578 /* So, the whole image should be scaled to w * h, but we only want the | |
| 1579 * given subarea of it. */ | |
| 1580 int l = (subarea->x0 * w) / image->super.w; | |
| 1581 int t = (subarea->y0 * h) / image->super.h; | |
| 1582 int r = (subarea->x1 * w + image->super.w - 1) / image->super.w; | |
| 1583 int b = (subarea->y1 * h + image->super.h - 1) / image->super.h; | |
| 1584 | |
| 1585 pix = fz_new_pixmap(ctx, image->super.colorspace, r-l, b-t, NULL, 0); | |
| 1586 pix->x = l; | |
| 1587 pix->y = t; | |
| 1588 } | |
| 1589 else | |
| 1590 { | |
| 1591 pix = fz_new_pixmap(ctx, image->super.colorspace, w, h, NULL, 0); | |
| 1592 } | |
| 1593 | |
| 1594 /* If we render the display list into pix with the image matrix, we'll get a unit | |
| 1595 * square result. Therefore scale by w, h. */ | |
| 1596 ctm = fz_pre_scale(image->transform, w, h); | |
| 1597 | |
| 1598 fz_clear_pixmap(ctx, pix); /* clear to transparent */ | |
| 1599 fz_try(ctx) | |
| 1600 { | |
| 1601 dev = fz_new_draw_device(ctx, ctm, pix); | |
| 1602 fz_run_display_list(ctx, image->list, dev, fz_identity, fz_infinite_rect, NULL); | |
| 1603 fz_close_device(ctx, dev); | |
| 1604 } | |
| 1605 fz_always(ctx) | |
| 1606 fz_drop_device(ctx, dev); | |
| 1607 fz_catch(ctx) | |
| 1608 { | |
| 1609 fz_drop_pixmap(ctx, pix); | |
| 1610 fz_rethrow(ctx); | |
| 1611 } | |
| 1612 | |
| 1613 /* Never do more subsampling, cos we've already given them the right size */ | |
| 1614 if (l2factor) | |
| 1615 *l2factor = 0; | |
| 1616 | |
| 1617 return pix; | |
| 1618 } | |
| 1619 | |
| 1620 static void drop_display_list_image(fz_context *ctx, fz_image *image_) | |
| 1621 { | |
| 1622 fz_display_list_image *image = (fz_display_list_image *)image_; | |
| 1623 | |
| 1624 if (image == NULL) | |
| 1625 return; | |
| 1626 fz_drop_display_list(ctx, image->list); | |
| 1627 } | |
| 1628 | |
| 1629 static size_t | |
| 1630 display_list_image_get_size(fz_context *ctx, fz_image *image_) | |
| 1631 { | |
| 1632 fz_display_list_image *image = (fz_display_list_image *)image_; | |
| 1633 | |
| 1634 if (image == NULL) | |
| 1635 return 0; | |
| 1636 | |
| 1637 return sizeof(fz_display_list_image) + 4096; /* FIXME */ | |
| 1638 } | |
| 1639 | |
| 1640 fz_image *fz_new_image_from_display_list(fz_context *ctx, float w, float h, fz_display_list *list) | |
| 1641 { | |
| 1642 fz_display_list_image *image; | |
| 1643 int iw, ih; | |
| 1644 | |
| 1645 iw = w * SCALABLE_IMAGE_DPI / 72; | |
| 1646 ih = h * SCALABLE_IMAGE_DPI / 72; | |
| 1647 | |
| 1648 image = fz_new_derived_image(ctx, iw, ih, 8, fz_device_rgb(ctx), | |
| 1649 SCALABLE_IMAGE_DPI, SCALABLE_IMAGE_DPI, 0, 0, | |
| 1650 NULL, NULL, NULL, fz_display_list_image, | |
| 1651 display_list_image_get_pixmap, | |
| 1652 display_list_image_get_size, | |
| 1653 drop_display_list_image); | |
| 1654 image->super.scalable = 1; | |
| 1655 image->transform = fz_scale(1 / w, 1 / h); | |
| 1656 image->list = fz_keep_display_list(ctx, list); | |
| 1657 | |
| 1658 return &image->super; | |
| 1659 } |
