/* <source> DCTDecode/filter <file> */ static int zDCTD(i_ctx_t *i_ctx_p) { os_ptr op = osp; gs_memory_t *mem; stream_DCT_state state; dict_param_list list; jpeg_decompress_data *jddp; int code; const ref *dop; uint dspace; if (r_has_type(op, t_dictionary)) dop = op, dspace = r_space(op); else dop = 0, dspace = 0; mem = (gs_memory_t *)find_stream_memory(i_ctx_p, 0, &dspace); state.memory = mem; /* First allocate space for IJG parameters. */ jddp = gs_alloc_struct_immovable(mem,jpeg_decompress_data, &st_jpeg_decompress_data, "zDCTD"); if (jddp == 0) return_error(e_VMerror); if (s_DCTD_template.set_defaults) (*s_DCTD_template.set_defaults) ((stream_state *) & state); state.data.decompress = jddp; jddp->memory = state.jpeg_memory = mem; /* set now for allocation */ jddp->scanline_buffer = NULL; /* set this early for safe error exit */ state.report_error = filter_report_error; /* in case create fails */ if ((code = gs_jpeg_create_decompress(&state)) < 0) goto fail; /* correct to do jpeg_destroy here */ /* Read parameters from dictionary */ if ((code = dict_param_list_read(&list, dop, NULL, false, iimemory)) < 0) goto fail; if ((code = s_DCTD_put_params((gs_param_list *) & list, &state)) < 0) goto rel; /* Create the filter. */ jddp->templat = s_DCTD_template; code = filter_read(i_ctx_p, 0, &jddp->templat, (stream_state *) & state, dspace); if (code >= 0) /* Success! */ return code; /* * We assume that if filter_read fails, the stream has not been * registered for closing, so s_DCTD_release will never be called. * Therefore we free the allocated memory before failing. */ rel: iparam_list_release(&list); fail: gs_jpeg_destroy(&state); gs_free_object(mem, jddp, "zDCTD fail"); return code; }
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; }
/* TODO: consider using source.count (and possibly also phase) */ static int read_headless_jpeg_bitmap_data(byte ** pdata, px_args_t * par, px_state_t * pxs) { px_vendor_state_t *v_state = pxs->vendor_state; uint data_per_row = v_state->data_per_row; /* jpeg doesn't pad */ uint avail = par->source.available; uint pos_in_row = par->source.position % data_per_row; const byte *data = par->source.data; stream_DCT_state *ss = (&v_state->dct_stream_state); stream_cursor_read r; stream_cursor_write w; uint used; int code = -1; if_debug3('w', "jpeg begin pos=%d row=%d/%d\n", pos_in_row, v_state->rowwritten, v_state->BlockHeight); /* consumed all of the data */ if ((v_state->state == vu_body) && v_state->rowwritten == v_state->BlockHeight) { if (par->source.available == 2) { /* the data includes EOI; the filter may or may not consume it */ par->source.data += 2; par->source.available -= 2; } gs_jpeg_destroy((&v_state->dct_stream_state)); v_state->state = vu_blank; v_state->rowwritten = 0; code = pl_end_image(pxs->pgs, v_state->info, true); if (code < 0) return code; return 0; } if (v_state->state == vu_tagged) { jpeg_decompress_data *jddp = &(v_state->jdd); v_state->rowwritten = 0; code = vu_begin_image(pxs); if (code < 0) return code; /* use the graphics library support for DCT streams */ ss->memory = pxs->memory; ss->templat = &s_DCTD_template; s_DCTD_template.set_defaults((stream_state *) ss); ss->report_error = vu_stream_error; ss->data.decompress = jddp; /* set now for allocation */ jddp->memory = ss->jpeg_memory = pxs->memory; /* set this early for safe error exit */ jddp->scanline_buffer = NULL; if (gs_jpeg_create_decompress(ss) < 0) return_error(errorInsufficientMemory); (*s_DCTD_template.init) ((stream_state *) ss); jddp->templat = s_DCTD_template; fastforward_jpeg_stream_state(jddp, ss, pxs); v_state->state = vu_body; } r.ptr = data - 1; r.limit = r.ptr + avail; if (pos_in_row < data_per_row) { /* Read more of the current row. */ byte *data = *pdata; w.ptr = data + pos_in_row - 1; w.limit = data + data_per_row - 1; code = (*s_DCTD_template.process) ((stream_state *) ss, &r, &w, false); /* code = num scanlines processed (0=need more data, -ve=error) */ if_debug1('w', "s_DCTD_template.process returns %d\n", code); used = w.ptr + 1 - data - pos_in_row; if ((code == EOFC) && (used > 0)) code = 1; if_debug2('w', "data generated: %d/%d\n", used, data_per_row); /* pos_in_row += used; */ par->source.position += used; } used = r.ptr + 1 - data; par->source.data = r.ptr + 1; par->source.available = avail - used; if_debug2('w', "scanlines %d used %d\n", code, used); if (code == 0) return pxNeedData; if (code == EOFC) /* used = 0 is possible, and earlier than end */ return 0; if (code > 0) { v_state->rowwritten++; if_debug1('w', "row written:%d\n", v_state->rowwritten); jpeg_custom_color_fixup(v_state->row, v_state->color_space, v_state->data_per_row); return 1; } return code; }