int xps_decode_jpeg(xps_context_t *ctx, byte *rbuf, int rlen, xps_image_t *image) { jpeg_decompress_data jddp; stream_DCT_state state; stream_cursor_read rp; stream_cursor_write wp; int code; int wlen; byte *wbuf; jpeg_saved_marker_ptr curr_marker; s_init_state((stream_state*)&state, &s_DCTD_template, ctx->memory); state.report_error = xps_report_error; s_DCTD_template.set_defaults((stream_state*)&state); state.jpeg_memory = ctx->memory; state.data.decompress = &jddp; jddp.templat = s_DCTD_template; jddp.memory = ctx->memory; jddp.scanline_buffer = NULL; if ((code = gs_jpeg_create_decompress(&state)) < 0) return gs_throw(-1, "cannot gs_jpeg_create_decompress"); s_DCTD_template.init((stream_state*)&state); rp.ptr = rbuf - 1; rp.limit = rbuf + rlen - 1; /* read the header only by not having a write buffer */ wp.ptr = 0; wp.limit = 0; /* Set up to save the ICC marker APP2. * According to the spec we should be getting APP1 APP2 and APP13. * Library gets APP0 and APP14. */ jpeg_save_markers(&(jddp.dinfo), 0xe2, 0xFFFF); code = s_DCTD_template.process((stream_state*)&state, &rp, &wp, true); if (code != 1) return gs_throw(-1, "premature EOF or error in jpeg"); /* Check if we had an ICC profile */ curr_marker = jddp.dinfo.marker_list; while (curr_marker != NULL) { if (curr_marker->marker == 0xe2) { /* Found ICC profile. Create a buffer and copy over now. * Strip JPEG APP2 14 byte header */ image->profilesize = curr_marker->data_length - 14; image->profile = xps_alloc(ctx, image->profilesize); if (image->profile) { /* If we can't create it, just ignore */ memcpy(image->profile, &(curr_marker->data[14]), image->profilesize); } break; } curr_marker = curr_marker->next; } image->width = jddp.dinfo.output_width; image->height = jddp.dinfo.output_height; image->comps = jddp.dinfo.output_components; image->bits = 8; image->stride = image->width * image->comps; if (image->comps == 1) image->colorspace = ctx->gray; if (image->comps == 3) image->colorspace = ctx->srgb; if (image->comps == 4) image->colorspace = ctx->cmyk; if (jddp.dinfo.density_unit == 1) { image->xres = jddp.dinfo.X_density; image->yres = jddp.dinfo.Y_density; } else if (jddp.dinfo.density_unit == 2) { image->xres = (int)(jddp.dinfo.X_density * 2.54 + 0.5); image->yres = (int)(jddp.dinfo.Y_density * 2.54 + 0.5); } else { image->xres = 96; image->yres = 96; } wlen = image->stride * image->height; wbuf = xps_alloc(ctx, wlen); if (!wbuf) return gs_throw1(gs_error_VMerror, "out of memory allocating samples: %d", wlen); image->samples = wbuf; wp.ptr = wbuf - 1; wp.limit = wbuf + wlen - 1; code = s_DCTD_template.process((stream_state*)&state, &rp, &wp, true); if (code != EOFC) return gs_throw1(-1, "error in jpeg (code = %d)", code); gs_jpeg_destroy(&state); return gs_okay; }
/* Send the page to the file. */ static int jbig2_print_page(gx_device_printer * pdev, FILE * prn_stream) { gx_device_jbig2 *jdev = (gx_device_jbig2 *) pdev; gs_memory_t *mem = jdev->memory; int line_size = gdev_mem_bytes_per_scan_line((gx_device *) pdev); byte *in = gs_alloc_bytes(mem, line_size, "jbig2_print_page(in)"); byte *fbuf = 0; uint fbuf_size; byte *jbuf = 0; uint jbuf_size; int lnum; int code = 0; stream_jbig2encode_state state; stream fstrm, cstrm; if (in == 0) { code = gs_note_error(gs_error_VMerror); goto fail; } /* Create the jbig2encode state. */ s_init_state((stream_state *)&state, &s_jbig2encode_template, 0); if (state.templat->set_defaults) (*state.templat->set_defaults) ((stream_state *) & state); state.width = jdev->width; state.height = jdev->height; /* Set up the streams. */ fbuf_size = max(512 /* arbitrary */ , state.templat->min_out_size); jbuf_size = state.templat->min_in_size; if ((fbuf = gs_alloc_bytes(mem, fbuf_size, "jbig2_print_page(fbuf)")) == 0 || (jbuf = gs_alloc_bytes(mem, jbuf_size, "jbig2_print_page(jbuf)")) == 0 ) { code = gs_note_error(gs_error_VMerror); goto done; } s_init(&fstrm, mem); swrite_file(&fstrm, prn_stream, fbuf, fbuf_size); s_init(&cstrm, mem); s_std_init(&cstrm, jbuf, jbuf_size, &s_filter_write_procs, s_mode_write); cstrm.state = (stream_state *) & state; cstrm.procs.process = state.templat->process; cstrm.strm = &fstrm; if (state.templat->init) (*state.templat->init) (cstrm.state); /* Copy the data to the output. */ for (lnum = 0; lnum < jdev->height; ++lnum) { byte *data; uint ignore_used; if (cstrm.end_status) { code = gs_note_error(gs_error_ioerror); goto done; } gdev_prn_get_bits(pdev, lnum, in, &data); sputs(&cstrm, data, state.stride, &ignore_used); } /* Wrap up. */ sclose(&cstrm); sflush(&fstrm); done: gs_free_object(mem, jbuf, "jbig2_print_page(jbuf)"); gs_free_object(mem, fbuf, "jbig2_print_page(fbuf)"); gs_free_object(mem, in, "jbig2_print_page(in)"); return code; fail: gs_free_object(mem, in, "jbig2_print_page(in)"); return code; }
/* Write the definition of a Type 1 font. */ int psf_write_type1_font(stream *s, gs_font_type1 *pfont, int options, gs_glyph *orig_subset_glyphs, uint orig_subset_size, const gs_const_string *alt_font_name, int lengths[3]) { stream *es = s; long start = stell(s); param_printer_params_t ppp; printer_param_list_t rlist; gs_param_list *const plist = (gs_param_list *)&rlist; stream AXE_stream; stream_AXE_state AXE_state; byte AXE_buf[200]; /* arbitrary */ stream exE_stream; stream_exE_state exE_state; byte exE_buf[200]; /* arbitrary */ psf_outline_glyphs_t glyphs; int lenIV = pfont->data.lenIV; int (*write_CharString)(stream *, const void *, uint) = stream_write; int code = psf_get_type1_glyphs(&glyphs, pfont, orig_subset_glyphs, orig_subset_size); if (code < 0) return code; /* Initialize the parameter printer. */ ppp = param_printer_params_default; ppp.item_suffix = " def\n"; ppp.print_ok = (options & WRITE_TYPE1_ASCIIHEX ? 0 : PRINT_BINARY_OK) | PRINT_HEX_NOT_OK; code = s_init_param_printer(&rlist, &ppp, s); if (code < 0) return code; /* Write the font header. */ stream_puts(s, "%!FontType1-1.0: "); write_font_name(s, pfont, alt_font_name, false); stream_puts(s, "\n11 dict begin\n"); /* Write FontInfo. */ stream_puts(s, "/FontInfo 5 dict dup begin"); { gs_font_info_t info; int code = pfont->procs.font_info((gs_font *)pfont, NULL, (FONT_INFO_COPYRIGHT | FONT_INFO_NOTICE | FONT_INFO_FAMILY_NAME | FONT_INFO_FULL_NAME), &info); if (code >= 0) { write_font_info(s, "Copyright", &info.Copyright, info.members & FONT_INFO_COPYRIGHT); write_font_info(s, "Notice", &info.Notice, info.members & FONT_INFO_NOTICE); write_font_info(s, "FamilyName", &info.FamilyName, info.members & FONT_INFO_FAMILY_NAME); write_font_info(s, "FullName", &info.FullName, info.members & FONT_INFO_FULL_NAME); } } stream_puts(s, "\nend readonly def\n"); /* Write the main font dictionary. */ stream_puts(s, "/FontName "); write_font_name(s, pfont, alt_font_name, true); stream_puts(s, " def\n"); code = write_Encoding(s, pfont, options, glyphs.subset_glyphs, glyphs.subset_size, glyphs.notdef); if (code < 0) return code; pprintg6(s, "/FontMatrix [%g %g %g %g %g %g] readonly def\n", pfont->FontMatrix.xx, pfont->FontMatrix.xy, pfont->FontMatrix.yx, pfont->FontMatrix.yy, pfont->FontMatrix.tx, pfont->FontMatrix.ty); write_uid(s, &pfont->UID); pprintg4(s, "/FontBBox {%g %g %g %g} readonly def\n", pfont->FontBBox.p.x, pfont->FontBBox.p.y, pfont->FontBBox.q.x, pfont->FontBBox.q.y); { static const gs_param_item_t font_items[] = { {"FontType", gs_param_type_int, offset_of(gs_font_type1, FontType)}, {"PaintType", gs_param_type_int, offset_of(gs_font_type1, PaintType)}, {"StrokeWidth", gs_param_type_float, offset_of(gs_font_type1, StrokeWidth)}, gs_param_item_end }; code = gs_param_write_items(plist, pfont, NULL, font_items); if (code < 0) return code; } { const gs_type1_data *const pdata = &pfont->data; write_float_array(plist, "WeightVector", pdata->WeightVector.values, pdata->WeightVector.count); } stream_puts(s, "currentdict end\n"); /* Write the Private dictionary. */ if (lenIV < 0 && (options & WRITE_TYPE1_WITH_LENIV)) { /* We'll have to encrypt the CharStrings. */ lenIV = 0; write_CharString = stream_write_encrypted; } if (options & WRITE_TYPE1_EEXEC) { stream_puts(s, "currentfile eexec\n"); lengths[0] = stell(s) - start; start = stell(s); if (options & WRITE_TYPE1_ASCIIHEX) { s_init(&AXE_stream, s->memory); s_init_state((stream_state *)&AXE_state, &s_AXE_template, NULL); AXE_state.EndOfData = false; s_init_filter(&AXE_stream, (stream_state *)&AXE_state, AXE_buf, sizeof(AXE_buf), es); es = &AXE_stream; } s_init(&exE_stream, s->memory); s_init_state((stream_state *)&exE_state, &s_exE_template, NULL); exE_state.cstate = 55665; s_init_filter(&exE_stream, (stream_state *)&exE_state, exE_buf, sizeof(exE_buf), es); es = &exE_stream; /* * Note: eexec encryption always writes/skips 4 initial bytes, not * the number of initial bytes given by pdata->lenIV. */ stream_puts(es, "****"); } code = write_Private(es, pfont, glyphs.subset_glyphs, glyphs.subset_size, glyphs.notdef, lenIV, write_CharString, &ppp); if (code < 0) return code; stream_puts(es, "dup/FontName get exch definefont pop\n"); if (options & WRITE_TYPE1_EEXEC) { if (options & (WRITE_TYPE1_EEXEC_PAD | WRITE_TYPE1_EEXEC_MARK)) stream_puts(es, "mark "); stream_puts(es, "currentfile closefile\n"); s_close_filters(&es, s); lengths[1] = stell(s) - start; start = stell(s); if (options & WRITE_TYPE1_EEXEC_PAD) { int i; for (i = 0; i < 8; ++i) stream_puts(s, "\n0000000000000000000000000000000000000000000000000000000000000000"); stream_puts(s, "\ncleartomark\n"); } lengths[2] = stell(s) - start; } else { lengths[0] = stell(s) - start; lengths[1] = lengths[2] = 0; } /* Wrap up. */ s_release_param_printer(&rlist); return 0; }
/* * Create an Indexed color space. This is a single-use procedure, * broken out only for readability. */ static int pdf_indexed_color_space(gx_device_pdf *pdev, cos_value_t *pvalue, const gs_color_space *pcs, cos_array_t *pca) { const gs_indexed_params *pip = &pcs->params.indexed; const gs_color_space *base_space = pcs->base_space; int num_entries = pip->hival + 1; int num_components = gs_color_space_num_components(base_space); uint table_size = num_entries * num_components; /* Guess at the extra space needed for PS string encoding. */ uint string_size = 2 + table_size * 4; uint string_used; byte buf[100]; /* arbitrary */ stream_AXE_state st; stream s, es; gs_memory_t *mem = pdev->pdf_memory; byte *table; byte *palette; cos_value_t v; int code; /* PDF doesn't support Indexed color spaces with more than 256 entries. */ if (num_entries > 256) return_error(gs_error_rangecheck); if (pdev->CompatibilityLevel < 1.3) { switch (gs_color_space_get_index(pcs)) { case gs_color_space_index_Pattern: case gs_color_space_index_Separation: case gs_color_space_index_Indexed: case gs_color_space_index_DeviceN: return_error(gs_error_rangecheck); default: DO_NOTHING; } } table = gs_alloc_string(mem, string_size, "pdf_color_space(table)"); palette = gs_alloc_string(mem, table_size, "pdf_color_space(palette)"); if (table == 0 || palette == 0) { gs_free_string(mem, palette, table_size, "pdf_color_space(palette)"); gs_free_string(mem, table, string_size, "pdf_color_space(table)"); return_error(gs_error_VMerror); } s_init(&s, mem); swrite_string(&s, table, string_size); s_init(&es, mem); s_init_state((stream_state *)&st, &s_PSSE_template, NULL); s_init_filter(&es, (stream_state *)&st, buf, sizeof(buf), &s); sputc(&s, '('); if (pcs->params.indexed.use_proc) { gs_client_color cmin, cmax; byte *pnext = palette; int i, j; /* Find the legal range for the color components. */ for (j = 0; j < num_components; ++j) cmin.paint.values[j] = (float)min_long, cmax.paint.values[j] = (float)max_long; gs_color_space_restrict_color(&cmin, base_space); gs_color_space_restrict_color(&cmax, base_space); /* * Compute the palette values, with the legal range for each * one mapped to [0 .. 255]. */ for (i = 0; i < num_entries; ++i) { gs_client_color cc; gs_cspace_indexed_lookup(pcs, i, &cc); for (j = 0; j < num_components; ++j) { float v = (cc.paint.values[j] - cmin.paint.values[j]) * 255 / (cmax.paint.values[j] - cmin.paint.values[j]); *pnext++ = (v <= 0 ? 0 : v >= 255 ? 255 : (byte)v); } } } else memcpy(palette, pip->lookup.table.data, table_size); if (gs_color_space_get_index(base_space) == gs_color_space_index_DeviceRGB ) { /* Check for an all-gray palette3. */ int i; for (i = table_size; (i -= 3) >= 0; ) if (palette[i] != palette[i + 1] || palette[i] != palette[i + 2] ) break; if (i < 0) { /* Change the color space to DeviceGray. */ for (i = 0; i < num_entries; ++i) palette[i] = palette[i * 3]; table_size = num_entries; base_space = gs_cspace_new_DeviceGray(mem); } } stream_write(&es, palette, table_size); gs_free_string(mem, palette, table_size, "pdf_color_space(palette)"); sclose(&es); sflush(&s); string_used = (uint)stell(&s); table = gs_resize_string(mem, table, string_size, string_used, "pdf_color_space(table)"); /* * Since the array is always referenced by name as a resource * rather than being written as a value, even for in-line images, * always use the full name for the color space. * * We don't have to worry about the range of the base space: * in PDF, unlike PostScript, the values from the lookup table are * scaled automatically. */ if ((code = pdf_color_space(pdev, pvalue, NULL, base_space, &pdf_color_space_names, false)) < 0 || (code = cos_array_add(pca, cos_c_string_value(&v, pdf_color_space_names.Indexed /*pcsn->Indexed*/))) < 0 || (code = cos_array_add(pca, pvalue)) < 0 || (code = cos_array_add_int(pca, pip->hival)) < 0 || (code = cos_array_add_no_copy(pca, cos_string_value(&v, table, string_used))) < 0 ) return code; return 0; }