pdf-image-rewriter.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968
  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. #include "mupdf/fitz.h"
  23. #include "mupdf/pdf.h"
  24. #include "../fitz/pixmap-imp.h"
  25. #include <string.h>
  26. #include <math.h>
  27. typedef struct
  28. {
  29. int num;
  30. int gen;
  31. float dpi;
  32. } image_details;
  33. typedef struct
  34. {
  35. int max;
  36. int len;
  37. int *uimg;
  38. } image_list;
  39. typedef struct
  40. {
  41. int max;
  42. int len;
  43. image_details *img;
  44. } unique_image_list;
  45. typedef struct
  46. {
  47. image_list list;
  48. unique_image_list uilist;
  49. pdf_image_rewriter_options *opts;
  50. int which;
  51. } image_info;
  52. static float
  53. dpi_from_ctm(fz_matrix ctm, int w, int h)
  54. {
  55. float expx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b);
  56. float expy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d);
  57. float dpix = w * 72.0f / (expx == 0 ? 1 : expx);
  58. float dpiy = h * 72.0f / (expy == 0 ? 1 : expy);
  59. if (dpix > dpiy)
  60. return dpiy;
  61. return dpix;
  62. }
  63. static void
  64. gather_image_rewrite(fz_context *ctx, void *opaque, fz_image **image, fz_matrix ctm, pdf_obj *im_obj)
  65. {
  66. image_info *info = (image_info *)opaque;
  67. image_list *ilist = &info->list;
  68. unique_image_list *uilist = &info->uilist;
  69. int i, num, gen;
  70. float dpi;
  71. if (im_obj == NULL)
  72. return; /* Inline image, don't need to pregather that. */
  73. num = pdf_to_num(ctx, im_obj);
  74. gen = pdf_to_gen(ctx, im_obj);
  75. dpi = dpi_from_ctm(ctm, (*image)->w, (*image)->h);
  76. /* Find this in the unique image list */
  77. for (i = 0; i < uilist->len; i++)
  78. {
  79. /* Found one already. Keep the smaller of the dpi's. */
  80. if (uilist->img[i].num == num &&
  81. uilist->img[i].gen == gen)
  82. {
  83. if (dpi < uilist->img[i].dpi)
  84. uilist->img[i].dpi = dpi;
  85. break;
  86. }
  87. }
  88. if (i == uilist->len)
  89. {
  90. /* Need to add a new unique image. */
  91. if (uilist->max == uilist->len)
  92. {
  93. int max2 = uilist->max * 2;
  94. if (max2 == 0)
  95. max2 = 32; /* Arbitrary */
  96. uilist->img = fz_realloc(ctx, uilist->img, max2 * sizeof(*uilist->img));
  97. uilist->max = max2;
  98. }
  99. uilist->img[uilist->len].num = num;
  100. uilist->img[uilist->len].gen = gen;
  101. uilist->img[uilist->len].dpi = dpi;
  102. uilist->len++;
  103. }
  104. /* Now we need to add an entry in the unique image list saying that entry n in
  105. * that list corresponds to the ith unique image. */
  106. if (ilist->max == ilist->len)
  107. {
  108. int max2 = ilist->max * 2;
  109. if (max2 == 0)
  110. max2 = 32; /* Arbitrary */
  111. ilist->uimg = fz_realloc(ctx, ilist->uimg, max2 * sizeof(*ilist->uimg));
  112. ilist->max = max2;
  113. }
  114. ilist->uimg[ilist->len++] = i;
  115. }
  116. typedef enum
  117. {
  118. IMAGE_COLOR = 0,
  119. IMAGE_GRAY,
  120. IMAGE_BITONAL
  121. } image_type;
  122. static image_type
  123. classify_pixmap(fz_context *ctx, fz_pixmap *pix)
  124. {
  125. /* For now, spots means color. In future we could check to
  126. * see if all the spots were 0? */
  127. if (pix->s)
  128. return IMAGE_COLOR;
  129. if (fz_colorspace_is_gray(ctx, pix->colorspace))
  130. {
  131. int n = pix->n;
  132. int h = pix->h;
  133. ptrdiff_t span_step = pix->stride - pix->w * n;
  134. const unsigned char *s = pix->samples;
  135. /* Loop until we know it's not bitonal */
  136. if (pix->alpha)
  137. {
  138. while (h--)
  139. {
  140. int w = pix->w;
  141. while (w--)
  142. {
  143. if (s[1] == 0)
  144. {
  145. /* If alpha is zero, other components don't matter. */
  146. }
  147. else if (s[0] != 0 && s[0] != 255)
  148. return IMAGE_GRAY;
  149. s += 2;
  150. }
  151. s += span_step;
  152. }
  153. return IMAGE_BITONAL;
  154. }
  155. else
  156. {
  157. while (h--)
  158. {
  159. int w = pix->w;
  160. while (w--)
  161. {
  162. if (s[0] != 0 && s[0] != 255)
  163. return IMAGE_GRAY;
  164. s++;
  165. }
  166. s += span_step;
  167. }
  168. return IMAGE_BITONAL;
  169. }
  170. }
  171. else if (fz_colorspace_is_rgb(ctx, pix->colorspace))
  172. {
  173. int n = pix->n;
  174. int h = pix->h;
  175. int w;
  176. ptrdiff_t span_step = pix->stride - pix->w * n;
  177. const unsigned char *s = pix->samples;
  178. /* Is this safe, cos of profiles? */
  179. if (pix->alpha)
  180. {
  181. /* Loop until we know it's not bitonal */
  182. while (h--)
  183. {
  184. w = pix->w;
  185. while (w--)
  186. {
  187. if (s[3] == 0)
  188. {
  189. /* If alpha is zero, other components don't matter. */
  190. }
  191. else if (s[0] == s[1] && s[0] == s[2])
  192. {
  193. /* Plausibly gray */
  194. if (s[0] != 0 && s[0] != 255)
  195. goto rgba_not_bitonal; /* But not bitonal */
  196. if (s[3] != 0 && s[3] != 255)
  197. goto rgba_not_bitonal;
  198. }
  199. else
  200. return IMAGE_COLOR;
  201. s += n;
  202. }
  203. s += span_step;
  204. }
  205. return IMAGE_BITONAL;
  206. /* Loop until we know it's not gray */
  207. while (h--)
  208. {
  209. w = pix->w;
  210. while (w--)
  211. {
  212. if (s[3] == 0)
  213. {
  214. /* If alpha is zero, other components don't matter. */
  215. }
  216. else if (s[0] != s[1] || s[0] != s[2])
  217. return IMAGE_COLOR;
  218. rgba_not_bitonal:
  219. s += n;
  220. }
  221. s += span_step;
  222. }
  223. return IMAGE_GRAY;
  224. }
  225. else
  226. {
  227. /* Loop until we know it's not bitonal */
  228. while (h--)
  229. {
  230. w = pix->w;
  231. while (w--)
  232. {
  233. if (s[0] == s[1] && s[0] == s[2])
  234. {
  235. if (s[0] != 0 && s[0] != 255)
  236. goto rgb_not_bitonal;
  237. }
  238. else
  239. return IMAGE_COLOR;
  240. s += n;
  241. }
  242. s += span_step;
  243. }
  244. return IMAGE_BITONAL;
  245. /* Loop until we know it's not gray */
  246. while (h--)
  247. {
  248. w = pix->w;
  249. while (w--)
  250. {
  251. if (s[0] != s[1] || s[0] != s[2])
  252. return IMAGE_COLOR;
  253. rgb_not_bitonal:
  254. s += n;
  255. }
  256. s += span_step;
  257. }
  258. return IMAGE_GRAY;
  259. }
  260. }
  261. else if (fz_colorspace_is_cmyk(ctx, pix->colorspace))
  262. {
  263. int n = pix->n;
  264. int h = pix->h;
  265. int w;
  266. ptrdiff_t span_step = pix->stride - pix->w * n;
  267. const unsigned char *s = pix->samples;
  268. if (pix->alpha)
  269. {
  270. /* Loop until we know it's not bitonal */
  271. while (h--)
  272. {
  273. w = pix->w;
  274. while (w--)
  275. {
  276. if (s[4] == 0)
  277. {
  278. /* If alpha is 0, other components don't matter. */
  279. }
  280. else if (s[0] == 0 && s[1] == 0 && s[2] == 0)
  281. {
  282. if (s[3] != 0 && s[3] != 255)
  283. goto cmyka_not_bitonal;
  284. }
  285. else
  286. return IMAGE_COLOR;
  287. s += 5;
  288. }
  289. s += span_step;
  290. }
  291. return IMAGE_GRAY;
  292. /* Loop until we know it's not gray */
  293. while (h--)
  294. {
  295. w = pix->w;
  296. while (w--)
  297. {
  298. if (s[4] == 0)
  299. {
  300. /* If alpha is 0, other components don't matter. */
  301. }
  302. else if (s[0] != 0 || s[1] != 0 || s[2] != 0)
  303. return IMAGE_COLOR;
  304. cmyka_not_bitonal:
  305. s += 5;
  306. }
  307. s += span_step;
  308. }
  309. return IMAGE_GRAY;
  310. }
  311. else
  312. {
  313. /* Loop until we know it's not bitonal */
  314. while (h--)
  315. {
  316. w = pix->w;
  317. while (w--)
  318. {
  319. if (s[0] == 0 && s[1] == 0 && s[2] != 0)
  320. {
  321. if (s[3] != 0 && s[3] != 255)
  322. goto cmyk_not_bitonal;
  323. }
  324. else
  325. return IMAGE_COLOR;
  326. s += 4;
  327. }
  328. s += span_step;
  329. }
  330. return IMAGE_GRAY;
  331. /* Loop until we know it's not gray */
  332. while (h--)
  333. {
  334. w = pix->w;
  335. while (w--)
  336. {
  337. if (s[0] != 0 || s[1] != 0 || s[2] != 0)
  338. return IMAGE_COLOR;
  339. cmyk_not_bitonal:
  340. s += 4;
  341. }
  342. s += span_step;
  343. }
  344. return IMAGE_GRAY;
  345. }
  346. }
  347. return IMAGE_COLOR;
  348. }
  349. static fz_pixmap *
  350. resample(fz_context *ctx, fz_pixmap *src, int method, float from_dpi, float to_dpi)
  351. {
  352. int w2 = src->w;
  353. int h2 = src->h;
  354. int w = (int)(w2 * to_dpi / from_dpi + 0.5f);
  355. int h = (int)(h2 * to_dpi / from_dpi + 0.5f);
  356. int factor;
  357. /* Allow for us shrinking an image to 0.*/
  358. assert(w >= 0 && h >= 0);
  359. if (w == 0)
  360. w = 1;
  361. if (h == 0)
  362. h = 1;
  363. /* Allow for the possibility that we might only want to make such a tiny change
  364. * in dpi that the image doesn't really resize. */
  365. if (w >= w2 && h >= h2)
  366. return NULL;
  367. if (method == FZ_SUBSAMPLE_BICUBIC)
  368. {
  369. fz_irect clip = { 0, 0, w, h };
  370. return fz_scale_pixmap(ctx, src, 0, 0, w, h, &clip);
  371. }
  372. factor = 0;
  373. while (1)
  374. {
  375. int w3 = (w2+1)/2;
  376. int h3 = (h2+1)/2;
  377. if (w3 <= w || h3 <= h)
  378. break;
  379. factor++;
  380. w2 = w3;
  381. h2 = h3;
  382. }
  383. fz_subsample_pixmap(ctx, src, factor);
  384. return fz_keep_pixmap(ctx, src);
  385. }
  386. static int
  387. fmt_is_lossy(int fmt)
  388. {
  389. if (fmt == FZ_IMAGE_JBIG2 ||
  390. fmt == FZ_IMAGE_JPEG ||
  391. fmt == FZ_IMAGE_JPX ||
  392. fmt == FZ_IMAGE_JXR)
  393. return 1;
  394. return 0;
  395. }
  396. static fz_compressed_buffer *
  397. fz_recompress_image_as_jpeg(fz_context *ctx, fz_pixmap *pix, const char *quality, fz_colorspace **cs)
  398. {
  399. fz_compressed_buffer *cbuf = NULL;
  400. fz_pixmap *rgb = NULL;
  401. int q = fz_atoi(quality);
  402. if (q == 0)
  403. q = 75; /* Default quality */
  404. if (!pix->colorspace)
  405. return NULL;
  406. if (!fz_colorspace_is_cmyk(ctx, pix->colorspace) &&
  407. !fz_colorspace_is_gray(ctx, pix->colorspace) &&
  408. !fz_colorspace_is_rgb(ctx, pix->colorspace))
  409. {
  410. /* We're going to need to convert colorspace. */
  411. /* It's not gray, so we need a color space - pick rgb. */
  412. pix = rgb = fz_convert_pixmap(ctx, pix, fz_device_rgb(ctx), NULL, NULL, fz_default_color_params, 0);
  413. *cs = fz_device_rgb(ctx);
  414. }
  415. fz_var(cbuf);
  416. fz_try(ctx)
  417. {
  418. cbuf = fz_new_compressed_buffer(ctx);
  419. cbuf->buffer = fz_new_buffer_from_pixmap_as_jpeg(ctx, pix, fz_default_color_params, q, 0);
  420. cbuf->params.type = FZ_IMAGE_JPEG;
  421. cbuf->params.u.jpeg.color_transform = -2;
  422. }
  423. fz_always(ctx)
  424. {
  425. if (rgb)
  426. fz_drop_pixmap(ctx, rgb);
  427. }
  428. fz_catch(ctx)
  429. {
  430. fz_drop_compressed_buffer(ctx, cbuf);
  431. fz_rethrow(ctx);
  432. }
  433. return cbuf;
  434. }
  435. static fz_compressed_buffer *
  436. fz_recompress_image_as_j2k(fz_context *ctx, fz_pixmap *pix, const char *quality)
  437. {
  438. fz_compressed_buffer *cbuf = fz_new_compressed_buffer(ctx);
  439. fz_output *out = NULL;
  440. int q = fz_atoi(quality);
  441. if (q <= 0)
  442. q = 80; /* Default 1:20 compression */
  443. if (q > 100)
  444. q = 100;
  445. fz_var(out);
  446. fz_try(ctx)
  447. {
  448. cbuf->buffer = fz_new_buffer(ctx, 1024);
  449. out = fz_new_output_with_buffer(ctx, cbuf->buffer);
  450. fz_write_pixmap_as_jpx(ctx, out, pix, q);
  451. cbuf->params.type = FZ_IMAGE_JPX;
  452. cbuf->params.u.jpx.smask_in_data = 0;
  453. }
  454. fz_always(ctx)
  455. {
  456. fz_drop_output(ctx, out);
  457. }
  458. fz_catch(ctx)
  459. {
  460. fz_drop_compressed_buffer(ctx, cbuf);
  461. fz_rethrow(ctx);
  462. }
  463. return cbuf;
  464. }
  465. static fz_compressed_buffer *
  466. fz_recompress_image_as_flate(fz_context *ctx, fz_pixmap *pix, const char *quality)
  467. {
  468. fz_compressed_buffer *cbuf = fz_new_compressed_buffer(ctx);
  469. fz_output *out = NULL;
  470. fz_output *out2 = NULL;
  471. int h = pix->h;
  472. size_t n = (size_t) pix->w * pix->n;
  473. const unsigned char *samp = pix->samples;
  474. ptrdiff_t str = pix->stride;
  475. int q = fz_atoi(quality);
  476. /* Notionally, it's 0-100 */
  477. q /= 11;
  478. if (q > FZ_DEFLATE_BEST)
  479. q = FZ_DEFLATE_BEST;
  480. if (q <= 0)
  481. q = FZ_DEFLATE_DEFAULT;
  482. fz_var(out);
  483. fz_var(out2);
  484. fz_try(ctx)
  485. {
  486. cbuf->buffer = fz_new_buffer(ctx, 1024);
  487. out = fz_new_output_with_buffer(ctx, cbuf->buffer);
  488. out2 = fz_new_deflate_output(ctx, out, q, 0);
  489. while (h--)
  490. {
  491. fz_write_data(ctx, out2, samp, n);
  492. samp += str;
  493. }
  494. fz_close_output(ctx, out2);
  495. fz_drop_output(ctx, out2);
  496. out2 = NULL;
  497. fz_close_output(ctx, out);
  498. }
  499. fz_always(ctx)
  500. {
  501. fz_drop_output(ctx, out2);
  502. fz_drop_output(ctx, out);
  503. }
  504. fz_catch(ctx)
  505. {
  506. fz_drop_compressed_buffer(ctx, cbuf);
  507. fz_rethrow(ctx);
  508. }
  509. cbuf->params.type = FZ_IMAGE_FLATE;
  510. cbuf->params.u.flate.bpc = 8;
  511. cbuf->params.u.flate.colors = 0;
  512. cbuf->params.u.flate.predictor = 0;
  513. cbuf->params.u.flate.columns = 0;
  514. return cbuf;
  515. }
  516. static fz_compressed_buffer *
  517. fz_recompress_image_as_fax(fz_context *ctx, fz_pixmap *pix)
  518. {
  519. /* FIXME: Should get default colorspaces from the doc! */
  520. fz_default_colorspaces *defcs = fz_new_default_colorspaces(ctx);
  521. fz_compressed_buffer *cbuf = NULL;
  522. fz_halftone *ht = NULL;
  523. fz_bitmap *bmp = NULL;
  524. fz_buffer *inv_buffer = NULL;
  525. fz_var(ht);
  526. fz_var(bmp);
  527. fz_var(cbuf);
  528. fz_var(inv_buffer);
  529. fz_keep_pixmap(ctx, pix);
  530. fz_try(ctx)
  531. {
  532. /* Convert to alphaless grey */
  533. if (pix->n != 1)
  534. {
  535. fz_pixmap *pix2 = fz_convert_pixmap(ctx, pix, fz_device_gray(ctx), NULL, defcs, fz_default_color_params, 0);
  536. fz_drop_pixmap(ctx, pix);
  537. pix = pix2;
  538. }
  539. /* Convert to a bitmap */
  540. ht = fz_default_halftone(ctx, 1);
  541. bmp = fz_new_bitmap_from_pixmap(ctx, pix, ht);
  542. cbuf = fz_new_compressed_buffer(ctx);
  543. cbuf->buffer = fz_compress_ccitt_fax_g4(ctx, bmp->samples, bmp->w, bmp->h, bmp->stride);
  544. cbuf->params.type = FZ_IMAGE_FAX;
  545. cbuf->params.u.fax.k = -1;
  546. cbuf->params.u.fax.columns = pix->w;
  547. cbuf->params.u.fax.rows = pix->h;
  548. fz_invert_bitmap(ctx, bmp);
  549. inv_buffer = fz_compress_ccitt_fax_g4(ctx, bmp->samples, bmp->w, bmp->h, bmp->stride);
  550. /* cbuf->buffer requires "/BlackIs1 true ", so it needs to beats the inverted one by
  551. * at least 15 bytes, or we'll use the inverted one. */
  552. if (cbuf->buffer->len + 15 < inv_buffer->len)
  553. {
  554. cbuf->params.u.fax.black_is_1 = 1;
  555. }
  556. else
  557. {
  558. fz_drop_buffer(ctx, cbuf->buffer);
  559. cbuf->buffer = inv_buffer;
  560. inv_buffer = NULL;
  561. }
  562. }
  563. fz_always(ctx)
  564. {
  565. fz_drop_bitmap(ctx, bmp);
  566. fz_drop_halftone(ctx, ht);
  567. fz_drop_pixmap(ctx, pix);
  568. fz_drop_buffer(ctx, inv_buffer);
  569. fz_drop_default_colorspaces(ctx, defcs);
  570. }
  571. fz_catch(ctx)
  572. {
  573. fz_drop_compressed_buffer(ctx, cbuf);
  574. fz_rethrow(ctx);
  575. }
  576. return cbuf;
  577. }
  578. static int method_from_fmt(int fmt)
  579. {
  580. switch (fmt)
  581. {
  582. case FZ_IMAGE_JPEG:
  583. return FZ_RECOMPRESS_JPEG;
  584. case FZ_IMAGE_JPX:
  585. return FZ_RECOMPRESS_J2K;
  586. case FZ_IMAGE_FAX:
  587. return FZ_RECOMPRESS_FAX;
  588. }
  589. return FZ_RECOMPRESS_LOSSLESS;
  590. }
  591. static fz_image *
  592. recompress_image(fz_context *ctx, fz_pixmap *pix, int type, int fmt, int method, const char *quality, fz_image *oldimg)
  593. {
  594. int interpolate = oldimg->interpolate;
  595. fz_compressed_buffer *cbuf = NULL;
  596. fz_colorspace *cs = pix->colorspace;
  597. int bpc = 8;
  598. if (method == FZ_RECOMPRESS_NEVER)
  599. return NULL;
  600. if (method == FZ_RECOMPRESS_SAME)
  601. method = method_from_fmt(fmt);
  602. if (method == FZ_RECOMPRESS_J2K)
  603. cbuf = fz_recompress_image_as_j2k(ctx, pix, quality);
  604. if (method == FZ_RECOMPRESS_JPEG)
  605. cbuf = fz_recompress_image_as_jpeg(ctx, pix, quality, &cs);
  606. if (method == FZ_RECOMPRESS_FAX)
  607. {
  608. cbuf = fz_recompress_image_as_fax(ctx, pix);
  609. if (cbuf)
  610. {
  611. bpc = 1;
  612. cs = fz_device_gray(ctx);
  613. }
  614. }
  615. if (cbuf == NULL)
  616. cbuf = fz_recompress_image_as_flate(ctx, pix, quality);
  617. if (cbuf == NULL)
  618. return NULL;
  619. /* fz_new_image_from_compressed_buffer takes ownership of compressed buffer, even
  620. * in failure case. */
  621. return fz_new_image_from_compressed_buffer(ctx, pix->w, pix->h, bpc, cs, pix->xres, pix->yres, interpolate, 0, NULL, NULL, cbuf, oldimg->mask);
  622. }
  623. static void
  624. do_image_rewrite(fz_context *ctx, void *opaque, fz_image **image, fz_matrix ctm, pdf_obj *im_obj)
  625. {
  626. image_info *info = (image_info *)opaque;
  627. image_list *ilist = &info->list;
  628. unique_image_list *uilist = &info->uilist;
  629. float dpi;
  630. fz_pixmap *pix;
  631. fz_pixmap *newpix = NULL;
  632. image_type type;
  633. int fmt = fz_compressed_image_type(ctx, *image);
  634. int lossy = fmt_is_lossy(fmt);
  635. size_t orig_len = pdf_dict_get_int64(ctx, im_obj, PDF_NAME(Length));
  636. /* FIXME: We don't recompress im_obj->mask! */
  637. /* Can't recompress colorkeyed images, currently. */
  638. if ((*image)->use_colorkey)
  639. return;
  640. /* Can't recompress scalable images. */
  641. if ((*image)->scalable)
  642. return;
  643. /* Can't rewrite separation ones, currently, as we can't pdf_add_image a separation image. */
  644. if (fz_colorspace_is_indexed(ctx, (*image)->colorspace) &&
  645. fz_colorspace_is_device_n(ctx, (*image)->colorspace->u.indexed.base))
  646. return;
  647. if (fz_colorspace_is_device_n(ctx, (*image)->colorspace))
  648. return;
  649. if (im_obj == NULL)
  650. dpi = dpi_from_ctm(ctm, (*image)->w, (*image)->h);
  651. else
  652. dpi = uilist->img[ilist->uimg[info->which++]].dpi;
  653. /* What sort of image is this? */
  654. pix = fz_get_pixmap_from_image(ctx, *image, NULL, NULL, NULL, NULL);
  655. type = classify_pixmap(ctx, pix);
  656. fz_var(newpix);
  657. fz_try(ctx)
  658. {
  659. fz_image *newimg = NULL;
  660. if (type == IMAGE_BITONAL &&
  661. info->opts->bitonal_image_recompress_method != FZ_RECOMPRESS_NEVER &&
  662. info->opts->bitonal_image_subsample_threshold != 0 &&
  663. dpi > info->opts->bitonal_image_subsample_threshold)
  664. {
  665. /* Resample a bitonal image. */
  666. newpix = resample(ctx, pix, info->opts->bitonal_image_subsample_method, dpi, info->opts->bitonal_image_subsample_to);
  667. }
  668. else if (type == IMAGE_COLOR && lossy &&
  669. info->opts->color_lossy_image_recompress_method != FZ_RECOMPRESS_NEVER &&
  670. info->opts->color_lossy_image_subsample_threshold != 0 &&
  671. dpi > info->opts->color_lossy_image_subsample_threshold)
  672. {
  673. /* Resample a lossily encoded color image. */
  674. newpix = resample(ctx, pix, info->opts->color_lossy_image_subsample_method, dpi, info->opts->color_lossy_image_subsample_to);
  675. }
  676. else if (type == IMAGE_COLOR && !lossy &&
  677. info->opts->color_lossless_image_recompress_method != FZ_RECOMPRESS_NEVER &&
  678. info->opts->color_lossless_image_subsample_threshold != 0 &&
  679. dpi > info->opts->color_lossless_image_subsample_threshold)
  680. {
  681. /* Resample a losslessly color image. */
  682. newpix = resample(ctx, pix, info->opts->color_lossless_image_subsample_method, dpi, info->opts->color_lossless_image_subsample_to);
  683. }
  684. else if (type == IMAGE_GRAY && lossy &&
  685. info->opts->gray_lossy_image_recompress_method != FZ_RECOMPRESS_NEVER &&
  686. info->opts->gray_lossy_image_subsample_threshold != 0 &&
  687. dpi > info->opts->gray_lossy_image_subsample_threshold)
  688. {
  689. /* Resample a lossily encoded gray image. */
  690. newpix = resample(ctx, pix, info->opts->gray_lossy_image_subsample_method, dpi, info->opts->gray_lossy_image_subsample_to);
  691. }
  692. else if (type == IMAGE_GRAY && !lossy &&
  693. info->opts->gray_lossless_image_recompress_method != FZ_RECOMPRESS_NEVER &&
  694. info->opts->gray_lossless_image_subsample_threshold != 0 &&
  695. dpi > info->opts->gray_lossless_image_subsample_threshold)
  696. {
  697. /* Resample a losslessly encoded gray image. */
  698. newpix = resample(ctx, pix, info->opts->gray_lossless_image_subsample_method, dpi, info->opts->gray_lossless_image_subsample_to);
  699. }
  700. if (newpix)
  701. {
  702. /* We've scaled (or otherwise converted the image). So it needs to be compressed. */
  703. if (type == IMAGE_COLOR)
  704. {
  705. if (lossy)
  706. newimg = recompress_image(ctx, newpix, type, fmt, info->opts->color_lossy_image_recompress_method, info->opts->color_lossy_image_recompress_quality, *image);
  707. else
  708. newimg = recompress_image(ctx, newpix, type, fmt, info->opts->color_lossless_image_recompress_method, info->opts->color_lossless_image_recompress_quality, *image);
  709. }
  710. else if (type == IMAGE_GRAY)
  711. {
  712. if (lossy)
  713. newimg = recompress_image(ctx, newpix, type, fmt, info->opts->gray_lossy_image_recompress_method, info->opts->gray_lossy_image_recompress_quality, *image);
  714. else
  715. newimg = recompress_image(ctx, newpix, type, fmt, info->opts->gray_lossless_image_recompress_method, info->opts->gray_lossless_image_recompress_quality, *image);
  716. }
  717. else if (type == IMAGE_BITONAL)
  718. newimg = recompress_image(ctx, newpix, type, fmt, info->opts->bitonal_image_recompress_method, info->opts->bitonal_image_recompress_quality, *image);
  719. }
  720. else if (type == IMAGE_COLOR)
  721. {
  722. if (lossy)
  723. newimg = recompress_image(ctx, pix, type, fmt, info->opts->color_lossy_image_recompress_method, info->opts->color_lossy_image_recompress_quality, *image);
  724. else
  725. newimg = recompress_image(ctx, pix, type, fmt, info->opts->color_lossless_image_recompress_method, info->opts->color_lossless_image_recompress_quality, *image);
  726. }
  727. else if (type == IMAGE_GRAY)
  728. {
  729. if (lossy)
  730. newimg = recompress_image(ctx, pix, type, fmt, info->opts->gray_lossy_image_recompress_method, info->opts->gray_lossy_image_recompress_quality, *image);
  731. else
  732. newimg = recompress_image(ctx, pix, type, fmt, info->opts->gray_lossless_image_recompress_method, info->opts->gray_lossless_image_recompress_quality, *image);
  733. }
  734. else if (type == IMAGE_BITONAL)
  735. {
  736. newimg = recompress_image(ctx, pix, type, fmt, info->opts->bitonal_image_recompress_method, info->opts->bitonal_image_recompress_quality, *image);
  737. }
  738. if (newimg)
  739. {
  740. /* fz_image_size gives us the uncompressed size for losslessly compressed images
  741. * as the image holds the uncompressed buffer. But orig_len will be 0 for inline
  742. * images. So we have to combine the two. */
  743. size_t oldsize = fz_image_size(ctx, *image);
  744. size_t newsize = fz_image_size(ctx, newimg);
  745. if (orig_len != 0)
  746. oldsize = orig_len;
  747. if (oldsize <= newsize)
  748. {
  749. /* Old one was smaller! Don't mess with it. */
  750. fz_drop_image(ctx, newimg);
  751. }
  752. else
  753. {
  754. fz_drop_image(ctx, *image);
  755. *image = newimg;
  756. }
  757. }
  758. }
  759. fz_always(ctx)
  760. {
  761. fz_drop_pixmap(ctx, newpix);
  762. fz_drop_pixmap(ctx, pix);
  763. }
  764. fz_catch(ctx)
  765. {
  766. fz_rethrow(ctx);
  767. }
  768. }
  769. static void
  770. gather_image_info(fz_context *ctx, pdf_document *doc, int page_num, image_info *info)
  771. {
  772. pdf_page *page = pdf_load_page(ctx, doc, page_num);
  773. pdf_filter_options options = { 0 };
  774. pdf_filter_factory list[2] = { 0 };
  775. pdf_color_filter_options copts = { 0 };
  776. pdf_annot *annot;
  777. copts.opaque = info;
  778. copts.color_rewrite = NULL;
  779. copts.image_rewrite = gather_image_rewrite;
  780. copts.shade_rewrite = NULL;
  781. options.filters = list;
  782. options.recurse = 1;
  783. options.no_update = 1;
  784. list[0].filter = pdf_new_color_filter;
  785. list[0].options = &copts;
  786. fz_try(ctx)
  787. {
  788. pdf_filter_page_contents(ctx, doc, page, &options);
  789. for (annot = pdf_first_annot(ctx, page); annot != NULL; annot = pdf_next_annot(ctx, annot))
  790. pdf_filter_annot_contents(ctx, doc, annot, &options);
  791. for (annot = pdf_first_widget(ctx, page); annot != NULL; annot = pdf_next_annot(ctx, annot))
  792. pdf_filter_annot_contents(ctx, doc, annot, &options);
  793. }
  794. fz_always(ctx)
  795. fz_drop_page(ctx, &page->super);
  796. fz_catch(ctx)
  797. fz_rethrow(ctx);
  798. }
  799. static void
  800. rewrite_image_info(fz_context *ctx, pdf_document *doc, int page_num, image_info *info)
  801. {
  802. pdf_page *page = pdf_load_page(ctx, doc, page_num);
  803. pdf_filter_options options = { 0 };
  804. pdf_filter_factory list[2] = { 0 };
  805. pdf_color_filter_options copts = { 0 };
  806. pdf_annot *annot;
  807. copts.opaque = info;
  808. copts.color_rewrite = NULL;
  809. copts.image_rewrite = do_image_rewrite;
  810. copts.shade_rewrite = NULL;
  811. options.filters = list;
  812. options.recurse = 1;
  813. list[0].filter = pdf_new_color_filter;
  814. list[0].options = &copts;
  815. fz_try(ctx)
  816. {
  817. pdf_filter_page_contents(ctx, doc, page, &options);
  818. for (annot = pdf_first_annot(ctx, page); annot != NULL; annot = pdf_next_annot(ctx, annot))
  819. pdf_filter_annot_contents(ctx, doc, annot, &options);
  820. for (annot = pdf_first_widget(ctx, page); annot != NULL; annot = pdf_next_annot(ctx, annot))
  821. pdf_filter_annot_contents(ctx, doc, annot, &options);
  822. }
  823. fz_always(ctx)
  824. fz_drop_page(ctx, &page->super);
  825. fz_catch(ctx)
  826. fz_rethrow(ctx);
  827. }
  828. void pdf_rewrite_images(fz_context *ctx, pdf_document *doc, pdf_image_rewriter_options *opts)
  829. {
  830. int i;
  831. int n = pdf_count_pages(ctx, doc);
  832. image_info info = { 0 };
  833. info.opts = opts;
  834. /* If nothing to do, do nothing! */
  835. if (opts->bitonal_image_subsample_threshold == 0 &&
  836. opts->gray_lossless_image_subsample_threshold == 0 &&
  837. opts->gray_lossy_image_subsample_threshold == 0 &&
  838. opts->color_lossless_image_subsample_threshold == 0 &&
  839. opts->color_lossy_image_subsample_threshold == 0 &&
  840. opts->bitonal_image_recompress_method == FZ_RECOMPRESS_NEVER &&
  841. opts->color_lossy_image_recompress_method == FZ_RECOMPRESS_NEVER &&
  842. opts->color_lossless_image_recompress_method == FZ_RECOMPRESS_NEVER &&
  843. opts->gray_lossy_image_recompress_method == FZ_RECOMPRESS_NEVER &&
  844. opts->gray_lossless_image_recompress_method == FZ_RECOMPRESS_NEVER)
  845. return;
  846. /* Pass 1: Gather information */
  847. for (i = 0; i < n; i++)
  848. {
  849. gather_image_info(ctx, doc, i, &info);
  850. }
  851. /* Pass 2: Resample as required */
  852. for (i = 0; i < n; i++)
  853. {
  854. rewrite_image_info(ctx, doc, i, &info);
  855. }
  856. fz_free(ctx, info.list.uimg);
  857. fz_free(ctx, info.uilist.img);
  858. }