Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/source/fitz/pixmap.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 "color-imp.h" | |
| 26 #include "pixmap-imp.h" | |
| 27 | |
| 28 #include <assert.h> | |
| 29 #include <limits.h> | |
| 30 #include <string.h> | |
| 31 #include <math.h> | |
| 32 #include <float.h> | |
| 33 | |
| 34 fz_pixmap * | |
| 35 fz_keep_pixmap(fz_context *ctx, fz_pixmap *pix) | |
| 36 { | |
| 37 return fz_keep_storable(ctx, &pix->storable); | |
| 38 } | |
| 39 | |
| 40 void | |
| 41 fz_drop_pixmap(fz_context *ctx, fz_pixmap *pix) | |
| 42 { | |
| 43 fz_drop_storable(ctx, &pix->storable); | |
| 44 } | |
| 45 | |
| 46 void | |
| 47 fz_drop_pixmap_imp(fz_context *ctx, fz_storable *pix_) | |
| 48 { | |
| 49 fz_pixmap *pix = (fz_pixmap *)pix_; | |
| 50 | |
| 51 fz_drop_colorspace(ctx, pix->colorspace); | |
| 52 fz_drop_separations(ctx, pix->seps); | |
| 53 if (pix->flags & FZ_PIXMAP_FLAG_FREE_SAMPLES) | |
| 54 fz_free(ctx, pix->samples); | |
| 55 fz_drop_pixmap(ctx, pix->underlying); | |
| 56 fz_free(ctx, pix); | |
| 57 } | |
| 58 | |
| 59 fz_pixmap * | |
| 60 fz_new_pixmap_with_data(fz_context *ctx, fz_colorspace *colorspace, int w, int h, fz_separations *seps, int alpha, int stride, unsigned char *samples) | |
| 61 { | |
| 62 fz_pixmap *pix; | |
| 63 int s = fz_count_active_separations(ctx, seps); | |
| 64 int n; | |
| 65 | |
| 66 if (w < 0 || h < 0) | |
| 67 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Illegal dimensions for pixmap %d %d", w, h); | |
| 68 | |
| 69 n = alpha + s + fz_colorspace_n(ctx, colorspace); | |
| 70 if (stride < n*w && stride > -n*w) | |
| 71 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Illegal stride for pixmap (n=%d w=%d, stride=%d)", n, w, stride); | |
| 72 if (samples == NULL && stride < n*w) | |
| 73 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Illegal -ve stride for pixmap without data"); | |
| 74 if (n > FZ_MAX_COLORS) | |
| 75 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Illegal number of colorants"); | |
| 76 | |
| 77 pix = fz_malloc_struct(ctx, fz_pixmap); | |
| 78 FZ_INIT_STORABLE(pix, 1, fz_drop_pixmap_imp); | |
| 79 pix->x = 0; | |
| 80 pix->y = 0; | |
| 81 pix->w = w; | |
| 82 pix->h = h; | |
| 83 pix->alpha = alpha = !!alpha; | |
| 84 pix->flags = FZ_PIXMAP_FLAG_INTERPOLATE; | |
| 85 pix->xres = 96; | |
| 86 pix->yres = 96; | |
| 87 pix->colorspace = NULL; | |
| 88 pix->n = n; | |
| 89 pix->s = s; | |
| 90 pix->seps = fz_keep_separations(ctx, seps); | |
| 91 pix->stride = stride; | |
| 92 | |
| 93 if (colorspace) | |
| 94 { | |
| 95 pix->colorspace = fz_keep_colorspace(ctx, colorspace); | |
| 96 } | |
| 97 else | |
| 98 { | |
| 99 assert(alpha || s); | |
| 100 } | |
| 101 | |
| 102 pix->samples = samples; | |
| 103 if (!samples && pix->h > 0 && pix->w > 0) | |
| 104 { | |
| 105 fz_try(ctx) | |
| 106 { | |
| 107 if ((size_t)pix->stride > SIZE_MAX / (size_t)pix->h) | |
| 108 fz_throw(ctx, FZ_ERROR_LIMIT, "Overly large image"); | |
| 109 pix->samples = Memento_label(fz_malloc(ctx, pix->h * pix->stride), "pixmap_data"); | |
| 110 } | |
| 111 fz_catch(ctx) | |
| 112 { | |
| 113 fz_drop_separations(ctx, pix->seps); | |
| 114 fz_drop_colorspace(ctx, pix->colorspace); | |
| 115 fz_free(ctx, pix); | |
| 116 fz_rethrow(ctx); | |
| 117 } | |
| 118 pix->flags |= FZ_PIXMAP_FLAG_FREE_SAMPLES; | |
| 119 } | |
| 120 | |
| 121 return pix; | |
| 122 } | |
| 123 | |
| 124 fz_pixmap * | |
| 125 fz_new_pixmap(fz_context *ctx, fz_colorspace *colorspace, int w, int h, fz_separations *seps, int alpha) | |
| 126 { | |
| 127 int stride; | |
| 128 int s = fz_count_active_separations(ctx, seps); | |
| 129 int n; | |
| 130 if (!colorspace && s == 0) alpha = 1; | |
| 131 n = fz_colorspace_n(ctx, colorspace) + s + alpha; | |
| 132 if (w > INT_MAX / n) | |
| 133 fz_throw(ctx, FZ_ERROR_LIMIT, "Overly wide image"); | |
| 134 stride = n * w; | |
| 135 return fz_new_pixmap_with_data(ctx, colorspace, w, h, seps, alpha, stride, NULL); | |
| 136 } | |
| 137 | |
| 138 fz_pixmap * | |
| 139 fz_new_pixmap_with_bbox(fz_context *ctx, fz_colorspace *colorspace, fz_irect bbox, fz_separations *seps, int alpha) | |
| 140 { | |
| 141 fz_pixmap *pixmap; | |
| 142 pixmap = fz_new_pixmap(ctx, colorspace, fz_irect_width(bbox), fz_irect_height(bbox), seps, alpha); | |
| 143 pixmap->x = bbox.x0; | |
| 144 pixmap->y = bbox.y0; | |
| 145 return pixmap; | |
| 146 } | |
| 147 | |
| 148 fz_pixmap * | |
| 149 fz_new_pixmap_with_bbox_and_data(fz_context *ctx, fz_colorspace *colorspace, fz_irect bbox, fz_separations *seps, int alpha, unsigned char *samples) | |
| 150 { | |
| 151 int w = fz_irect_width(bbox); | |
| 152 int stride; | |
| 153 int s = fz_count_active_separations(ctx, seps); | |
| 154 fz_pixmap *pixmap; | |
| 155 if (!colorspace && s == 0) alpha = 1; | |
| 156 stride = (fz_colorspace_n(ctx, colorspace) + s + alpha) * w; | |
| 157 pixmap = fz_new_pixmap_with_data(ctx, colorspace, w, fz_irect_height(bbox), seps, alpha, stride, samples); | |
| 158 pixmap->x = bbox.x0; | |
| 159 pixmap->y = bbox.y0; | |
| 160 return pixmap; | |
| 161 } | |
| 162 | |
| 163 fz_pixmap *fz_new_pixmap_from_pixmap(fz_context *ctx, fz_pixmap *pixmap, const fz_irect *rect) | |
| 164 { | |
| 165 fz_irect local_rect; | |
| 166 fz_pixmap *subpix; | |
| 167 | |
| 168 if (!pixmap) | |
| 169 return NULL; | |
| 170 | |
| 171 if (rect == NULL) | |
| 172 { | |
| 173 rect = &local_rect; | |
| 174 local_rect.x0 = pixmap->x; | |
| 175 local_rect.y0 = pixmap->y; | |
| 176 local_rect.x1 = pixmap->x + pixmap->w; | |
| 177 local_rect.y1 = pixmap->y + pixmap->h; | |
| 178 } | |
| 179 else if (rect->x0 < pixmap->x || rect->y0 < pixmap->y || rect->x1 > pixmap->x + pixmap->w || rect->y1 > pixmap->y + pixmap->h) | |
| 180 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Pixmap region is not a subarea"); | |
| 181 | |
| 182 subpix = fz_malloc_struct(ctx, fz_pixmap); | |
| 183 *subpix = *pixmap; | |
| 184 subpix->storable.refs = 1; | |
| 185 subpix->x = rect->x0; | |
| 186 subpix->y = rect->y0; | |
| 187 subpix->w = fz_irect_width(*rect); | |
| 188 subpix->h = fz_irect_height(*rect); | |
| 189 subpix->samples += (rect->x0 - pixmap->x) + (rect->y0 - pixmap->y) * pixmap->stride; | |
| 190 subpix->underlying = fz_keep_pixmap(ctx, pixmap); | |
| 191 subpix->colorspace = fz_keep_colorspace(ctx, pixmap->colorspace); | |
| 192 subpix->seps = fz_keep_separations(ctx, pixmap->seps); | |
| 193 subpix->flags &= ~FZ_PIXMAP_FLAG_FREE_SAMPLES; | |
| 194 | |
| 195 return subpix; | |
| 196 } | |
| 197 | |
| 198 fz_pixmap *fz_clone_pixmap(fz_context *ctx, const fz_pixmap *old) | |
| 199 { | |
| 200 fz_pixmap *pix = fz_new_pixmap_with_bbox(ctx, old->colorspace, fz_make_irect(old->x, old->y, old->w, old->h), old->seps, old->alpha); | |
| 201 memcpy(pix->samples, old->samples, pix->stride * pix->h); | |
| 202 return pix; | |
| 203 } | |
| 204 | |
| 205 fz_irect | |
| 206 fz_pixmap_bbox(fz_context *ctx, const fz_pixmap *pix) | |
| 207 { | |
| 208 fz_irect bbox; | |
| 209 bbox.x0 = pix->x; | |
| 210 bbox.y0 = pix->y; | |
| 211 bbox.x1 = pix->x + pix->w; | |
| 212 bbox.y1 = pix->y + pix->h; | |
| 213 return bbox; | |
| 214 } | |
| 215 | |
| 216 fz_irect | |
| 217 fz_pixmap_bbox_no_ctx(const fz_pixmap *pix) | |
| 218 { | |
| 219 fz_irect bbox; | |
| 220 bbox.x0 = pix->x; | |
| 221 bbox.y0 = pix->y; | |
| 222 bbox.x1 = pix->x + pix->w; | |
| 223 bbox.y1 = pix->y + pix->h; | |
| 224 return bbox; | |
| 225 } | |
| 226 | |
| 227 fz_colorspace * | |
| 228 fz_pixmap_colorspace(fz_context *ctx, const fz_pixmap *pix) | |
| 229 { | |
| 230 if (!pix) | |
| 231 return NULL; | |
| 232 return pix->colorspace; | |
| 233 } | |
| 234 | |
| 235 int | |
| 236 fz_pixmap_x(fz_context *ctx, const fz_pixmap *pix) | |
| 237 { | |
| 238 return pix->x; | |
| 239 } | |
| 240 | |
| 241 int | |
| 242 fz_pixmap_y(fz_context *ctx, const fz_pixmap *pix) | |
| 243 { | |
| 244 return pix->y; | |
| 245 } | |
| 246 | |
| 247 int | |
| 248 fz_pixmap_width(fz_context *ctx, const fz_pixmap *pix) | |
| 249 { | |
| 250 return pix->w; | |
| 251 } | |
| 252 | |
| 253 int | |
| 254 fz_pixmap_height(fz_context *ctx, const fz_pixmap *pix) | |
| 255 { | |
| 256 return pix->h; | |
| 257 } | |
| 258 | |
| 259 int | |
| 260 fz_pixmap_components(fz_context *ctx, const fz_pixmap *pix) | |
| 261 { | |
| 262 return pix->n; | |
| 263 } | |
| 264 | |
| 265 int | |
| 266 fz_pixmap_colorants(fz_context *ctx, const fz_pixmap *pix) | |
| 267 { | |
| 268 return pix->n - pix->alpha - pix->s; | |
| 269 } | |
| 270 | |
| 271 int | |
| 272 fz_pixmap_spots(fz_context *ctx, const fz_pixmap *pix) | |
| 273 { | |
| 274 return pix->s; | |
| 275 } | |
| 276 | |
| 277 int | |
| 278 fz_pixmap_alpha(fz_context *ctx, const fz_pixmap *pix) | |
| 279 { | |
| 280 return pix->alpha; | |
| 281 } | |
| 282 | |
| 283 int | |
| 284 fz_pixmap_stride(fz_context *ctx, const fz_pixmap *pix) | |
| 285 { | |
| 286 return pix->stride; | |
| 287 } | |
| 288 | |
| 289 unsigned char * | |
| 290 fz_pixmap_samples(fz_context *ctx, const fz_pixmap *pix) | |
| 291 { | |
| 292 if (!pix) | |
| 293 return NULL; | |
| 294 return pix->samples; | |
| 295 } | |
| 296 | |
| 297 /* | |
| 298 The slowest routine in most CMYK rendering profiles. | |
| 299 We therefore spend some effort to improve it. Rather than | |
| 300 writing bytes, we write uint32_t's. | |
| 301 */ | |
| 302 #ifdef ARCH_ARM | |
| 303 static void | |
| 304 clear_cmyka_bitmap_ARM(uint32_t *samples, int c, int value) | |
| 305 __attribute__((naked)); | |
| 306 | |
| 307 static void | |
| 308 clear_cmyka_bitmap_ARM(uint32_t *samples, int c, int value) | |
| 309 { | |
| 310 asm volatile( | |
| 311 ENTER_ARM | |
| 312 "stmfd r13!,{r4-r6,r14} \n" | |
| 313 "@ r0 = samples \n" | |
| 314 "@ r1 = c \n" | |
| 315 "@ r2 = value \n" | |
| 316 "mov r3, #255 \n" | |
| 317 "mov r12,#0 @ r12= 0 \n" | |
| 318 "subs r1, r1, #3 \n" | |
| 319 "ble 2f \n" | |
| 320 "str r12,[r13,#-20]! \n" | |
| 321 "str r12,[r13,#4] \n" | |
| 322 "str r12,[r13,#8] \n" | |
| 323 "str r12,[r13,#12] \n" | |
| 324 "str r12,[r13,#16] \n" | |
| 325 "strb r2, [r13,#3] \n" | |
| 326 "strb r3, [r13,#4] \n" | |
| 327 "strb r2, [r13,#8] \n" | |
| 328 "strb r3, [r13,#9] \n" | |
| 329 "strb r2, [r13,#13] \n" | |
| 330 "strb r3, [r13,#14] \n" | |
| 331 "strb r2, [r13,#18] \n" | |
| 332 "strb r3, [r13,#19] \n" | |
| 333 "ldmfd r13!,{r4,r5,r6,r12,r14} \n" | |
| 334 "1: \n" | |
| 335 "stmia r0!,{r4,r5,r6,r12,r14} \n" | |
| 336 "subs r1, r1, #4 \n" | |
| 337 "bgt 1b \n" | |
| 338 "2: \n" | |
| 339 "adds r1, r1, #3 \n" | |
| 340 "ble 4f \n" | |
| 341 "3: \n" | |
| 342 "strb r12,[r0], #1 \n" | |
| 343 "strb r12,[r0], #1 \n" | |
| 344 "strb r12,[r0], #1 \n" | |
| 345 "strb r2, [r0], #1 \n" | |
| 346 "strb r3, [r0], #1 \n" | |
| 347 "subs r1, r1, #1 \n" | |
| 348 "bgt 3b \n" | |
| 349 "4: \n" | |
| 350 "ldmfd r13!,{r4-r6,PC} \n" | |
| 351 ENTER_THUMB | |
| 352 ); | |
| 353 } | |
| 354 #endif | |
| 355 | |
| 356 static void | |
| 357 clear_cmyk_bitmap(unsigned char *samples, int w, int h, int spots, int stride, int value, int alpha) | |
| 358 { | |
| 359 uint32_t *s = (uint32_t *)(void *)samples; | |
| 360 uint8_t *t; | |
| 361 | |
| 362 if (w < 0 || h < 0) | |
| 363 return; | |
| 364 | |
| 365 if (spots) | |
| 366 { | |
| 367 int x, i; | |
| 368 spots += 4; | |
| 369 stride -= w * (spots + alpha); | |
| 370 for (; h > 0; h--) | |
| 371 { | |
| 372 for (x = w; x > 0; x--) | |
| 373 { | |
| 374 for (i = spots; i > 0; i--) | |
| 375 *samples++ = value; | |
| 376 if (alpha) | |
| 377 *samples++ = 255; | |
| 378 } | |
| 379 samples += stride; | |
| 380 } | |
| 381 return; | |
| 382 } | |
| 383 | |
| 384 if (alpha) | |
| 385 { | |
| 386 int c = w; | |
| 387 stride -= w*5; | |
| 388 if (stride == 0) | |
| 389 { | |
| 390 #ifdef ARCH_ARM | |
| 391 clear_cmyka_bitmap_ARM(s, c, alpha); | |
| 392 return; | |
| 393 #else | |
| 394 /* We can do it all fast (except for maybe a few stragglers) */ | |
| 395 union | |
| 396 { | |
| 397 uint8_t bytes[20]; | |
| 398 uint32_t words[5]; | |
| 399 } d; | |
| 400 | |
| 401 c *= h; | |
| 402 h = 1; | |
| 403 | |
| 404 d.words[0] = 0; | |
| 405 d.words[1] = 0; | |
| 406 d.words[2] = 0; | |
| 407 d.words[3] = 0; | |
| 408 d.words[4] = 0; | |
| 409 d.bytes[3] = value; | |
| 410 d.bytes[4] = 255; | |
| 411 d.bytes[8] = value; | |
| 412 d.bytes[9] = 255; | |
| 413 d.bytes[13] = value; | |
| 414 d.bytes[14] = 255; | |
| 415 d.bytes[18] = value; | |
| 416 d.bytes[19] = 255; | |
| 417 | |
| 418 c -= 3; | |
| 419 { | |
| 420 const uint32_t a0 = d.words[0]; | |
| 421 const uint32_t a1 = d.words[1]; | |
| 422 const uint32_t a2 = d.words[2]; | |
| 423 const uint32_t a3 = d.words[3]; | |
| 424 const uint32_t a4 = d.words[4]; | |
| 425 while (c > 0) | |
| 426 { | |
| 427 *s++ = a0; | |
| 428 *s++ = a1; | |
| 429 *s++ = a2; | |
| 430 *s++ = a3; | |
| 431 *s++ = a4; | |
| 432 c -= 4; | |
| 433 } | |
| 434 } | |
| 435 c += 3; | |
| 436 #endif | |
| 437 } | |
| 438 t = (unsigned char *)s; | |
| 439 w = c; | |
| 440 while (h--) | |
| 441 { | |
| 442 c = w; | |
| 443 while (c > 0) | |
| 444 { | |
| 445 *t++ = 0; | |
| 446 *t++ = 0; | |
| 447 *t++ = 0; | |
| 448 *t++ = value; | |
| 449 *t++ = 255; | |
| 450 c--; | |
| 451 } | |
| 452 t += stride; | |
| 453 } | |
| 454 } | |
| 455 else | |
| 456 { | |
| 457 stride -= w*4; | |
| 458 if ((stride & 3) == 0) | |
| 459 { | |
| 460 size_t W = w; | |
| 461 if (stride == 0) | |
| 462 { | |
| 463 W *= h; | |
| 464 h = 1; | |
| 465 } | |
| 466 W *= 4; | |
| 467 if (value == 0) | |
| 468 { | |
| 469 while (h--) | |
| 470 { | |
| 471 memset(s, 0, W); | |
| 472 s += (stride>>2); | |
| 473 } | |
| 474 } | |
| 475 else | |
| 476 { | |
| 477 /* We can do it all fast */ | |
| 478 union | |
| 479 { | |
| 480 uint8_t bytes[4]; | |
| 481 uint32_t word; | |
| 482 } d; | |
| 483 | |
| 484 d.word = 0; | |
| 485 d.bytes[3] = value; | |
| 486 { | |
| 487 const uint32_t a0 = d.word; | |
| 488 while (h--) | |
| 489 { | |
| 490 size_t WW = W >> 2; | |
| 491 while (WW--) | |
| 492 { | |
| 493 *s++ = a0; | |
| 494 } | |
| 495 s += (stride>>2); | |
| 496 } | |
| 497 } | |
| 498 } | |
| 499 } | |
| 500 else | |
| 501 { | |
| 502 t = (unsigned char *)s; | |
| 503 while (h--) | |
| 504 { | |
| 505 int c = w; | |
| 506 while (c > 0) | |
| 507 { | |
| 508 *t++ = 0; | |
| 509 *t++ = 0; | |
| 510 *t++ = 0; | |
| 511 *t++ = value; | |
| 512 c--; | |
| 513 } | |
| 514 t += stride; | |
| 515 } | |
| 516 } | |
| 517 } | |
| 518 } | |
| 519 | |
| 520 void | |
| 521 fz_clear_pixmap(fz_context *ctx, fz_pixmap *pix) | |
| 522 { | |
| 523 ptrdiff_t stride = pix->w * (ptrdiff_t)pix->n; | |
| 524 int h = pix->h; | |
| 525 unsigned char *s = pix->samples; | |
| 526 if (stride == pix->stride) | |
| 527 { | |
| 528 stride *= h; | |
| 529 h = 1; | |
| 530 } | |
| 531 if (pix->alpha || fz_colorspace_is_subtractive(ctx, pix->colorspace)) | |
| 532 { | |
| 533 while (h--) | |
| 534 { | |
| 535 memset(s, 0, stride); | |
| 536 s += pix->stride; | |
| 537 } | |
| 538 } | |
| 539 else if (pix->s == 0) | |
| 540 { | |
| 541 while (h--) | |
| 542 { | |
| 543 memset(s, 0xff, stride); | |
| 544 s += pix->stride; | |
| 545 } | |
| 546 } | |
| 547 else | |
| 548 { | |
| 549 /* Horrible, slow case: additive with spots */ | |
| 550 size_t w = stride/pix->n; | |
| 551 int spots = pix->s; | |
| 552 int colorants = pix->n - spots; /* We know there is no alpha */ | |
| 553 while (h--) | |
| 554 { | |
| 555 size_t w2 = w; | |
| 556 while (w2--) | |
| 557 { | |
| 558 int i = colorants; | |
| 559 do | |
| 560 { | |
| 561 *s++ = 0xff; | |
| 562 i--; | |
| 563 } | |
| 564 while (i != 0); | |
| 565 | |
| 566 i = spots; | |
| 567 do | |
| 568 { | |
| 569 *s++ = 0; | |
| 570 i--; | |
| 571 } | |
| 572 while (i != 0); | |
| 573 } | |
| 574 } | |
| 575 } | |
| 576 } | |
| 577 | |
| 578 void | |
| 579 fz_clear_pixmap_with_value(fz_context *ctx, fz_pixmap *pix, int value) | |
| 580 { | |
| 581 unsigned char *s; | |
| 582 int w, h, n; | |
| 583 ptrdiff_t stride, len; | |
| 584 int alpha = pix->alpha; | |
| 585 | |
| 586 w = pix->w; | |
| 587 h = pix->h; | |
| 588 if (w < 0 || h < 0) | |
| 589 return; | |
| 590 | |
| 591 /* CMYK needs special handling (and potentially any other subtractive colorspaces) */ | |
| 592 if (fz_colorspace_n(ctx, pix->colorspace) == 4) | |
| 593 { | |
| 594 clear_cmyk_bitmap(pix->samples, w, h, pix->s, pix->stride, 255-value, pix->alpha); | |
| 595 return; | |
| 596 } | |
| 597 | |
| 598 n = pix->n; | |
| 599 stride = pix->stride; | |
| 600 len = (ptrdiff_t)w * n; | |
| 601 | |
| 602 s = pix->samples; | |
| 603 if (value == 255 || !alpha) | |
| 604 { | |
| 605 if (stride == len) | |
| 606 { | |
| 607 len *= h; | |
| 608 h = 1; | |
| 609 } | |
| 610 while (h--) | |
| 611 { | |
| 612 memset(s, value, len); | |
| 613 s += stride; | |
| 614 } | |
| 615 } | |
| 616 else | |
| 617 { | |
| 618 int k, x, y; | |
| 619 stride -= len; | |
| 620 for (y = 0; y < pix->h; y++) | |
| 621 { | |
| 622 for (x = 0; x < pix->w; x++) | |
| 623 { | |
| 624 for (k = 0; k < pix->n - 1; k++) | |
| 625 *s++ = value; | |
| 626 if (alpha) | |
| 627 *s++ = 255; | |
| 628 } | |
| 629 s += stride; | |
| 630 } | |
| 631 } | |
| 632 } | |
| 633 | |
| 634 void | |
| 635 fz_fill_pixmap_with_color(fz_context *ctx, fz_pixmap *pix, fz_colorspace *colorspace, float *color, fz_color_params color_params) | |
| 636 { | |
| 637 float colorfv[FZ_MAX_COLORS]; | |
| 638 unsigned char colorbv[FZ_MAX_COLORS]; | |
| 639 int i, n, a, s, x, y, w, h; | |
| 640 | |
| 641 n = fz_colorspace_n(ctx, pix->colorspace); | |
| 642 a = pix->alpha; | |
| 643 s = pix->s; | |
| 644 fz_convert_color(ctx, colorspace, color, pix->colorspace, colorfv, NULL, color_params); | |
| 645 for (i = 0; i < n; ++i) | |
| 646 colorbv[i] = colorfv[i] * 255; | |
| 647 | |
| 648 w = pix->w; | |
| 649 h = pix->h; | |
| 650 for (y = 0; y < h; ++y) | |
| 651 { | |
| 652 unsigned char *p = pix->samples + y * pix->stride; | |
| 653 for (x = 0; x < w; ++x) | |
| 654 { | |
| 655 for (i = 0; i < n; ++i) | |
| 656 *p++ = colorbv[i]; | |
| 657 for (i = 0; i < s; ++i) | |
| 658 *p++ = 0; | |
| 659 if (a) | |
| 660 *p++ = 255; | |
| 661 } | |
| 662 } | |
| 663 } | |
| 664 | |
| 665 void | |
| 666 fz_copy_pixmap_rect(fz_context *ctx, fz_pixmap *dest, fz_pixmap *src, fz_irect b, const fz_default_colorspaces *default_cs) | |
| 667 { | |
| 668 unsigned char *srcp; | |
| 669 unsigned char *destp; | |
| 670 unsigned int y, w; | |
| 671 size_t destspan, srcspan; | |
| 672 | |
| 673 b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, dest)); | |
| 674 b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, src)); | |
| 675 if (fz_is_empty_irect(b)) | |
| 676 return; | |
| 677 w = (unsigned int)(b.x1 - b.x0); | |
| 678 y = (unsigned int)(b.y1 - b.y0); | |
| 679 | |
| 680 srcspan = src->stride; | |
| 681 srcp = src->samples + srcspan * (b.y0 - src->y) + (b.x0 - src->x) * (size_t)src->n; | |
| 682 destspan = dest->stride; | |
| 683 destp = dest->samples + destspan * (b.y0 - dest->y) + (b.x0 - dest->x) * (size_t)dest->n; | |
| 684 | |
| 685 if (src->n == dest->n) | |
| 686 { | |
| 687 w *= src->n; | |
| 688 do | |
| 689 { | |
| 690 memcpy(destp, srcp, w); | |
| 691 srcp += srcspan; | |
| 692 destp += destspan; | |
| 693 } | |
| 694 while (--y); | |
| 695 } | |
| 696 else | |
| 697 { | |
| 698 fz_pixmap fake_src = *src; | |
| 699 fake_src.x = b.x0; | |
| 700 fake_src.y = b.y0; | |
| 701 fake_src.w = w; | |
| 702 fake_src.h = y; | |
| 703 fake_src.samples = srcp; | |
| 704 fz_convert_pixmap_samples(ctx, &fake_src, dest, NULL, default_cs, fz_default_color_params, 0); | |
| 705 } | |
| 706 } | |
| 707 | |
| 708 void | |
| 709 fz_clear_pixmap_rect_with_value(fz_context *ctx, fz_pixmap *dest, int value, fz_irect b) | |
| 710 { | |
| 711 unsigned char *destp; | |
| 712 int x, y, w, k; | |
| 713 size_t destspan; | |
| 714 | |
| 715 b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, dest)); | |
| 716 w = b.x1 - b.x0; | |
| 717 y = b.y1 - b.y0; | |
| 718 if (w <= 0 || y <= 0) | |
| 719 return; | |
| 720 | |
| 721 destspan = dest->stride; | |
| 722 destp = dest->samples + destspan * (b.y0 - dest->y) + (b.x0 - dest->x) * (size_t)dest->n; | |
| 723 | |
| 724 /* CMYK needs special handling (and potentially any other subtractive colorspaces) */ | |
| 725 if (fz_colorspace_n(ctx, dest->colorspace) == 4) | |
| 726 { | |
| 727 value = 255 - value; | |
| 728 do | |
| 729 { | |
| 730 unsigned char *s = destp; | |
| 731 for (x = 0; x < w; x++) | |
| 732 { | |
| 733 *s++ = 0; | |
| 734 *s++ = 0; | |
| 735 *s++ = 0; | |
| 736 *s++ = value; | |
| 737 *s++ = 255; | |
| 738 } | |
| 739 destp += destspan; | |
| 740 } | |
| 741 while (--y); | |
| 742 return; | |
| 743 } | |
| 744 | |
| 745 if (value == 255) | |
| 746 { | |
| 747 do | |
| 748 { | |
| 749 memset(destp, 255, w * (size_t)dest->n); | |
| 750 destp += destspan; | |
| 751 } | |
| 752 while (--y); | |
| 753 } | |
| 754 else | |
| 755 { | |
| 756 do | |
| 757 { | |
| 758 unsigned char *s = destp; | |
| 759 for (x = 0; x < w; x++) | |
| 760 { | |
| 761 for (k = 0; k < dest->n - 1; k++) | |
| 762 *s++ = value; | |
| 763 *s++ = 255; | |
| 764 } | |
| 765 destp += destspan; | |
| 766 } | |
| 767 while (--y); | |
| 768 } | |
| 769 } | |
| 770 | |
| 771 void | |
| 772 fz_premultiply_pixmap(fz_context *ctx, fz_pixmap *pix) | |
| 773 { | |
| 774 unsigned char *s = pix->samples; | |
| 775 unsigned char a; | |
| 776 int k, x, y; | |
| 777 size_t stride = pix->stride - pix->w * (size_t)pix->n; | |
| 778 | |
| 779 if (!pix->alpha) | |
| 780 return; | |
| 781 | |
| 782 for (y = 0; y < pix->h; y++) | |
| 783 { | |
| 784 for (x = 0; x < pix->w; x++) | |
| 785 { | |
| 786 a = s[pix->n - 1]; | |
| 787 for (k = 0; k < pix->n - 1; k++) | |
| 788 s[k] = fz_mul255(s[k], a); | |
| 789 s += pix->n; | |
| 790 } | |
| 791 s += stride; | |
| 792 } | |
| 793 } | |
| 794 | |
| 795 fz_pixmap * | |
| 796 fz_alpha_from_gray(fz_context *ctx, fz_pixmap *gray) | |
| 797 { | |
| 798 fz_pixmap *alpha; | |
| 799 unsigned char *sp, *dp; | |
| 800 int w, h, sstride, dstride; | |
| 801 | |
| 802 assert(gray->n == 1); | |
| 803 | |
| 804 alpha = fz_new_pixmap_with_bbox(ctx, NULL, fz_pixmap_bbox(ctx, gray), 0, 1); | |
| 805 dp = alpha->samples; | |
| 806 dstride = alpha->stride; | |
| 807 sp = gray->samples; | |
| 808 sstride = gray->stride; | |
| 809 | |
| 810 h = gray->h; | |
| 811 w = gray->w; | |
| 812 while (h--) | |
| 813 { | |
| 814 memcpy(dp, sp, w); | |
| 815 sp += sstride; | |
| 816 dp += dstride; | |
| 817 } | |
| 818 | |
| 819 return alpha; | |
| 820 } | |
| 821 | |
| 822 void | |
| 823 fz_tint_pixmap(fz_context *ctx, fz_pixmap *pix, int black, int white) | |
| 824 { | |
| 825 unsigned char *s = pix->samples; | |
| 826 int n = pix->n; | |
| 827 int x, y, save; | |
| 828 int rb = (black>>16)&255; | |
| 829 int gb = (black>>8)&255; | |
| 830 int bb = (black)&255; | |
| 831 int rw = (white>>16)&255; | |
| 832 int gw = (white>>8)&255; | |
| 833 int bw = (white)&255; | |
| 834 int rm = (rw - rb); | |
| 835 int gm = (gw - gb); | |
| 836 int bm = (bw - bb); | |
| 837 | |
| 838 switch (fz_colorspace_type(ctx, pix->colorspace)) | |
| 839 { | |
| 840 case FZ_COLORSPACE_GRAY: | |
| 841 gw = (rw + gw + bw) / 3; | |
| 842 gb = (rb + gb + bb) / 3; | |
| 843 gm = gw - gb; | |
| 844 for (y = 0; y < pix->h; y++) | |
| 845 { | |
| 846 for (x = 0; x < pix->w; x++) | |
| 847 { | |
| 848 *s = gb + fz_mul255(*s, gm); | |
| 849 s += n; | |
| 850 } | |
| 851 s += pix->stride - pix->w * n; | |
| 852 } | |
| 853 break; | |
| 854 | |
| 855 case FZ_COLORSPACE_BGR: | |
| 856 save = rm; rm = bm; bm = save; | |
| 857 save = rb; rb = bb; bb = save; | |
| 858 /* fall through */ | |
| 859 case FZ_COLORSPACE_RGB: | |
| 860 for (y = 0; y < pix->h; y++) | |
| 861 { | |
| 862 for (x = 0; x < pix->w; x++) | |
| 863 { | |
| 864 s[0] = rb + fz_mul255(s[0], rm); | |
| 865 s[1] = gb + fz_mul255(s[1], gm); | |
| 866 s[2] = bb + fz_mul255(s[2], bm); | |
| 867 s += n; | |
| 868 } | |
| 869 s += pix->stride - pix->w * n; | |
| 870 } | |
| 871 break; | |
| 872 | |
| 873 default: | |
| 874 fz_throw(ctx, FZ_ERROR_ARGUMENT, "can only tint RGB, BGR and Gray pixmaps"); | |
| 875 break; | |
| 876 } | |
| 877 } | |
| 878 | |
| 879 /* Invert luminance in RGB/BGR pixmap, but keep the colors as is. */ | |
| 880 static inline void invert_luminance(int type, unsigned char *s) | |
| 881 { | |
| 882 int r, g, b, y; | |
| 883 | |
| 884 /* Convert to YUV */ | |
| 885 if (type == FZ_COLORSPACE_RGB) | |
| 886 { | |
| 887 r = s[0]; | |
| 888 g = s[1]; | |
| 889 b = s[2]; | |
| 890 } | |
| 891 else | |
| 892 { | |
| 893 r = s[2]; | |
| 894 g = s[1]; | |
| 895 b = s[0]; | |
| 896 } | |
| 897 | |
| 898 y = (39336 * r + 76884 * g + 14900 * b + 32768)>>16; | |
| 899 y = 259-y; | |
| 900 r += y; | |
| 901 g += y; | |
| 902 b += y; | |
| 903 | |
| 904 if (type == FZ_COLORSPACE_RGB) | |
| 905 { | |
| 906 s[0] = r > 255 ? 255 : r < 0 ? 0 : r; | |
| 907 s[1] = g > 255 ? 255 : g < 0 ? 0 : g; | |
| 908 s[2] = b > 255 ? 255 : b < 0 ? 0 : b; | |
| 909 } | |
| 910 else | |
| 911 { | |
| 912 s[2] = r > 255 ? 255 : r < 0 ? 0 : r; | |
| 913 s[1] = g > 255 ? 255 : g < 0 ? 0 : g; | |
| 914 s[0] = b > 255 ? 255 : b < 0 ? 0 : b; | |
| 915 } | |
| 916 } | |
| 917 | |
| 918 void | |
| 919 fz_invert_pixmap_luminance(fz_context *ctx, fz_pixmap *pix) | |
| 920 { | |
| 921 unsigned char *s = pix->samples; | |
| 922 int x, y, n = pix->n; | |
| 923 int type = pix->colorspace ? pix->colorspace->type : FZ_COLORSPACE_NONE; | |
| 924 | |
| 925 if (type == FZ_COLORSPACE_GRAY) | |
| 926 { | |
| 927 fz_invert_pixmap(ctx, pix); | |
| 928 } | |
| 929 else if (type == FZ_COLORSPACE_RGB || type == FZ_COLORSPACE_BGR) | |
| 930 { | |
| 931 for (y = 0; y < pix->h; y++) | |
| 932 { | |
| 933 for (x = 0; x < pix->w; x++) | |
| 934 { | |
| 935 invert_luminance(type, s); | |
| 936 s += n; | |
| 937 } | |
| 938 s += pix->stride - pix->w * n; | |
| 939 } | |
| 940 } | |
| 941 else | |
| 942 { | |
| 943 fz_throw(ctx, FZ_ERROR_ARGUMENT, "can only invert luminance of Gray and RGB pixmaps"); | |
| 944 } | |
| 945 } | |
| 946 | |
| 947 void | |
| 948 fz_invert_pixmap(fz_context *ctx, fz_pixmap *pix) | |
| 949 { | |
| 950 fz_irect rect = { pix->x, pix->y, pix->x + pix->w, pix->y + pix->h }; | |
| 951 fz_invert_pixmap_rect(ctx, pix, rect); | |
| 952 } | |
| 953 | |
| 954 void | |
| 955 fz_invert_pixmap_alpha(fz_context *ctx, fz_pixmap *pix) | |
| 956 { | |
| 957 unsigned char *s = pix->samples; | |
| 958 int x, y; | |
| 959 int n1 = pix->n - pix->alpha; | |
| 960 int n = pix->n; | |
| 961 | |
| 962 if (!pix->alpha) | |
| 963 return; | |
| 964 | |
| 965 for (y = 0; y < pix->h; y++) | |
| 966 { | |
| 967 s += n1; | |
| 968 for (x = 0; x < pix->w; x++) | |
| 969 { | |
| 970 *s = 255 - *s; | |
| 971 s += n; | |
| 972 } | |
| 973 s += pix->stride - pix->w * n; | |
| 974 } | |
| 975 } | |
| 976 | |
| 977 void fz_invert_pixmap_rect(fz_context *ctx, fz_pixmap *pix, fz_irect rect) | |
| 978 { | |
| 979 int x0 = fz_clampi(rect.x0 - pix->x, 0, pix->w); | |
| 980 int x1 = fz_clampi(rect.x1 - pix->x, 0, pix->w); | |
| 981 int y0 = fz_clampi(rect.y0 - pix->y, 0, pix->h); | |
| 982 int y1 = fz_clampi(rect.y1 - pix->y, 0, pix->h); | |
| 983 | |
| 984 int x, y; | |
| 985 int n = pix->n; | |
| 986 int s = pix->s; | |
| 987 int cmyk = (pix->colorspace && pix->colorspace->type == FZ_COLORSPACE_CMYK); | |
| 988 | |
| 989 if (cmyk) | |
| 990 { | |
| 991 /* For cmyk, we're storing: (a.c, a.m, a.y, a.k, a) | |
| 992 * So, a.r = a - a.c - a.k | |
| 993 * a.g = a - a.m - a.k | |
| 994 * a.b = a - a.y - a.k | |
| 995 * Invert that: | |
| 996 * a.R = a.c + a.k | |
| 997 * a.G = a.m + a.k | |
| 998 * a.B = a.y + a.k | |
| 999 * Convert that back to cmy | |
| 1000 * a.C = a - a.c - a.k; | |
| 1001 * a.M = a - a.m - a.k; | |
| 1002 * a.Y = a - a.y - a.k; | |
| 1003 * Extract K: | |
| 1004 * a.K' = min(a.C, a.M, a.Y) | |
| 1005 * = a - a.k - max(a.c, a.m, a.y) | |
| 1006 * a.C' = a.C - a.K' = a - a.c - a.k - (a - a.k - max(a.c, a.m, a.y)) = max(a.c, a.m, a.y) - a.c | |
| 1007 * a.M' = a.M - a.K' = a - a.m - a.k - (a - a.k - max(a.c, a.m, a.y)) = max(a.c, a.m, a.y) - a.m | |
| 1008 * a.Y' = a.Y - a.K' = a - a.y - a.k - (a - a.k - max(a.c, a.m, a.y)) = max(a.c, a.m, a.y) - a.y | |
| 1009 * */ | |
| 1010 if (pix->alpha) | |
| 1011 { | |
| 1012 int n1 = pix->n - pix->alpha - s; | |
| 1013 for (y = y0; y < y1; y++) | |
| 1014 { | |
| 1015 unsigned char *d = pix->samples + ((y * (size_t)pix->stride) + (x0 * (size_t)pix->n)); | |
| 1016 for (x = x0; x < x1; x++) | |
| 1017 { | |
| 1018 int ac = d[0]; | |
| 1019 int am = d[1]; | |
| 1020 int ay = d[2]; | |
| 1021 int ak = d[3]; | |
| 1022 int a = d[n1]; | |
| 1023 int mx = fz_maxi(fz_maxi(ac, am), ay); | |
| 1024 d[0] = mx-ac; | |
| 1025 d[1] = mx-am; | |
| 1026 d[2] = mx-ay; | |
| 1027 ak = a - ak - mx; | |
| 1028 if (ak < 0) | |
| 1029 ak = 0; | |
| 1030 d[3] = ak; | |
| 1031 d += n; | |
| 1032 } | |
| 1033 } | |
| 1034 } | |
| 1035 else | |
| 1036 { | |
| 1037 for (y = y0; y < y1; y++) | |
| 1038 { | |
| 1039 unsigned char *d = pix->samples + ((y * (size_t)pix->stride) + (x0 * (size_t)pix->n)); | |
| 1040 for (x = x0; x < x1; x++) | |
| 1041 { | |
| 1042 int c = d[0]; | |
| 1043 int m = d[1]; | |
| 1044 int ye = d[2]; | |
| 1045 int k = d[3]; | |
| 1046 int mx = fz_maxi(fz_maxi(c, m), ye); | |
| 1047 d[0] = mx-c; | |
| 1048 d[1] = mx-m; | |
| 1049 d[2] = mx-ye; | |
| 1050 k = 255 - k - mx; | |
| 1051 if (k < 0) | |
| 1052 k = 0; | |
| 1053 d[3] = k; | |
| 1054 d += n; | |
| 1055 } | |
| 1056 } | |
| 1057 } | |
| 1058 } | |
| 1059 else if (pix->alpha) | |
| 1060 { | |
| 1061 int n1 = pix->n - pix->alpha - s; | |
| 1062 for (y = y0; y < y1; y++) | |
| 1063 { | |
| 1064 unsigned char *d = pix->samples + ((y * (size_t)pix->stride) + (x0 * (size_t)pix->n)); | |
| 1065 for (x = x0; x < x1; x++) | |
| 1066 { | |
| 1067 int a = d[n1]; | |
| 1068 int k; | |
| 1069 for (k = 0; k < n1; k++) | |
| 1070 d[k] = a - d[k]; | |
| 1071 d += n; | |
| 1072 } | |
| 1073 } | |
| 1074 } | |
| 1075 else if (s) | |
| 1076 { | |
| 1077 int n1 = pix->n - s; | |
| 1078 for (y = y0; y < y1; y++) | |
| 1079 { | |
| 1080 unsigned char *d = pix->samples + ((y * (size_t)pix->stride) + (x0 * (size_t)pix->n)); | |
| 1081 for (x = x0; x < x1; x++) | |
| 1082 { | |
| 1083 int k; | |
| 1084 for (k = 0; k < n1; k++) | |
| 1085 d[k] = 255 - d[k]; | |
| 1086 d += n; | |
| 1087 } | |
| 1088 } | |
| 1089 } | |
| 1090 else | |
| 1091 { | |
| 1092 for (y = y0; y < y1; y++) | |
| 1093 { | |
| 1094 unsigned char *d = pix->samples + ((y * (size_t)pix->stride) + (x0 * (size_t)pix->n)); | |
| 1095 for (x = x0; x < x1; x++) | |
| 1096 { | |
| 1097 int k; | |
| 1098 for (k = 0; k < n; k++) | |
| 1099 d[k] = 255 - d[k]; | |
| 1100 d += n; | |
| 1101 } | |
| 1102 } | |
| 1103 } | |
| 1104 } | |
| 1105 | |
| 1106 void | |
| 1107 fz_invert_pixmap_raw(fz_context *ctx, fz_pixmap *pix) | |
| 1108 { | |
| 1109 unsigned char *s = pix->samples; | |
| 1110 int k, x, y; | |
| 1111 int n1 = pix->n - pix->alpha; | |
| 1112 int n = pix->n; | |
| 1113 | |
| 1114 for (y = 0; y < pix->h; y++) | |
| 1115 { | |
| 1116 for (x = 0; x < pix->w; x++) | |
| 1117 { | |
| 1118 for (k = 0; k < n1; k++) | |
| 1119 s[k] = 255 - s[k]; | |
| 1120 s += n; | |
| 1121 } | |
| 1122 s += pix->stride - pix->w * n; | |
| 1123 } | |
| 1124 } | |
| 1125 | |
| 1126 void | |
| 1127 fz_gamma_pixmap(fz_context *ctx, fz_pixmap *pix, float gamma) | |
| 1128 { | |
| 1129 unsigned char gamma_map[256]; | |
| 1130 unsigned char *s = pix->samples; | |
| 1131 int n1 = pix->n - pix->alpha; | |
| 1132 int n = pix->n; | |
| 1133 int k, x, y; | |
| 1134 | |
| 1135 for (k = 0; k < 256; k++) | |
| 1136 gamma_map[k] = powf(k / 255.0f, gamma) * 255; | |
| 1137 | |
| 1138 for (y = 0; y < pix->h; y++) | |
| 1139 { | |
| 1140 for (x = 0; x < pix->w; x++) | |
| 1141 { | |
| 1142 for (k = 0; k < n1; k++) | |
| 1143 s[k] = gamma_map[s[k]]; | |
| 1144 s += n; | |
| 1145 } | |
| 1146 s += pix->stride - pix->w * n; | |
| 1147 } | |
| 1148 } | |
| 1149 | |
| 1150 size_t | |
| 1151 fz_pixmap_size(fz_context *ctx, fz_pixmap * pix) | |
| 1152 { | |
| 1153 if (pix == NULL) | |
| 1154 return 0; | |
| 1155 return sizeof(*pix) + (size_t)pix->n * pix->w * pix->h; | |
| 1156 } | |
| 1157 | |
| 1158 fz_pixmap * | |
| 1159 fz_convert_pixmap(fz_context *ctx, const fz_pixmap *pix, fz_colorspace *ds, fz_colorspace *prf, fz_default_colorspaces *default_cs, fz_color_params color_params, int keep_alpha) | |
| 1160 { | |
| 1161 fz_pixmap *cvt; | |
| 1162 | |
| 1163 if (!ds && !keep_alpha) | |
| 1164 fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot both throw away and keep alpha"); | |
| 1165 | |
| 1166 cvt = fz_new_pixmap(ctx, ds, pix->w, pix->h, pix->seps, keep_alpha && pix->alpha); | |
| 1167 | |
| 1168 cvt->xres = pix->xres; | |
| 1169 cvt->yres = pix->yres; | |
| 1170 cvt->x = pix->x; | |
| 1171 cvt->y = pix->y; | |
| 1172 if (pix->flags & FZ_PIXMAP_FLAG_INTERPOLATE) | |
| 1173 cvt->flags |= FZ_PIXMAP_FLAG_INTERPOLATE; | |
| 1174 else | |
| 1175 cvt->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE; | |
| 1176 | |
| 1177 fz_try(ctx) | |
| 1178 { | |
| 1179 fz_convert_pixmap_samples(ctx, pix, cvt, prf, default_cs, color_params, 1); | |
| 1180 } | |
| 1181 fz_catch(ctx) | |
| 1182 { | |
| 1183 fz_drop_pixmap(ctx, cvt); | |
| 1184 fz_rethrow(ctx); | |
| 1185 } | |
| 1186 | |
| 1187 return cvt; | |
| 1188 } | |
| 1189 | |
| 1190 fz_pixmap * | |
| 1191 fz_new_pixmap_from_8bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span) | |
| 1192 { | |
| 1193 fz_pixmap *pixmap = fz_new_pixmap(ctx, NULL, w, h, NULL, 1); | |
| 1194 int stride = pixmap->stride; | |
| 1195 unsigned char *s = pixmap->samples; | |
| 1196 pixmap->x = x; | |
| 1197 pixmap->y = y; | |
| 1198 | |
| 1199 for (y = 0; y < h; y++) | |
| 1200 { | |
| 1201 memcpy(s, sp + y * span, w); | |
| 1202 s += stride; | |
| 1203 } | |
| 1204 | |
| 1205 return pixmap; | |
| 1206 } | |
| 1207 | |
| 1208 fz_pixmap * | |
| 1209 fz_new_pixmap_from_1bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span) | |
| 1210 { | |
| 1211 fz_pixmap *pixmap = fz_new_pixmap(ctx, NULL, w, h, NULL, 1); | |
| 1212 int stride = pixmap->stride - pixmap->w; | |
| 1213 pixmap->x = x; | |
| 1214 pixmap->y = y; | |
| 1215 | |
| 1216 for (y = 0; y < h; y++) | |
| 1217 { | |
| 1218 unsigned char *out = pixmap->samples + y * w; | |
| 1219 unsigned char *in = sp + y * span; | |
| 1220 unsigned char bit = 0x80; | |
| 1221 int ww = w; | |
| 1222 while (ww--) | |
| 1223 { | |
| 1224 *out++ = (*in & bit) ? 255 : 0; | |
| 1225 bit >>= 1; | |
| 1226 if (bit == 0) | |
| 1227 bit = 0x80, in++; | |
| 1228 } | |
| 1229 out += stride; | |
| 1230 } | |
| 1231 | |
| 1232 return pixmap; | |
| 1233 } | |
| 1234 | |
| 1235 static float | |
| 1236 calc_percentile(int *hist, float thr, float scale, float minval, float maxval) | |
| 1237 { | |
| 1238 float prct; | |
| 1239 int k = 0, count = 0; | |
| 1240 | |
| 1241 while (count < thr) | |
| 1242 count += hist[k++]; | |
| 1243 | |
| 1244 if (k <= 0) | |
| 1245 prct = k; | |
| 1246 else | |
| 1247 { | |
| 1248 float c0 = count - thr; | |
| 1249 float c1 = thr - (count - hist[k - 1]); | |
| 1250 prct = (c1 * k + c0 * (k - 1)) / (c0 + c1); | |
| 1251 } | |
| 1252 | |
| 1253 prct /= scale; | |
| 1254 prct += minval; | |
| 1255 return fz_clamp(prct, minval, maxval); | |
| 1256 } | |
| 1257 | |
| 1258 static void | |
| 1259 calc_percentiles(fz_context *ctx, float *samples, size_t nsamples, float *minprct, float *maxprct) | |
| 1260 { | |
| 1261 float minval, maxval, scale; | |
| 1262 size_t size, k; | |
| 1263 int *hist; | |
| 1264 | |
| 1265 minval = maxval = samples[0]; | |
| 1266 for (k = 1; k < nsamples; k++) | |
| 1267 { | |
| 1268 minval = fz_min(minval, samples[k]); | |
| 1269 maxval = fz_max(maxval, samples[k]); | |
| 1270 } | |
| 1271 | |
| 1272 if (minval - maxval == 0) | |
| 1273 { | |
| 1274 *minprct = *maxprct = minval; | |
| 1275 return; | |
| 1276 } | |
| 1277 | |
| 1278 size = fz_minz(65535, nsamples); | |
| 1279 scale = (size - 1) / (maxval - minval); | |
| 1280 | |
| 1281 hist = fz_calloc(ctx, size, sizeof(int)); | |
| 1282 | |
| 1283 *minprct = 0; | |
| 1284 *maxprct = 0; | |
| 1285 | |
| 1286 for (k = 0; k < nsamples; k++) | |
| 1287 hist[(uint16_t) (scale * (samples[k] - minval))]++; | |
| 1288 | |
| 1289 *minprct = calc_percentile(hist, 0.01f * nsamples, scale, minval, maxval); | |
| 1290 *maxprct = calc_percentile(hist, 0.99f * nsamples, scale, minval, maxval); | |
| 1291 | |
| 1292 fz_free(ctx, hist); | |
| 1293 } | |
| 1294 | |
| 1295 /* Tone mapping according to "Consistent Tone Reproduction" by Min H. Kim and Jan Kautz. */ | |
| 1296 fz_pixmap * | |
| 1297 fz_new_pixmap_from_float_data(fz_context *ctx, fz_colorspace *cs, int w, int h, float *samples) | |
| 1298 { | |
| 1299 fz_pixmap *pixmap = NULL; | |
| 1300 unsigned char *dp; | |
| 1301 float *sample; | |
| 1302 float minsample, maxsample, mu; | |
| 1303 float k1, d0, sigma, sigmasq2; | |
| 1304 float minprct, maxprct, range; | |
| 1305 size_t k, nsamples; | |
| 1306 int y; | |
| 1307 #define KIMKAUTZC1 (3.0f) | |
| 1308 #define KIMKAUTZC2 (0.5f) | |
| 1309 #define MAXLD (logf(300.0f)) | |
| 1310 #define MINLD (logf(0.3f)) | |
| 1311 | |
| 1312 pixmap = fz_new_pixmap(ctx, cs, w, h, NULL, 0); | |
| 1313 if (w > 0 && h > 0 && pixmap->n > 0) | |
| 1314 { | |
| 1315 fz_try(ctx) | |
| 1316 { | |
| 1317 nsamples = (size_t) w * h; | |
| 1318 if ((size_t) pixmap->n > SIZE_MAX / nsamples) | |
| 1319 fz_throw(ctx, FZ_ERROR_LIMIT, "too many floating point samples to convert to pixmap"); | |
| 1320 nsamples *= pixmap->n; | |
| 1321 | |
| 1322 mu = 0; | |
| 1323 minsample = FLT_MAX; | |
| 1324 maxsample = -FLT_MAX; | |
| 1325 | |
| 1326 for (k = 0; k < nsamples; k++) | |
| 1327 { | |
| 1328 float v = logf(samples[k] == 0 ? FLT_MIN : samples[k]); | |
| 1329 mu += v; | |
| 1330 minsample = fz_min(minsample, v); | |
| 1331 maxsample = fz_max(maxsample, v); | |
| 1332 } | |
| 1333 | |
| 1334 mu /= nsamples; | |
| 1335 d0 = maxsample - minsample; | |
| 1336 k1 = (MAXLD - MINLD) / d0; | |
| 1337 sigma = d0 / KIMKAUTZC1; | |
| 1338 sigmasq2 = sigma * sigma * 2; | |
| 1339 | |
| 1340 for (k = 0; k < nsamples; k++) | |
| 1341 { | |
| 1342 float samplemu = samples[k] - mu; | |
| 1343 float samplemu2 = samplemu * samplemu; | |
| 1344 float fw = expf(-samplemu2 / sigmasq2); | |
| 1345 float k2 = (1 - k1) * fw + k1; | |
| 1346 samples[k] = expf(KIMKAUTZC2 * k2 * (logf(samples[k] == 0 ? FLT_MIN : samples[k]) - mu) + mu); | |
| 1347 } | |
| 1348 | |
| 1349 calc_percentiles(ctx, samples, nsamples, &minprct, &maxprct); | |
| 1350 range = maxprct - minprct; | |
| 1351 | |
| 1352 dp = pixmap->samples + pixmap->stride * (h - 1); | |
| 1353 sample = samples; | |
| 1354 | |
| 1355 for (y = 0; y < h; y++) | |
| 1356 { | |
| 1357 unsigned char *dpp = dp; | |
| 1358 | |
| 1359 for (k = 0; k < (size_t) w * pixmap->n; k++) | |
| 1360 *dpp++ = 255.0f * (fz_clamp(*sample++, minprct, maxprct) - minprct) / range; | |
| 1361 | |
| 1362 dp -= pixmap->stride; | |
| 1363 } | |
| 1364 } | |
| 1365 fz_catch(ctx) | |
| 1366 { | |
| 1367 fz_drop_pixmap(ctx, pixmap); | |
| 1368 fz_rethrow(ctx); | |
| 1369 } | |
| 1370 } | |
| 1371 | |
| 1372 return pixmap; | |
| 1373 } | |
| 1374 | |
| 1375 fz_pixmap * | |
| 1376 fz_new_pixmap_from_alpha_channel(fz_context *ctx, fz_pixmap *src) | |
| 1377 { | |
| 1378 fz_pixmap *dst; | |
| 1379 int w, h, n, x; | |
| 1380 unsigned char *sp, *dp; | |
| 1381 | |
| 1382 if (!src->alpha) | |
| 1383 return NULL; | |
| 1384 | |
| 1385 dst = fz_new_pixmap_with_bbox(ctx, NULL, fz_pixmap_bbox(ctx, src), NULL, 1); | |
| 1386 w = src->w; | |
| 1387 h = src->h; | |
| 1388 n = src->n; | |
| 1389 sp = src->samples + n - 1; | |
| 1390 dp = dst->samples; | |
| 1391 | |
| 1392 while (h--) | |
| 1393 { | |
| 1394 unsigned char *s = sp; | |
| 1395 unsigned char *d = dp; | |
| 1396 for (x = 0; x < w; ++x) | |
| 1397 { | |
| 1398 *d++ = *s; | |
| 1399 s += n; | |
| 1400 } | |
| 1401 sp += src->stride; | |
| 1402 dp += dst->stride; | |
| 1403 } | |
| 1404 | |
| 1405 return dst; | |
| 1406 } | |
| 1407 | |
| 1408 fz_pixmap * | |
| 1409 fz_new_pixmap_from_color_and_mask(fz_context *ctx, fz_pixmap *color, fz_pixmap *mask) | |
| 1410 { | |
| 1411 fz_pixmap *dst; | |
| 1412 int w = color->w; | |
| 1413 int h = color->h; | |
| 1414 int n = color->n; | |
| 1415 int x, y, k; | |
| 1416 | |
| 1417 if (color->alpha) | |
| 1418 fz_throw(ctx, FZ_ERROR_ARGUMENT, "color pixmap must not have an alpha channel"); | |
| 1419 if (mask->n != 1) | |
| 1420 fz_throw(ctx, FZ_ERROR_ARGUMENT, "mask pixmap must have exactly one channel"); | |
| 1421 if (mask->w != color->w || mask->h != color->h) | |
| 1422 fz_throw(ctx, FZ_ERROR_ARGUMENT, "color and mask pixmaps must be the same size"); | |
| 1423 | |
| 1424 dst = fz_new_pixmap_with_bbox(ctx, color->colorspace, fz_pixmap_bbox(ctx, color), NULL, 1); | |
| 1425 | |
| 1426 for (y = 0; y < h; ++y) | |
| 1427 { | |
| 1428 unsigned char *cs = &color->samples[y * color->stride]; | |
| 1429 unsigned char *ms = &mask->samples[y * mask->stride]; | |
| 1430 unsigned char *ds = &dst->samples[y * dst->stride]; | |
| 1431 for (x = 0; x < w; ++x) | |
| 1432 { | |
| 1433 unsigned char a = *ms++; | |
| 1434 for (k = 0; k < n; ++k) | |
| 1435 *ds++ = fz_mul255(*cs++, a); | |
| 1436 *ds++ = a; | |
| 1437 } | |
| 1438 } | |
| 1439 | |
| 1440 return dst; | |
| 1441 } | |
| 1442 | |
| 1443 int | |
| 1444 fz_is_pixmap_monochrome(fz_context *ctx, fz_pixmap *pixmap) | |
| 1445 { | |
| 1446 int n = pixmap->n; | |
| 1447 int w = pixmap->w; | |
| 1448 int h = pixmap->h; | |
| 1449 unsigned char *s = pixmap->samples; | |
| 1450 int x; | |
| 1451 | |
| 1452 if (n != 1) | |
| 1453 return 0; | |
| 1454 | |
| 1455 while (h--) | |
| 1456 { | |
| 1457 for (x = 0; x < w; ++x) | |
| 1458 { | |
| 1459 unsigned char v = s[x]; | |
| 1460 if (v != 0 && v != 255) | |
| 1461 return 0; | |
| 1462 } | |
| 1463 s += pixmap->stride; | |
| 1464 } | |
| 1465 | |
| 1466 return 1; | |
| 1467 } | |
| 1468 | |
| 1469 #ifdef ARCH_ARM | |
| 1470 static void | |
| 1471 fz_subsample_pixmap_ARM(unsigned char *ptr, int w, int h, int f, int factor, | |
| 1472 int n, int fwd, int back, int back2, int fwd2, | |
| 1473 int divX, int back4, int fwd4, int fwd3, | |
| 1474 int divY, int back5, int divXY) | |
| 1475 __attribute__((naked)); | |
| 1476 | |
| 1477 static void | |
| 1478 fz_subsample_pixmap_ARM(unsigned char *ptr, int w, int h, int f, int factor, | |
| 1479 int n, int fwd, int back, int back2, int fwd2, | |
| 1480 int divX, int back4, int fwd4, int fwd3, | |
| 1481 int divY, int back5, int divXY) | |
| 1482 { | |
| 1483 asm volatile( | |
| 1484 ENTER_ARM | |
| 1485 "stmfd r13!,{r1,r4-r11,r14} \n" | |
| 1486 "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n" | |
| 1487 "@ r0 = src = ptr \n" | |
| 1488 "@ r1 = w \n" | |
| 1489 "@ r2 = h \n" | |
| 1490 "@ r3 = f \n" | |
| 1491 "mov r9, r0 @ r9 = dst = ptr \n" | |
| 1492 "ldr r6, [r13,#4*12] @ r6 = fwd \n" | |
| 1493 "ldr r7, [r13,#4*13] @ r7 = back \n" | |
| 1494 "subs r2, r2, r3 @ r2 = h -= f \n" | |
| 1495 "blt 12f @ Skip if less than a full row \n" | |
| 1496 "1: @ for (y = h; y > 0; y--) { \n" | |
| 1497 "ldr r1, [r13] @ r1 = w \n" | |
| 1498 "subs r1, r1, r3 @ r1 = w -= f \n" | |
| 1499 "blt 6f @ Skip if less than a full col \n" | |
| 1500 "ldr r4, [r13,#4*10] @ r4 = factor \n" | |
| 1501 "ldr r8, [r13,#4*14] @ r8 = back2 \n" | |
| 1502 "ldr r12,[r13,#4*15] @ r12= fwd2 \n" | |
| 1503 "2: @ for (x = w; x > 0; x--) { \n" | |
| 1504 "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n" | |
| 1505 "3: @ \n" | |
| 1506 "mov r14,#0 @ r14= v = 0 \n" | |
| 1507 "sub r5, r5, r3, LSL #8 @ for (xx = f; xx > 0; x--) { \n" | |
| 1508 "4: @ \n" | |
| 1509 "add r5, r5, r3, LSL #16 @ for (yy = f; yy > 0; y--) { \n" | |
| 1510 "5: @ \n" | |
| 1511 "ldrb r11,[r0], r6 @ r11= *src src += fwd \n" | |
| 1512 "subs r5, r5, #1<<16 @ xx-- \n" | |
| 1513 "add r14,r14,r11 @ v += r11 \n" | |
| 1514 "bgt 5b @ } \n" | |
| 1515 "sub r0, r0, r7 @ src -= back \n" | |
| 1516 "adds r5, r5, #1<<8 @ yy-- \n" | |
| 1517 "blt 4b @ } \n" | |
| 1518 "mov r14,r14,LSR r4 @ r14 = v >>= factor \n" | |
| 1519 "strb r14,[r9], #1 @ *d++ = r14 \n" | |
| 1520 "sub r0, r0, r8 @ s -= back2 \n" | |
| 1521 "subs r5, r5, #1 @ n-- \n" | |
| 1522 "bgt 3b @ } \n" | |
| 1523 "add r0, r0, r12 @ s += fwd2 \n" | |
| 1524 "subs r1, r1, r3 @ x -= f \n" | |
| 1525 "bge 2b @ } \n" | |
| 1526 "6: @ Less than a full column left \n" | |
| 1527 "adds r1, r1, r3 @ x += f \n" | |
| 1528 "beq 11f @ if (x == 0) next row \n" | |
| 1529 "@ r0 = src \n" | |
| 1530 "@ r1 = x \n" | |
| 1531 "@ r2 = y \n" | |
| 1532 "@ r3 = f \n" | |
| 1533 "@ r4 = factor \n" | |
| 1534 "@ r6 = fwd \n" | |
| 1535 "@ r7 = back \n" | |
| 1536 "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n" | |
| 1537 "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n" | |
| 1538 "ldr r4, [r13,#4*16] @ r4 = divX \n" | |
| 1539 "ldr r8, [r13,#4*17] @ r8 = back4 \n" | |
| 1540 "ldr r12,[r13,#4*18] @ r12= fwd4 \n" | |
| 1541 "8: @ \n" | |
| 1542 "mov r14,#0 @ r14= v = 0 \n" | |
| 1543 "sub r5, r5, r1, LSL #8 @ for (xx = x; xx > 0; x--) { \n" | |
| 1544 "9: @ \n" | |
| 1545 "add r5, r5, r3, LSL #16 @ for (yy = f; yy > 0; y--) { \n" | |
| 1546 "10: @ \n" | |
| 1547 "ldrb r11,[r0], r6 @ r11= *src src += fwd \n" | |
| 1548 "subs r5, r5, #1<<16 @ xx-- \n" | |
| 1549 "add r14,r14,r11 @ v += r11 \n" | |
| 1550 "bgt 10b @ } \n" | |
| 1551 "sub r0, r0, r7 @ src -= back \n" | |
| 1552 "adds r5, r5, #1<<8 @ yy-- \n" | |
| 1553 "blt 9b @ } \n" | |
| 1554 "mul r14,r4, r14 @ r14= v *= divX \n" | |
| 1555 "mov r14,r14,LSR #16 @ r14= v >>= 16 \n" | |
| 1556 "strb r14,[r9], #1 @ *d++ = r14 \n" | |
| 1557 "sub r0, r0, r8 @ s -= back4 \n" | |
| 1558 "subs r5, r5, #1 @ n-- \n" | |
| 1559 "bgt 8b @ } \n" | |
| 1560 "add r0, r0, r12 @ s += fwd4 \n" | |
| 1561 "11: @ \n" | |
| 1562 "ldr r14,[r13,#4*19] @ r14 = fwd3 \n" | |
| 1563 "subs r2, r2, r3 @ h -= f \n" | |
| 1564 "add r0, r0, r14 @ s += fwd3 \n" | |
| 1565 "bge 1b @ } \n" | |
| 1566 "12: \n" | |
| 1567 "adds r2, r2, r3 @ h += f \n" | |
| 1568 "beq 21f @ if no stray row, end \n" | |
| 1569 "@ So doing one last (partial) row \n" | |
| 1570 "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n" | |
| 1571 "@ r0 = src = ptr \n" | |
| 1572 "@ r1 = w \n" | |
| 1573 "@ r2 = h \n" | |
| 1574 "@ r3 = f \n" | |
| 1575 "@ r4 = factor \n" | |
| 1576 "@ r5 = n \n" | |
| 1577 "@ r6 = fwd \n" | |
| 1578 " @ for (y = h; y > 0; y--) { \n" | |
| 1579 "ldr r1, [r13] @ r1 = w \n" | |
| 1580 "ldr r7, [r13,#4*21] @ r7 = back5 \n" | |
| 1581 "ldr r8, [r13,#4*14] @ r8 = back2 \n" | |
| 1582 "subs r1, r1, r3 @ r1 = w -= f \n" | |
| 1583 "blt 17f @ Skip if less than a full col \n" | |
| 1584 "ldr r4, [r13,#4*20] @ r4 = divY \n" | |
| 1585 "ldr r12,[r13,#4*15] @ r12= fwd2 \n" | |
| 1586 "13: @ for (x = w; x > 0; x--) { \n" | |
| 1587 "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n" | |
| 1588 "14: @ \n" | |
| 1589 "mov r14,#0 @ r14= v = 0 \n" | |
| 1590 "sub r5, r5, r3, LSL #8 @ for (xx = f; xx > 0; x--) { \n" | |
| 1591 "15: @ \n" | |
| 1592 "add r5, r5, r2, LSL #16 @ for (yy = y; yy > 0; y--) { \n" | |
| 1593 "16: @ \n" | |
| 1594 "ldrb r11,[r0], r6 @ r11= *src src += fwd \n" | |
| 1595 "subs r5, r5, #1<<16 @ xx-- \n" | |
| 1596 "add r14,r14,r11 @ v += r11 \n" | |
| 1597 "bgt 16b @ } \n" | |
| 1598 "sub r0, r0, r7 @ src -= back5 \n" | |
| 1599 "adds r5, r5, #1<<8 @ yy-- \n" | |
| 1600 "blt 15b @ } \n" | |
| 1601 "mul r14,r4, r14 @ r14 = x *= divY \n" | |
| 1602 "mov r14,r14,LSR #16 @ r14 = v >>= 16 \n" | |
| 1603 "strb r14,[r9], #1 @ *d++ = r14 \n" | |
| 1604 "sub r0, r0, r8 @ s -= back2 \n" | |
| 1605 "subs r5, r5, #1 @ n-- \n" | |
| 1606 "bgt 14b @ } \n" | |
| 1607 "add r0, r0, r12 @ s += fwd2 \n" | |
| 1608 "subs r1, r1, r3 @ x -= f \n" | |
| 1609 "bge 13b @ } \n" | |
| 1610 "17: @ Less than a full column left \n" | |
| 1611 "adds r1, r1, r3 @ x += f \n" | |
| 1612 "beq 21f @ if (x == 0) end \n" | |
| 1613 "@ r0 = src \n" | |
| 1614 "@ r1 = x \n" | |
| 1615 "@ r2 = y \n" | |
| 1616 "@ r3 = f \n" | |
| 1617 "@ r4 = factor \n" | |
| 1618 "@ r6 = fwd \n" | |
| 1619 "@ r7 = back5 \n" | |
| 1620 "@ r8 = back2 \n" | |
| 1621 "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n" | |
| 1622 "ldr r4, [r13,#4*22] @ r4 = divXY \n" | |
| 1623 "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n" | |
| 1624 "ldr r8, [r13,#4*17] @ r8 = back4 \n" | |
| 1625 "18: @ \n" | |
| 1626 "mov r14,#0 @ r14= v = 0 \n" | |
| 1627 "sub r5, r5, r1, LSL #8 @ for (xx = x; xx > 0; x--) { \n" | |
| 1628 "19: @ \n" | |
| 1629 "add r5, r5, r2, LSL #16 @ for (yy = y; yy > 0; y--) { \n" | |
| 1630 "20: @ \n" | |
| 1631 "ldrb r11,[r0],r6 @ r11= *src src += fwd \n" | |
| 1632 "subs r5, r5, #1<<16 @ xx-- \n" | |
| 1633 "add r14,r14,r11 @ v += r11 \n" | |
| 1634 "bgt 20b @ } \n" | |
| 1635 "sub r0, r0, r7 @ src -= back5 \n" | |
| 1636 "adds r5, r5, #1<<8 @ yy-- \n" | |
| 1637 "blt 19b @ } \n" | |
| 1638 "mul r14,r4, r14 @ r14= v *= divX \n" | |
| 1639 "mov r14,r14,LSR #16 @ r14= v >>= 16 \n" | |
| 1640 "strb r14,[r9], #1 @ *d++ = r14 \n" | |
| 1641 "sub r0, r0, r8 @ s -= back4 \n" | |
| 1642 "subs r5, r5, #1 @ n-- \n" | |
| 1643 "bgt 18b @ } \n" | |
| 1644 "21: @ \n" | |
| 1645 "ldmfd r13!,{r1,r4-r11,PC} @ pop, return to thumb \n" | |
| 1646 ENTER_THUMB | |
| 1647 ); | |
| 1648 } | |
| 1649 | |
| 1650 #endif | |
| 1651 | |
| 1652 void | |
| 1653 fz_subsample_pixmap(fz_context *ctx, fz_pixmap *tile, int factor) | |
| 1654 { | |
| 1655 int f; | |
| 1656 | |
| 1657 if (!tile) | |
| 1658 return; | |
| 1659 | |
| 1660 assert(tile->stride >= tile->w * tile->n); | |
| 1661 | |
| 1662 fz_subsample_pixblock(tile->samples, tile->w, tile->h, tile->n, factor, tile->stride); | |
| 1663 | |
| 1664 f = 1<<factor; | |
| 1665 tile->w = (tile->w + f-1)>>factor; | |
| 1666 tile->h = (tile->h + f-1)>>factor; | |
| 1667 tile->stride = tile->w * (size_t)tile->n; | |
| 1668 /* Redundant test? We only ever make pixmaps smaller! */ | |
| 1669 if (tile->h > INT_MAX / (tile->w * tile->n)) | |
| 1670 fz_throw(ctx, FZ_ERROR_LIMIT, "pixmap too large"); | |
| 1671 tile->samples = fz_realloc(ctx, tile->samples, (size_t)tile->h * tile->w * tile->n); | |
| 1672 } | |
| 1673 | |
| 1674 void | |
| 1675 fz_subsample_pixblock(unsigned char *s, int w, int h, int n, int factor, ptrdiff_t stride) | |
| 1676 { | |
| 1677 int fwd, fwd2, fwd3, back, back2, f; | |
| 1678 unsigned char *d; | |
| 1679 #ifndef ARCH_ARM | |
| 1680 int x, y, xx, yy, nn; | |
| 1681 #endif | |
| 1682 | |
| 1683 d = s; | |
| 1684 f = 1<<factor; | |
| 1685 fwd = stride; | |
| 1686 back = f*fwd-n; | |
| 1687 back2 = f*n-1; | |
| 1688 fwd2 = (f-1)*n; | |
| 1689 fwd3 = (f-1)*fwd + (int)stride - w * n; | |
| 1690 factor *= 2; | |
| 1691 #ifdef ARCH_ARM | |
| 1692 { | |
| 1693 int strayX = w%f; | |
| 1694 int divX = (strayX ? 65536/(strayX*f) : 0); | |
| 1695 int fwd4 = (strayX-1) * n; | |
| 1696 int back4 = strayX*n-1; | |
| 1697 int strayY = h%f; | |
| 1698 int divY = (strayY ? 65536/(strayY*f) : 0); | |
| 1699 int back5 = fwd * strayY - n; | |
| 1700 int divXY = (strayY*strayX ? 65536/(strayX*strayY) : 0); | |
| 1701 fz_subsample_pixmap_ARM(s, w, h, f, factor, n, fwd, back, | |
| 1702 back2, fwd2, divX, back4, fwd4, fwd3, | |
| 1703 divY, back5, divXY); | |
| 1704 } | |
| 1705 #else | |
| 1706 for (y = h - f; y >= 0; y -= f) | |
| 1707 { | |
| 1708 for (x = w - f; x >= 0; x -= f) | |
| 1709 { | |
| 1710 for (nn = n; nn > 0; nn--) | |
| 1711 { | |
| 1712 int v = 0; | |
| 1713 for (xx = f; xx > 0; xx--) | |
| 1714 { | |
| 1715 for (yy = f; yy > 0; yy--) | |
| 1716 { | |
| 1717 v += *s; | |
| 1718 s += fwd; | |
| 1719 } | |
| 1720 s -= back; | |
| 1721 } | |
| 1722 *d++ = v >> factor; | |
| 1723 s -= back2; | |
| 1724 } | |
| 1725 s += fwd2; | |
| 1726 } | |
| 1727 /* Do any strays */ | |
| 1728 x += f; | |
| 1729 if (x > 0) | |
| 1730 { | |
| 1731 int div = x * f; | |
| 1732 int fwd4 = (x-1) * n; | |
| 1733 int back4 = x*n-1; | |
| 1734 for (nn = n; nn > 0; nn--) | |
| 1735 { | |
| 1736 int v = 0; | |
| 1737 for (xx = x; xx > 0; xx--) | |
| 1738 { | |
| 1739 for (yy = f; yy > 0; yy--) | |
| 1740 { | |
| 1741 v += *s; | |
| 1742 s += fwd; | |
| 1743 } | |
| 1744 s -= back; | |
| 1745 } | |
| 1746 *d++ = v / div; | |
| 1747 s -= back4; | |
| 1748 } | |
| 1749 s += fwd4; | |
| 1750 } | |
| 1751 s += fwd3; | |
| 1752 } | |
| 1753 /* Do any stray line */ | |
| 1754 y += f; | |
| 1755 if (y > 0) | |
| 1756 { | |
| 1757 int div = y * f; | |
| 1758 int back5 = fwd * y - n; | |
| 1759 for (x = w - f; x >= 0; x -= f) | |
| 1760 { | |
| 1761 for (nn = n; nn > 0; nn--) | |
| 1762 { | |
| 1763 int v = 0; | |
| 1764 for (xx = f; xx > 0; xx--) | |
| 1765 { | |
| 1766 for (yy = y; yy > 0; yy--) | |
| 1767 { | |
| 1768 v += *s; | |
| 1769 s += fwd; | |
| 1770 } | |
| 1771 s -= back5; | |
| 1772 } | |
| 1773 *d++ = v / div; | |
| 1774 s -= back2; | |
| 1775 } | |
| 1776 s += fwd2; | |
| 1777 } | |
| 1778 /* Do any stray at the end of the stray line */ | |
| 1779 x += f; | |
| 1780 if (x > 0) | |
| 1781 { | |
| 1782 int back4 = x * n - 1; | |
| 1783 div = x * y; | |
| 1784 for (nn = n; nn > 0; nn--) | |
| 1785 { | |
| 1786 int v = 0; | |
| 1787 for (xx = x; xx > 0; xx--) | |
| 1788 { | |
| 1789 for (yy = y; yy > 0; yy--) | |
| 1790 { | |
| 1791 v += *s; | |
| 1792 s += fwd; | |
| 1793 } | |
| 1794 s -= back5; | |
| 1795 } | |
| 1796 *d++ = v / div; | |
| 1797 s -= back4; | |
| 1798 } | |
| 1799 } | |
| 1800 } | |
| 1801 #endif | |
| 1802 } | |
| 1803 | |
| 1804 void | |
| 1805 fz_set_pixmap_resolution(fz_context *ctx, fz_pixmap *pix, int xres, int yres) | |
| 1806 { | |
| 1807 pix->xres = xres; | |
| 1808 pix->yres = yres; | |
| 1809 } | |
| 1810 | |
| 1811 /* | |
| 1812 Return the md5 digest for a pixmap | |
| 1813 */ | |
| 1814 void | |
| 1815 fz_md5_pixmap(fz_context *ctx, fz_pixmap *pix, unsigned char digest[16]) | |
| 1816 { | |
| 1817 fz_md5 md5; | |
| 1818 | |
| 1819 fz_md5_init(&md5); | |
| 1820 if (pix) | |
| 1821 { | |
| 1822 unsigned char *s = pix->samples; | |
| 1823 int h = pix->h; | |
| 1824 int ss = pix->stride; | |
| 1825 int len = pix->w * pix->n; | |
| 1826 while (h--) | |
| 1827 { | |
| 1828 fz_md5_update(&md5, s, len); | |
| 1829 s += ss; | |
| 1830 } | |
| 1831 } | |
| 1832 fz_md5_final(&md5, digest); | |
| 1833 } | |
| 1834 | |
| 1835 #ifdef HAVE_VALGRIND | |
| 1836 int fz_valgrind_pixmap(const fz_pixmap *pix) | |
| 1837 { | |
| 1838 int w, h, n, total; | |
| 1839 int ww, hh, nn; | |
| 1840 int stride; | |
| 1841 const unsigned char *p = pix->samples; | |
| 1842 | |
| 1843 if (pix == NULL) | |
| 1844 return 0; | |
| 1845 | |
| 1846 total = 0; | |
| 1847 ww = pix->w; | |
| 1848 hh = pix->h; | |
| 1849 nn = pix->n; | |
| 1850 stride = pix->stride - ww*nn; | |
| 1851 for (h = 0; h < hh; h++) | |
| 1852 { | |
| 1853 for (w = 0; w < ww; w++) | |
| 1854 for (n = 0; n < nn; n++) | |
| 1855 if (*p++) total ++; | |
| 1856 p += stride; | |
| 1857 } | |
| 1858 return total; | |
| 1859 } | |
| 1860 #endif /* HAVE_VALGRIND */ | |
| 1861 | |
| 1862 fz_pixmap * | |
| 1863 fz_convert_indexed_pixmap_to_base(fz_context *ctx, const fz_pixmap *src) | |
| 1864 { | |
| 1865 fz_pixmap *dst; | |
| 1866 fz_colorspace *base; | |
| 1867 const unsigned char *s; | |
| 1868 unsigned char *d; | |
| 1869 int y, x, k, n, high; | |
| 1870 unsigned char *lookup; | |
| 1871 ptrdiff_t s_line_inc, d_line_inc; | |
| 1872 | |
| 1873 if (src->colorspace->type != FZ_COLORSPACE_INDEXED) | |
| 1874 fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot convert non-indexed pixmap"); | |
| 1875 if (src->n != 1 + src->alpha) | |
| 1876 fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot convert indexed pixmap mis-matching components"); | |
| 1877 | |
| 1878 base = src->colorspace->u.indexed.base; | |
| 1879 high = src->colorspace->u.indexed.high; | |
| 1880 lookup = src->colorspace->u.indexed.lookup; | |
| 1881 n = base->n; | |
| 1882 | |
| 1883 dst = fz_new_pixmap_with_bbox(ctx, base, fz_pixmap_bbox(ctx, src), src->seps, src->alpha); | |
| 1884 s = src->samples; | |
| 1885 d = dst->samples; | |
| 1886 s_line_inc = src->stride - src->w * (ptrdiff_t)src->n; | |
| 1887 d_line_inc = dst->stride - dst->w * (ptrdiff_t)dst->n; | |
| 1888 | |
| 1889 if (src->alpha) | |
| 1890 { | |
| 1891 for (y = 0; y < src->h; y++) | |
| 1892 { | |
| 1893 for (x = 0; x < src->w; x++) | |
| 1894 { | |
| 1895 int v = *s++; | |
| 1896 int a = *s++; | |
| 1897 int aa = a + (a>>7); | |
| 1898 v = fz_mini(v, high); | |
| 1899 for (k = 0; k < n; k++) | |
| 1900 *d++ = (aa * lookup[v * n + k] + 128)>>8; | |
| 1901 *d++ = a; | |
| 1902 } | |
| 1903 s += s_line_inc; | |
| 1904 d += d_line_inc; | |
| 1905 } | |
| 1906 } | |
| 1907 else | |
| 1908 { | |
| 1909 for (y = 0; y < src->h; y++) | |
| 1910 { | |
| 1911 for (x = 0; x < src->w; x++) | |
| 1912 { | |
| 1913 int v = *s++; | |
| 1914 v = fz_mini(v, high); | |
| 1915 for (k = 0; k < n; k++) | |
| 1916 *d++ = lookup[v * n + k]; | |
| 1917 } | |
| 1918 s += s_line_inc; | |
| 1919 d += d_line_inc; | |
| 1920 } | |
| 1921 } | |
| 1922 | |
| 1923 if (src->flags & FZ_PIXMAP_FLAG_INTERPOLATE) | |
| 1924 dst->flags |= FZ_PIXMAP_FLAG_INTERPOLATE; | |
| 1925 else | |
| 1926 dst->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE; | |
| 1927 | |
| 1928 return dst; | |
| 1929 } | |
| 1930 | |
| 1931 fz_pixmap * | |
| 1932 fz_convert_separation_pixmap_to_base(fz_context *ctx, const fz_pixmap *src) | |
| 1933 { | |
| 1934 fz_pixmap *dst; | |
| 1935 fz_colorspace *ss, *base; | |
| 1936 const unsigned char *s; | |
| 1937 unsigned char *d; | |
| 1938 int y, x, k, sn, bn, a; | |
| 1939 float src_v[FZ_MAX_COLORS]; | |
| 1940 float base_v[FZ_MAX_COLORS]; | |
| 1941 ptrdiff_t s_line_inc, d_line_inc; | |
| 1942 | |
| 1943 ss = src->colorspace; | |
| 1944 | |
| 1945 if (ss->type != FZ_COLORSPACE_SEPARATION) | |
| 1946 fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot expand non-separation pixmap"); | |
| 1947 if (src->n != ss->n + src->alpha) | |
| 1948 fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot expand separation pixmap mis-matching alpha channel"); | |
| 1949 | |
| 1950 base = ss->u.separation.base; | |
| 1951 dst = fz_new_pixmap_with_bbox(ctx, base, fz_pixmap_bbox(ctx, src), src->seps, src->alpha); | |
| 1952 fz_clear_pixmap(ctx, dst); | |
| 1953 fz_try(ctx) | |
| 1954 { | |
| 1955 s = src->samples; | |
| 1956 d = dst->samples; | |
| 1957 s_line_inc = src->stride - src->w * (ptrdiff_t)src->n; | |
| 1958 d_line_inc = dst->stride - dst->w * (ptrdiff_t)dst->n; | |
| 1959 sn = ss->n; | |
| 1960 bn = base->n; | |
| 1961 | |
| 1962 if (base->type == FZ_COLORSPACE_LAB) | |
| 1963 { | |
| 1964 if (src->alpha) | |
| 1965 { | |
| 1966 for (y = 0; y < src->h; y++) | |
| 1967 { | |
| 1968 for (x = 0; x < src->w; x++) | |
| 1969 { | |
| 1970 for (k = 0; k < sn; ++k) | |
| 1971 src_v[k] = *s++ / 255.0f; | |
| 1972 a = *s++; | |
| 1973 ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn); | |
| 1974 *d++ = (base_v[0] / 100) * 255.0f; | |
| 1975 *d++ = base_v[1] + 128; | |
| 1976 *d++ = base_v[2] + 128; | |
| 1977 *d++ = a; | |
| 1978 } | |
| 1979 s += s_line_inc; | |
| 1980 d += d_line_inc; | |
| 1981 } | |
| 1982 } | |
| 1983 else | |
| 1984 { | |
| 1985 for (y = 0; y < src->h; y++) | |
| 1986 { | |
| 1987 for (x = 0; x < src->w; x++) | |
| 1988 { | |
| 1989 for (k = 0; k < sn; ++k) | |
| 1990 src_v[k] = *s++ / 255.0f; | |
| 1991 ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn); | |
| 1992 *d++ = (base_v[0] / 100) * 255.0f; | |
| 1993 *d++ = base_v[1] + 128; | |
| 1994 *d++ = base_v[2] + 128; | |
| 1995 } | |
| 1996 s += s_line_inc; | |
| 1997 d += d_line_inc; | |
| 1998 } | |
| 1999 } | |
| 2000 } | |
| 2001 else | |
| 2002 { | |
| 2003 if (src->alpha) | |
| 2004 { | |
| 2005 for (y = 0; y < src->h; y++) | |
| 2006 { | |
| 2007 for (x = 0; x < src->w; x++) | |
| 2008 { | |
| 2009 for (k = 0; k < sn; ++k) | |
| 2010 src_v[k] = *s++ / 255.0f; | |
| 2011 a = *s++; | |
| 2012 ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn); | |
| 2013 for (k = 0; k < bn; ++k) | |
| 2014 *d++ = base_v[k] * 255.0f; | |
| 2015 *d++ = a; | |
| 2016 } | |
| 2017 s += s_line_inc; | |
| 2018 d += d_line_inc; | |
| 2019 } | |
| 2020 } | |
| 2021 else | |
| 2022 { | |
| 2023 for (y = 0; y < src->h; y++) | |
| 2024 { | |
| 2025 for (x = 0; x < src->w; x++) | |
| 2026 { | |
| 2027 for (k = 0; k < sn; ++k) | |
| 2028 src_v[k] = *s++ / 255.0f; | |
| 2029 ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn); | |
| 2030 for (k = 0; k < bn; ++k) | |
| 2031 *d++ = base_v[k] * 255.0f; | |
| 2032 } | |
| 2033 s += s_line_inc; | |
| 2034 d += d_line_inc; | |
| 2035 } | |
| 2036 } | |
| 2037 } | |
| 2038 | |
| 2039 if (src->flags & FZ_PIXMAP_FLAG_INTERPOLATE) | |
| 2040 dst->flags |= FZ_PIXMAP_FLAG_INTERPOLATE; | |
| 2041 else | |
| 2042 dst->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE; | |
| 2043 } | |
| 2044 fz_catch(ctx) | |
| 2045 { | |
| 2046 fz_drop_pixmap(ctx, dst); | |
| 2047 fz_rethrow(ctx); | |
| 2048 } | |
| 2049 | |
| 2050 return dst; | |
| 2051 } |
