static void fz_test_fill_image(fz_context *ctx, fz_device *dev_, fz_image *image, fz_matrix ctm, float alpha, const fz_color_params *color_params) { fz_test_device *dev = (fz_test_device*)dev_; while (dev->resolved == 0) /* So we can break out */ { fz_compressed_buffer *buffer; if (*dev->is_color || !image->colorspace || fz_colorspace_is_gray(ctx, image->colorspace)) break; if ((dev->options & FZ_TEST_OPT_IMAGES) == 0) { /* Don't test every pixel. Upgrade us from "black and white" to "probably color" */ if (*dev->is_color == 0) *dev->is_color = 1; dev->resolved = 1; if (dev->passthrough == NULL) fz_throw(ctx, FZ_ERROR_ABORT, "Page found as color; stopping interpretation"); break; } buffer = fz_compressed_image_buffer(ctx, image); if (buffer && image->bpc == 8) { fz_stream *stream = fz_open_compressed_buffer(ctx, buffer); fz_try(ctx) fz_test_fill_compressed_8bpc_image(ctx, dev, image, stream, color_params); fz_always(ctx) fz_drop_stream(ctx, stream); fz_catch(ctx) fz_rethrow(ctx); } else { fz_pixmap *pix = fz_get_pixmap_from_image(ctx, image, NULL, NULL, 0, 0); if (pix == NULL) /* Should never happen really, but... */ break; fz_try(ctx) fz_test_fill_other_image(ctx, dev, pix, color_params); fz_always(ctx) fz_drop_pixmap(ctx, pix); fz_catch(ctx) fz_rethrow(ctx); } break; } if (dev->passthrough) fz_fill_image(ctx, dev->passthrough, image, ctm, alpha, color_params); }
static void svg_dev_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha) { svg_device *sdev = (svg_device*)dev; fz_compressed_buffer *buffer; fz_output *out; fz_matrix local_ctm = *ctm; fz_matrix scale = { 0 }; int mask = sdev->id++; scale.a = 1.0f / image->w; scale.d = 1.0f / image->h; fz_concat(&local_ctm, &scale, ctm); out = start_def(ctx, sdev); fz_printf(ctx, out, "<mask id=\"ma%d\"><image", mask); fz_printf(ctx, out, " width=\"%dpx\" height=\"%dpx\" xlink:href=\"data:", image->w, image->h); buffer = fz_compressed_image_buffer(ctx, image); switch (buffer == NULL ? FZ_IMAGE_JPX : buffer->params.type) { case FZ_IMAGE_JPEG: fz_printf(ctx, out, "image/jpeg;base64,"); send_data_base64(ctx, out, buffer->buffer); break; case FZ_IMAGE_PNG: fz_printf(ctx, out, "image/png;base64,"); send_data_base64(ctx, out, buffer->buffer); break; default: { fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, image); fz_printf(ctx, out, "image/png;base64,"); send_data_base64(ctx, out, buf); fz_drop_buffer(ctx, buf); break; } } fz_printf(ctx, out, "\"/></mask>\n"); out = end_def(ctx, sdev); fz_printf(ctx, out, "<rect x=\"0\" y=\"0\" width=\"%d\" height=\"%d\"", image->w, image->h); svg_dev_fill_color(ctx, sdev, colorspace, color, alpha); svg_dev_ctm(ctx, sdev, &local_ctm); fz_printf(ctx, out, " mask=\"url(#ma%d)\"/>\n", mask); }
static void svg_dev_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha) { svg_device *sdev = (svg_device*)dev; fz_output *out = sdev->out; fz_compressed_buffer *buffer; fz_matrix local_ctm = *ctm; fz_matrix scale = { 0 }; scale.a = 1.0f / image->w; scale.d = 1.0f / image->h; fz_concat(&local_ctm, &scale, ctm); if (alpha != 1.0f) fz_printf(ctx, out, "<g opacity=\"%g\">", alpha); fz_printf(ctx, out, "<image"); svg_dev_ctm(ctx, sdev, &local_ctm); buffer = fz_compressed_image_buffer(ctx, image); fz_printf(ctx, out, " width=\"%dpx\" height=\"%dpx\" xlink:href=\"data:", image->w, image->h); switch (buffer == NULL ? FZ_IMAGE_JPX : buffer->params.type) { case FZ_IMAGE_JPEG: fz_printf(ctx, out, "image/jpeg;base64,"); send_data_base64(ctx, out, buffer->buffer); break; case FZ_IMAGE_PNG: fz_printf(ctx, out, "image/png;base64,"); send_data_base64(ctx, out, buffer->buffer); break; default: { fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, image); fz_printf(ctx, out, "image/png;base64,"); send_data_base64(ctx, out, buf); fz_drop_buffer(ctx, buf); break; } } fz_printf(ctx, out, "\"/>\n"); if (alpha != 1.0f) fz_printf(ctx, out, "</g>"); }
static void fz_test_fill_image(fz_context *ctx, fz_device *dev_, fz_image *image, const fz_matrix *ctm, float alpha, const fz_color_params *color_params) { fz_test_device *dev = (fz_test_device*)dev_; while (dev->resolved == 0) /* So we can break out */ { fz_pixmap *pix; unsigned int count, i, k, h, sa, ss; unsigned char *s; fz_compressed_buffer *buffer; if (*dev->is_color || !image->colorspace || fz_colorspace_is_gray(ctx, image->colorspace)) break; if ((dev->options & FZ_TEST_OPT_IMAGES) == 0) { /* Don't test every pixel. Upgrade us from "black and white" to "probably color" */ if (*dev->is_color == 0) *dev->is_color = 1; dev->resolved = 1; if (dev->passthrough == NULL) fz_throw(ctx, FZ_ERROR_ABORT, "Page found as color; stopping interpretation"); break; } buffer = fz_compressed_image_buffer(ctx, image); if (buffer && image->bpc == 8) { fz_stream *stream = fz_open_compressed_buffer(ctx, buffer); count = (unsigned int)image->w * (unsigned int)image->h; if (image->colorspace == fz_device_rgb(ctx)) { int threshold_u8 = dev->threshold * 255; for (i = 0; i < count; i++) { int r = fz_read_byte(ctx, stream); int g = fz_read_byte(ctx, stream); int b = fz_read_byte(ctx, stream); if (is_rgb_color_u8(threshold_u8, r, g, b)) { *dev->is_color = 1; dev->resolved = 1; fz_drop_stream(ctx, stream); if (dev->passthrough == NULL) fz_throw(ctx, FZ_ERROR_ABORT, "Page found as color; stopping interpretation"); break; } } } else { fz_color_converter cc; unsigned int n = (unsigned int)image->n; fz_init_cached_color_converter(ctx, &cc, NULL, fz_device_rgb(ctx), image->colorspace, color_params); fz_try(ctx) { for (i = 0; i < count; i++) { float cs[FZ_MAX_COLORS]; float ds[FZ_MAX_COLORS]; for (k = 0; k < n; k++) cs[k] = fz_read_byte(ctx, stream) / 255.0f; cc.convert(ctx, &cc, ds, cs); if (is_rgb_color(dev->threshold, ds[0], ds[1], ds[2])) { *dev->is_color = 1; dev->resolved = 1; if (dev->passthrough == NULL) { fz_drop_stream(ctx, stream); fz_fin_cached_color_converter(ctx, &cc); fz_throw(ctx, FZ_ERROR_ABORT, "Page found as color; stopping interpretation"); } break; } } } fz_always(ctx) fz_fin_cached_color_converter(ctx, &cc); fz_catch(ctx) fz_rethrow(ctx); } fz_drop_stream(ctx, stream); break; } pix = fz_get_pixmap_from_image(ctx, image, NULL, NULL, 0, 0); if (pix == NULL) /* Should never happen really, but... */ break; count = pix->w; h = pix->h; s = pix->samples; sa = pix->alpha; ss = pix->stride - pix->w * pix->n; if (pix->colorspace == fz_device_rgb(ctx)) { int threshold_u8 = dev->threshold * 255; while (h--) { for (i = 0; i < count; i++) { if ((!sa || s[3] != 0) && is_rgb_color_u8(threshold_u8, s[0], s[1], s[2])) { *dev->is_color = 1; dev->resolved = 1; if (dev->passthrough == NULL) { fz_drop_pixmap(ctx, pix); fz_throw(ctx, FZ_ERROR_ABORT, "Page found as color; stopping interpretation"); } break; } s += 3 + sa; } s += ss; } } else { fz_color_converter cc; unsigned int n = (unsigned int)pix->n-1; fz_init_cached_color_converter(ctx, &cc, NULL, fz_device_rgb(ctx), pix->colorspace, color_params); fz_try(ctx) { while (h--) { for (i = 0; i < count; i++) { float cs[FZ_MAX_COLORS]; float ds[FZ_MAX_COLORS]; for (k = 0; k < n; k++) cs[k] = (*s++) / 255.0f; if (sa && *s++ == 0) continue; cc.convert(ctx, &cc, ds, cs); if (is_rgb_color(dev->threshold, ds[0], ds[1], ds[2])) { *dev->is_color = 1; dev->resolved = 1; if (dev->passthrough == NULL) { fz_fin_cached_color_converter(ctx, &cc); fz_drop_pixmap(ctx, pix); fz_throw(ctx, FZ_ERROR_ABORT, "Page found as color; stopping interpretation"); } break; } } s += ss; } } fz_always(ctx) fz_fin_cached_color_converter(ctx, &cc); fz_catch(ctx) fz_rethrow(ctx); } fz_drop_pixmap(ctx, pix); break; }
static void pdf_out_BI(fz_context *ctx, pdf_processor *proc, fz_image *img) { fz_output *out = ((pdf_output_processor*)proc)->out; int ahx = ((pdf_output_processor*)proc)->ahxencode; fz_compressed_buffer *cbuf; fz_buffer *buf; int i; if (img == NULL) return; cbuf = fz_compressed_image_buffer(ctx, img); if (cbuf == NULL) return; buf = cbuf->buffer; if (buf == NULL) return; fz_printf(ctx, out, "BI\n"); fz_printf(ctx, out, "/W %d\n", img->w); fz_printf(ctx, out, "/H %d\n", img->h); fz_printf(ctx, out, "/BPC %d\n", img->bpc); if (img->imagemask) fz_printf(ctx, out, "/IM true\n"); else if (img->colorspace == fz_device_gray(ctx)) fz_printf(ctx, out, "/CS/G\n"); else if (img->colorspace == fz_device_rgb(ctx)) fz_printf(ctx, out, "/CS/RGB\n"); else if (img->colorspace == fz_device_cmyk(ctx)) fz_printf(ctx, out, "/CS/CMYK\n"); else if (fz_colorspace_is_indexed(ctx, img->colorspace)) fz_printf(ctx, out, "/CS/I\n"); if (img->interpolate) fz_printf(ctx, out, "/I true\n"); fz_printf(ctx, out, "/D["); for (i = 0; i < img->n * 2; ++i) { if (i > 0) fz_putc(ctx, out, ' '); fz_printf(ctx, out, "%g", img->decode[i]); } fz_printf(ctx, out, "]\n"); switch (cbuf->params.type) { default: fz_throw(ctx, FZ_ERROR_GENERIC, "unknown compressed buffer type"); break; case FZ_IMAGE_JPEG: fz_printf(ctx, out, ahx ? "/F[/AHx/DCT]\n" : "/F/DCT\n"); if (cbuf->params.u.jpeg.color_transform != -1) fz_printf(ctx, out, "/DP<</ColorTransform %d>>\n", cbuf->params.u.jpeg.color_transform); break; case FZ_IMAGE_FAX: fz_printf(ctx, out, ahx ? "/F[/AHx/CCF]\n/DP[null<<\n" : "/F/CCF\n/DP<<\n"); fz_printf(ctx, out, "/K %d\n", cbuf->params.u.fax.k); if (cbuf->params.u.fax.columns != 1728) fz_printf(ctx, out, "/Columns %d\n", cbuf->params.u.fax.columns); if (cbuf->params.u.fax.rows > 0) fz_printf(ctx, out, "/Rows %d\n", cbuf->params.u.fax.rows); if (cbuf->params.u.fax.end_of_line) fz_printf(ctx, out, "/EndOfLine true\n"); if (cbuf->params.u.fax.encoded_byte_align) fz_printf(ctx, out, "/EncodedByteAlign true\n"); if (!cbuf->params.u.fax.end_of_block) fz_printf(ctx, out, "/EndOfBlock false\n"); if (cbuf->params.u.fax.black_is_1) fz_printf(ctx, out, "/BlackIs1 true\n"); if (cbuf->params.u.fax.damaged_rows_before_error > 0) fz_printf(ctx, out, "/DamagedRowsBeforeError %d\n", cbuf->params.u.fax.damaged_rows_before_error); fz_printf(ctx, out, ahx ? ">>]\n" : ">>\n"); break; case FZ_IMAGE_RAW: if (ahx) fz_printf(ctx, out, "/F/AHx\n"); break; case FZ_IMAGE_RLD: fz_printf(ctx, out, ahx ? "/F[/AHx/RL]\n" : "/F/RL\n"); break; case FZ_IMAGE_FLATE: fz_printf(ctx, out, ahx ? "/F[/AHx/Fl]\n" : "/F/Fl\n"); if (cbuf->params.u.flate.predictor > 1) { fz_printf(ctx, out, ahx ? "/DP[null<<\n" : "/DP<<\n"); fz_printf(ctx, out, "/Predictor %d\n", cbuf->params.u.flate.predictor); if (cbuf->params.u.flate.columns != 1) fz_printf(ctx, out, "/Columns %d\n", cbuf->params.u.flate.columns); if (cbuf->params.u.flate.colors != 1) fz_printf(ctx, out, "/Colors %d\n", cbuf->params.u.flate.colors); if (cbuf->params.u.flate.bpc != 8) fz_printf(ctx, out, "/BitsPerComponent %d\n", cbuf->params.u.flate.bpc); fz_printf(ctx, out, ahx ? ">>]\n" : ">>\n"); } break; case FZ_IMAGE_LZW: fz_printf(ctx, out, ahx ? "/F[/AHx/LZW]\n" : "/F/LZW\n"); if (cbuf->params.u.lzw.predictor > 1) { fz_printf(ctx, out, ahx ? "/DP[<<null\n" : "/DP<<\n"); fz_printf(ctx, out, "/Predictor %d\n", cbuf->params.u.lzw.predictor); if (cbuf->params.u.lzw.columns != 1) fz_printf(ctx, out, "/Columns %d\n", cbuf->params.u.lzw.columns); if (cbuf->params.u.lzw.colors != 1) fz_printf(ctx, out, "/Colors %d\n", cbuf->params.u.lzw.colors); if (cbuf->params.u.lzw.bpc != 8) fz_printf(ctx, out, "/BitsPerComponent %d\n", cbuf->params.u.lzw.bpc); if (cbuf->params.u.lzw.early_change != 1) fz_printf(ctx, out, "/EarlyChange %d\n", cbuf->params.u.lzw.early_change); fz_printf(ctx, out, ahx ? ">>]\n" : ">>\n"); } break; } fz_printf(ctx, out, "ID\n"); if (ahx) { size_t z; for (z = 0; z < buf->len; ++z) { int c = buf->data[z]; fz_putc(ctx, out, "0123456789abcdef"[(c >> 4) & 0xf]); fz_putc(ctx, out, "0123456789abcdef"[c & 0xf]); if ((z & 31) == 31) fz_putc(ctx, out, '\n'); } fz_putc(ctx, out, '>'); } else {
void fz_print_stext_page_html(fz_context *ctx, fz_output *out, fz_stext_page *page) { int block_n, line_n, ch_n; fz_stext_style *style = NULL; fz_stext_line *line; fz_stext_span *span; void *last_region = NULL; fz_printf(ctx, out, "<div class=\"page\">\n"); for (block_n = 0; block_n < page->len; block_n++) { switch (page->blocks[block_n].type) { case FZ_PAGE_BLOCK_TEXT: { fz_stext_block * block = page->blocks[block_n].u.text; fz_printf(ctx, out, "<div class=\"block\"><p>\n"); for (line_n = 0; line_n < block->len; line_n++) { int lastcol=-1; line = &block->lines[line_n]; style = NULL; if (line->region != last_region) { if (last_region) fz_printf(ctx, out, "</div>"); fz_printf(ctx, out, "<div class=\"metaline\">"); last_region = line->region; } fz_printf(ctx, out, "<div class=\"line\""); #ifdef DEBUG_INTERNALS if (line->region) fz_printf(ctx, out, " region=\"%x\"", line->region); #endif fz_printf(ctx, out, ">"); for (span = line->first_span; span; span = span->next) { float size = fz_matrix_expansion(&span->transform); float base_offset = span->base_offset / size; if (lastcol != span->column) { if (lastcol >= 0) { fz_printf(ctx, out, "</div>"); } /* If we skipped any columns then output some spacer spans */ while (lastcol < span->column-1) { fz_printf(ctx, out, "<div class=\"cell\"></div>"); lastcol++; } lastcol++; /* Now output the span to contain this entire column */ fz_printf(ctx, out, "<div class=\"cell\" style=\""); { fz_stext_span *sn; for (sn = span->next; sn; sn = sn->next) { if (sn->column != lastcol) break; } fz_printf(ctx, out, "width:%g%%;align:%s", span->column_width, (span->align == 0 ? "left" : (span->align == 1 ? "center" : "right"))); } if (span->indent > 1) fz_printf(ctx, out, ";padding-left:1em;text-indent:-1em"); if (span->indent < -1) fz_printf(ctx, out, ";text-indent:1em"); fz_printf(ctx, out, "\">"); } #ifdef DEBUG_INTERNALS fz_printf(ctx, out, "<span class=\"internal_span\""); if (span->column) fz_printf(ctx, out, " col=\"%x\"", span->column); fz_printf(ctx, out, ">"); #endif if (span->spacing >= 1) fz_printf(ctx, out, " "); if (base_offset > SUBSCRIPT_OFFSET) fz_printf(ctx, out, "<sub>"); else if (base_offset < SUPERSCRIPT_OFFSET) fz_printf(ctx, out, "<sup>"); for (ch_n = 0; ch_n < span->len; ch_n++) { fz_stext_char *ch = &span->text[ch_n]; if (style != ch->style) { if (style) fz_print_style_end(ctx, out, style); fz_print_style_begin(ctx, out, ch->style); style = ch->style; } if (ch->c == '<') fz_printf(ctx, out, "<"); else if (ch->c == '>') fz_printf(ctx, out, ">"); else if (ch->c == '&') fz_printf(ctx, out, "&"); else if (ch->c >= 32 && ch->c <= 127) fz_printf(ctx, out, "%c", ch->c); else fz_printf(ctx, out, "&#x%x;", ch->c); } if (style) { fz_print_style_end(ctx, out, style); style = NULL; } if (base_offset > SUBSCRIPT_OFFSET) fz_printf(ctx, out, "</sub>"); else if (base_offset < SUPERSCRIPT_OFFSET) fz_printf(ctx, out, "</sup>"); #ifdef DEBUG_INTERNALS fz_printf(ctx, out, "</span>"); #endif } /* Close our floating span */ fz_printf(ctx, out, "</div>"); /* Close the line */ fz_printf(ctx, out, "</div>"); fz_printf(ctx, out, "\n"); } /* Close the metaline */ fz_printf(ctx, out, "</div>"); last_region = NULL; fz_printf(ctx, out, "</p></div>\n"); break; } case FZ_PAGE_BLOCK_IMAGE: { fz_image_block *image = page->blocks[block_n].u.image; fz_compressed_buffer *buffer = fz_compressed_image_buffer(ctx, image->image); fz_printf(ctx, out, "<img width=%d height=%d src=\"data:", image->image->w, image->image->h); switch (buffer == NULL ? FZ_IMAGE_JPX : buffer->params.type) { case FZ_IMAGE_JPEG: fz_printf(ctx, out, "image/jpeg;base64,"); send_data_base64_stext(ctx, out, buffer->buffer); break; case FZ_IMAGE_PNG: fz_printf(ctx, out, "image/png;base64,"); send_data_base64_stext(ctx, out, buffer->buffer); break; default: { fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, image->image); fz_printf(ctx, out, "image/png;base64,"); send_data_base64_stext(ctx, out, buf); fz_drop_buffer(ctx, buf); break; } } fz_printf(ctx, out, "\">\n"); break; } } } fz_printf(ctx, out, "</div>\n"); }
pdf_obj * pdf_add_image(fz_context *ctx, pdf_document *doc, fz_image *image) { fz_pixmap *pixmap = NULL; pdf_obj *imobj = NULL; pdf_obj *dp; fz_buffer *buffer = NULL; pdf_obj *imref = NULL; fz_compressed_buffer *cbuffer; unsigned char digest[16]; int i, n; /* If we can maintain compression, do so */ cbuffer = fz_compressed_image_buffer(ctx, image); fz_var(pixmap); fz_var(buffer); fz_var(imobj); fz_var(imref); /* Check if the same image already exists in this doc. */ imref = pdf_find_image_resource(ctx, doc, image, digest); if (imref) return imref; imobj = pdf_add_new_dict(ctx, doc, 3); fz_try(ctx) { dp = pdf_dict_put_dict(ctx, imobj, PDF_NAME(DecodeParms), 3); pdf_dict_put(ctx, imobj, PDF_NAME(Type), PDF_NAME(XObject)); pdf_dict_put(ctx, imobj, PDF_NAME(Subtype), PDF_NAME(Image)); if (cbuffer) { fz_compression_params *cp = &cbuffer->params; switch (cp ? cp->type : FZ_IMAGE_UNKNOWN) { default: goto raw_or_unknown_compression; case FZ_IMAGE_JPEG: if (cp->u.jpeg.color_transform != -1) pdf_dict_put_int(ctx, dp, PDF_NAME(ColorTransform), cp->u.jpeg.color_transform); pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(DCTDecode)); break; case FZ_IMAGE_JPX: if (cp->u.jpx.smask_in_data) pdf_dict_put_int(ctx, dp, PDF_NAME(SMaskInData), cp->u.jpx.smask_in_data); pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(JPXDecode)); break; case FZ_IMAGE_FAX: if (cp->u.fax.columns) pdf_dict_put_int(ctx, dp, PDF_NAME(Columns), cp->u.fax.columns); if (cp->u.fax.rows) pdf_dict_put_int(ctx, dp, PDF_NAME(Rows), cp->u.fax.rows); if (cp->u.fax.k) pdf_dict_put_int(ctx, dp, PDF_NAME(K), cp->u.fax.k); if (cp->u.fax.end_of_line) pdf_dict_put_bool(ctx, dp, PDF_NAME(EndOfLine), cp->u.fax.end_of_line); if (cp->u.fax.encoded_byte_align) pdf_dict_put_bool(ctx, dp, PDF_NAME(EncodedByteAlign), cp->u.fax.encoded_byte_align); if (cp->u.fax.end_of_block) pdf_dict_put_bool(ctx, dp, PDF_NAME(EndOfBlock), cp->u.fax.end_of_block); if (cp->u.fax.black_is_1) pdf_dict_put_bool(ctx, dp, PDF_NAME(BlackIs1), cp->u.fax.black_is_1); if (cp->u.fax.damaged_rows_before_error) pdf_dict_put_int(ctx, dp, PDF_NAME(DamagedRowsBeforeError), cp->u.fax.damaged_rows_before_error); pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(CCITTFaxDecode)); break; case FZ_IMAGE_FLATE: if (cp->u.flate.columns) pdf_dict_put_int(ctx, dp, PDF_NAME(Columns), cp->u.flate.columns); if (cp->u.flate.colors) pdf_dict_put_int(ctx, dp, PDF_NAME(Colors), cp->u.flate.colors); if (cp->u.flate.predictor) pdf_dict_put_int(ctx, dp, PDF_NAME(Predictor), cp->u.flate.predictor); if (cp->u.flate.bpc) pdf_dict_put_int(ctx, dp, PDF_NAME(BitsPerComponent), cp->u.flate.bpc); pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(FlateDecode)); pdf_dict_put_int(ctx, imobj, PDF_NAME(BitsPerComponent), image->bpc); break; case FZ_IMAGE_LZW: if (cp->u.lzw.columns) pdf_dict_put_int(ctx, dp, PDF_NAME(Columns), cp->u.lzw.columns); if (cp->u.lzw.colors) pdf_dict_put_int(ctx, dp, PDF_NAME(Colors), cp->u.lzw.colors); if (cp->u.lzw.predictor) pdf_dict_put_int(ctx, dp, PDF_NAME(Predictor), cp->u.lzw.predictor); if (cp->u.lzw.early_change) pdf_dict_put_int(ctx, dp, PDF_NAME(EarlyChange), cp->u.lzw.early_change); if (cp->u.lzw.bpc) pdf_dict_put_int(ctx, dp, PDF_NAME(BitsPerComponent), cp->u.lzw.bpc); pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(LZWDecode)); break; case FZ_IMAGE_RLD: pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(RunLengthDecode)); break; } if (!pdf_dict_len(ctx, dp)) pdf_dict_del(ctx, imobj, PDF_NAME(DecodeParms)); buffer = fz_keep_buffer(ctx, cbuffer->buffer); if (image->use_decode) { pdf_obj *ary = pdf_dict_put_array(ctx, imobj, PDF_NAME(Decode), image->n * 2); for (i = 0; i < image->n * 2; ++i) pdf_array_push_real(ctx, ary, image->decode[i]); } } else { unsigned int size; int h; unsigned char *d, *s; raw_or_unknown_compression: /* Currently, set to maintain resolution; should we consider * subsampling here according to desired output res? */ pixmap = fz_get_pixmap_from_image(ctx, image, NULL, NULL, NULL, NULL); n = pixmap->n - pixmap->alpha - pixmap->s; /* number of colorants */ if (n == 0) n = 1; /* treat pixmaps with only alpha or spots as grayscale */ size = image->w * n; h = image->h; s = pixmap->samples; d = fz_malloc(ctx, size * h); buffer = fz_new_buffer_from_data(ctx, d, size * h); if (n == pixmap->n) { /* If we use all channels, we can copy the data as is. */ while (h--) { memcpy(d, s, size); d += size; s += pixmap->stride; } } else { /* Need to remove the alpha and spot planes. */ /* TODO: extract alpha plane to a soft mask. */ /* TODO: convert spots to colors. */ int line_skip = pixmap->stride - pixmap->w * pixmap->n; int skip = pixmap->n - n; while (h--) { int w = pixmap->w; while (w--) { int k; for (k = 0; k < n; ++k) *d++ = *s++; s += skip; } s += line_skip; } } } pdf_dict_put_int(ctx, imobj, PDF_NAME(Width), pixmap ? pixmap->w : image->w); pdf_dict_put_int(ctx, imobj, PDF_NAME(Height), pixmap ? pixmap->h : image->h); if (image->imagemask) { pdf_dict_put_bool(ctx, imobj, PDF_NAME(ImageMask), 1); } else { fz_colorspace *cs; pdf_dict_put_int(ctx, imobj, PDF_NAME(BitsPerComponent), image->bpc); cs = pixmap ? pixmap->colorspace : image->colorspace; switch (fz_colorspace_type(ctx, cs)) { case FZ_COLORSPACE_INDEXED: { fz_colorspace *basecs; unsigned char *lookup = NULL; int high = 0; int basen; pdf_obj *arr; lookup = fz_indexed_colorspace_palette(ctx, cs, &high); basecs = fz_colorspace_base(ctx, cs); basen = fz_colorspace_n(ctx, basecs); arr = pdf_dict_put_array(ctx, imobj, PDF_NAME(ColorSpace), 4); pdf_array_push(ctx, arr, PDF_NAME(Indexed)); switch (fz_colorspace_type(ctx, basecs)) { case FZ_COLORSPACE_GRAY: pdf_array_push(ctx, arr, PDF_NAME(DeviceGray)); break; case FZ_COLORSPACE_RGB: pdf_array_push(ctx, arr, PDF_NAME(DeviceRGB)); break; case FZ_COLORSPACE_CMYK: pdf_array_push(ctx, arr, PDF_NAME(DeviceCMYK)); break; default: // TODO: convert to RGB! fz_throw(ctx, FZ_ERROR_GENERIC, "only indexed Gray, RGB, and CMYK colorspaces supported"); break; } pdf_array_push_int(ctx, arr, high); pdf_array_push_string(ctx, arr, (char *) lookup, basen * (high + 1)); } break; case FZ_COLORSPACE_NONE: case FZ_COLORSPACE_GRAY: pdf_dict_put(ctx, imobj, PDF_NAME(ColorSpace), PDF_NAME(DeviceGray)); break; case FZ_COLORSPACE_RGB: pdf_dict_put(ctx, imobj, PDF_NAME(ColorSpace), PDF_NAME(DeviceRGB)); break; case FZ_COLORSPACE_CMYK: pdf_dict_put(ctx, imobj, PDF_NAME(ColorSpace), PDF_NAME(DeviceCMYK)); break; default: // TODO: convert to RGB! fz_throw(ctx, FZ_ERROR_GENERIC, "only Gray, RGB, and CMYK colorspaces supported"); break; } } if (image->mask) { pdf_dict_put_drop(ctx, imobj, PDF_NAME(SMask), pdf_add_image(ctx, doc, image->mask)); } pdf_update_stream(ctx, doc, imobj, buffer, 1); /* Add ref to our image resource hash table. */ imref = pdf_insert_image_resource(ctx, doc, digest, imobj); } fz_always(ctx) { fz_drop_pixmap(ctx, pixmap); fz_drop_buffer(ctx, buffer); pdf_drop_obj(ctx, imobj); } fz_catch(ctx) fz_rethrow(ctx); return imref; }