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