/* * Convert a CIEBasedA color into device color. */ static int client_remap_CIEBasedA(client_custom_color_params_t * pparams, const gs_client_color * pc, const gs_color_space * pcs, gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, gs_color_select_t select) { demo_color_space_data_t * pdata = (demo_color_space_data_t *)(pcs->pclient_color_space_data); frac gray = convert2frac(pc->paint.values[0], pcs->params.a->RangeA); /*** Demonstrate method to convert to XYZ ***/ if (pdata->CIEtoXYZ_pis) { frac xyz[3]; cs_concretize_color(pc, pcs, xyz, pdata->CIEtoXYZ_pis); /* We don't really do anything with these values, but this */ /* is where a real client could convert to a device color */ if_debug4('|', "[c]client_remap CIEA [%g] -> XYZ [%g, %g, %g]\n", pc->paint.values[0], frac2float(xyz[0]), frac2float(xyz[1]), frac2float(xyz[2])); } /* * For demo and debug purposes, make our colors a function of the * intensity of the given color value and the object type. */ return client_remap_DeviceGray(pparams, &gray, pcs, pdc, pis, dev, select); }
/* Render a CIEBasedDEFG color. */ int gx_concretize_CIEDEFG(const gs_client_color * pc, const gs_color_space * pcs_in, frac * pconc, const gs_imager_state * pis, gx_device *dev) { int code; gs_color_space *pcs_icc; gs_client_color scale_pc; gs_color_space *pcs = (gs_color_space *) pcs_in; if_debug4('c', "[c]concretize DEFG [%g %g %g %g]\n", pc->paint.values[0], pc->paint.values[1], pc->paint.values[2], pc->paint.values[3]); /* If we are comming in here then we have not completed the conversion of the DEFG space to an ICC type. We will finish that process now. */ if (pcs->icc_equivalent == NULL) { code = gx_ciedefg_to_icc(&pcs_icc, pcs, pis->memory->stable_memory); } else { pcs_icc = pcs->icc_equivalent; } /* Rescale the input based upon the input range since profile is created to remap this range from 0 to 1 */ if (check_range(&(pcs->params.defg->RangeDEFG.ranges[0]), 4)) { return((pcs_icc->type->concretize_color)(pc, pcs_icc, pconc, pis, dev)); } /* Do the rescale from 0 to 1 */ rescale_input_color(&(pcs->params.defg->RangeDEFG.ranges[0]), 4, pc, &scale_pc); /* Now the icc remap */ return((pcs_icc->type->concretize_color)(pc, pcs_icc, pconc, pis, dev)); }
/* Used for when we have to mash entire transform to CIEXYZ */ int gx_psconcretize_CIEDEFG(const gs_client_color * pc, const gs_color_space * pcs, frac * pconc, const gs_imager_state * pis) { const gs_cie_defg *pcie = pcs->params.defg; int i; fixed hijk[4]; frac abc[3]; cie_cached_vector3 vec3; int code; if_debug4('c', "[c]concretize DEFG [%g %g %g %g]\n", pc->paint.values[0], pc->paint.values[1], pc->paint.values[2], pc->paint.values[3]); code = gx_cie_check_rendering_inline(pcs, pconc, pis); if (code < 0) return code; if (code == 1) return 0; /* * Apply DecodeDEFG, including restriction to RangeHIJK and scaling to * the Table dimensions. */ for (i = 0; i < 4; ++i) { int tdim = pcie->Table.dims[i] - 1; double factor = pcie->caches_defg.DecodeDEFG[i].floats.params.factor; double v0 = pc->paint.values[i]; const gs_range *const rangeDEFG = &pcie->RangeDEFG.ranges[i]; double value = (v0 < rangeDEFG->rmin ? 0.0 : factor * (v0 > rangeDEFG->rmax ? rangeDEFG->rmax - rangeDEFG->rmin : v0 - rangeDEFG->rmin )); int vi = (int)value; double vf = value - vi; double v = pcie->caches_defg.DecodeDEFG[i].floats.values[vi]; if (vf != 0 && vi < factor) v += vf * (pcie->caches_defg.DecodeDEFG[i].floats.values[vi + 1] - v); v = (v < 0 ? 0 : v > tdim ? tdim : v); hijk[i] = float2fixed(v); } /* Apply Table. */ gx_color_interpolate_linear(hijk, &pcie->Table, abc); #define SCALE_TO_RANGE(range, frac) ( \ float2cie_cached(((range).rmax - (range).rmin) * frac2float(frac) + \ (range).rmin) \ ) /* Scale the abc[] frac values to RangeABC cie_cached result */ vec3.u = SCALE_TO_RANGE(pcie->RangeABC.ranges[0], abc[0]); vec3.v = SCALE_TO_RANGE(pcie->RangeABC.ranges[1], abc[1]); vec3.w = SCALE_TO_RANGE(pcie->RangeABC.ranges[2], abc[2]); /* Apply DecodeABC and MatrixABC. */ if (!pis->cie_joint_caches->skipDecodeABC) cie_lookup_map3(&vec3 /* ABC => LMN */, &pcie->caches.DecodeABC, "Decode/MatrixABC"); GX_CIE_REMAP_FINISH(vec3, pconc, pis, pcs); return 0; }
static inline int get_run(stream_CFD_state *ss, stream_cursor_read *pr, const cfd_node decode[], int initial_bits, int min_bits, int *runlen, const char *str) { cfd_declare_state; const cfd_node *np; int clen; cfd_load_state(); HCD_ENSURE_BITS_ELSE(initial_bits) { /* We might still have enough bits for the specific code. */ if (bits_left < min_bits) goto outl; np = &decode[hcd_peek_bits_left() << (initial_bits - bits_left)]; if ((clen = np->code_length) > bits_left) goto outl; goto locl; } np = &decode[peek_bits(initial_bits)]; if ((clen = np->code_length) > initial_bits) { IF_DEBUG(uint init_bits = peek_bits(initial_bits)); if (!avail_bits(clen)) goto outl; clen -= initial_bits; skip_bits(initial_bits); ensure_bits(clen, outl); /* can't goto outl */ np = &decode[np->run_length + peek_var_bits(clen)]; if_debug4('W', "%s xcode=0x%x,%d rlen=%d\n", str, (init_bits << np->code_length) + peek_var_bits(np->code_length), initial_bits + np->code_length, np->run_length); skip_bits(np->code_length); } else { locl: if_debug4('W', "%s code=0x%x,%d rlen=%d\n", str, peek_var_bits(clen), clen, np->run_length); skip_bits(clen); } *runlen = np->run_length; cfd_store_state(); return(0); outl: cfd_store_state(); return(-1); }
static int vu_tag_dispatch(px_args_t * par, px_state_t * pxs) { px_vendor_state_t *v_state = pxs->vendor_state; if (v_state->state == vu_blank) { if (par->source.available < 6) return pxNeedData; v_state->tag.tag_id = uint16at(par->source.data, pxs->data_source_big_endian); v_state->tag.bytes_expected = uint32at(par->source.data + 2, pxs->data_source_big_endian); v_state->tag.bytes_so_far = 0; v_state->state = vu_tagged; memset(v_state->row, 0xff, v_state->data_per_row); par->source.data += 6; par->source.available -= 6; par->source.position += 6; if_debug2('I', "Signature %04X expect=%d\n", v_state->tag.tag_id, v_state->tag.bytes_expected); }; if (v_state->state != vu_blank) { if_debug4('I', "tag %04X bytes=%d/%d avail=%d\n", v_state->tag.tag_id, v_state->tag.bytes_so_far, v_state->tag.bytes_expected, par->source.available); switch (v_state->tag.tag_id) { case 0x9031: /* CLJ3600 specific; 3550 returns IllegalTag */ case 0x9011: case 0x9021: return tag_dispatch_90X1(par, pxs); break; case 0x1001: /* do nothing */ if (v_state->tag.bytes_expected == 0) { v_state->state = vu_blank; return 0; } /* probably should return error */ return tag_dispatch_generic(par, pxs); break; case 0x8000: return tag_dispatch_8000(par, pxs); break; case 0x8001: return tag_dispatch_generic(par, pxs); break; default: return_error(errorIllegalTag); break; } } /* unreachable */ return pxNeedData; }
/* Record the side bearing and character width. */ int gs_type1_sbw(gs_type1_state * pcis, fixed lsbx, fixed lsby, fixed wx, fixed wy) { if (!pcis->sb_set) pcis->lsb.x = lsbx, pcis->lsb.y = lsby, pcis->sb_set = true; /* needed for accented chars */ if (!pcis->width_set) pcis->width.x = wx, pcis->width.y = wy, pcis->width_set = true; if_debug4('1', "[1]sb=(%g,%g) w=(%g,%g)\n", fixed2float(pcis->lsb.x), fixed2float(pcis->lsb.y), fixed2float(pcis->width.x), fixed2float(pcis->width.y)); return 0; }
gx_color_index eprn_map_cmyk_color_max(gx_device *device, const gx_color_value cv[]) { gx_color_value cyan = cv[0], magenta = cv[1], yellow = cv[2], black = cv[3]; gx_color_index value; #ifdef EPRN_TRACE if_debug4(EPRN_TRACE_CHAR, "! eprn_map_cmyk_color_max() called for CMYK = (%hu, %hu, %hu, %hu),\n", cyan, magenta, yellow, black); #endif value = dominant_8bits(black); value |= dominant_8bits(cyan) << 8; value |= dominant_8bits(magenta) << 16; value |= dominant_8bits(yellow) << 24; #ifdef EPRN_TRACE if_debug1(EPRN_TRACE_CHAR, " returning 0x%08lX.\n", (unsigned long)value); #endif return value; }
gx_color_index eprn_map_cmyk_color(gx_device *device, const gx_color_value cv[]) { gx_color_value cyan = cv[0], magenta = cv[1], yellow = cv[2], black = cv[3]; gx_color_index value = 0; static const gx_color_value threshold = gx_max_color_value/2; #ifdef EPRN_TRACE if_debug4(EPRN_TRACE_CHAR, "! eprn_map_cmyk_color() called for CMYK = (%hu, %hu, %hu, %hu),\n", cyan, magenta, yellow, black); #endif if (cyan > threshold) value |= CYAN_BIT; if (magenta > threshold) value |= MAGENTA_BIT; if (yellow > threshold) value |= YELLOW_BIT; if (black > threshold) value |= BLACK_BIT; #ifdef EPRN_TRACE if_debug1(EPRN_TRACE_CHAR, " returning 0x%lX.\n", (unsigned long)value); #endif return value; }
static int svg_lineto(gx_device_vector *vdev, floatp x0, floatp y0, floatp x, floatp y, gx_path_type_t type) { gx_device_svg *svg = (gx_device_svg *)vdev; char line[SVG_LINESIZE]; /* hack single-page output */ if (svg->page_count) return 0; /* skip non-drawing paths for now */ if (!(type & gx_path_type_fill) && !(type & gx_path_type_stroke)) return 0; if_debug4('_', "svg_lineto(%lf,%lf,%lf,%lf) ", x0,y0, x,y); svg_print_path_type(svg, type); if_debug0('_', "\n"); sprintf(line, " L%lf,%lf", x, y); svg_write(svg, line); return 0; }
int gx_remap_CIEDEFG(const gs_client_color * pc, const gs_color_space * pcs_in, gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, gs_color_select_t select) { gs_color_space *pcs_icc; int code, i; gs_client_color scale_pc; gs_color_space *pcs = (gs_color_space *) pcs_in; if_debug4('c', "[c]remap CIEDEFG [%g %g %g %g]\n", pc->paint.values[0], pc->paint.values[1], pc->paint.values[2], pc->paint.values[3]); /* If we are comming in here then we have not completed the conversion of the DEFG space to an ICC type. We will finish that process now. */ if (pcs->icc_equivalent == NULL) { code = gx_ciedefg_to_icc(&pcs_icc, pcs, pis->memory->stable_memory); } else { pcs_icc = pcs->icc_equivalent; } /* Rescale the input based upon the input range since profile is created to remap this range from 0 to 1 */ if (check_range(&(pcs->params.defg->RangeDEFG.ranges[0]), 4)) { return((pcs_icc->type->remap_color)(pc,pcs_icc,pdc,pis,dev,select)); } /* Do the rescale from 0 to 1 */ rescale_input_color(&(pcs->params.defg->RangeDEFG.ranges[0]), 4, pc, &scale_pc); /* Now the icc remap */ code = (pcs_icc->type->remap_color)(&scale_pc,pcs_icc,pdc,pis,dev,select); /* Save unscaled data for high level device (e.g. pdfwrite) */ for (i = 0; i < 4; i++) pdc->ccolor.paint.values[i] = pc->paint.values[i]; pdc->ccolor_valid = true; return(code); }
gx_color_index eprn_map_cmyk_color_flex(gx_device *device, const gx_color_value cv[]) { gx_color_value cyan = cv[0], magenta = cv[1], yellow = cv[2], black = cv[3]; gx_color_index value = 0; gx_color_value step; unsigned int level; const eprn_Eprn *eprn = &((eprn_Device *)device)->eprn; #ifdef EPRN_TRACE if_debug4(EPRN_TRACE_CHAR, "! eprn_map_cmyk_color_flex() called for CMYK = (%hu, %hu, %hu, %hu),\n", cyan, magenta, yellow, black); #endif /* I can think of three linear methods to extract discrete values from a continuous intensity in the range [0, 1]: (a) multiply by the number of levels minus 1 and truncate, (b) multiply by the number of levels minus 1 and round, and (c) multiply by the number of levels and truncate, except for an intensity of 1 in which case one returns the number of levels minus 1. For intensity values which can be represented exactly, i.e., intensity = i/(levels-1) for some non-negative i < levels, these three methods are identical. (a) is however inappropriate here because for less than 32 levels ghostscript already provides intensity values which have been adjusted to a representable level. A rounding error could now result in a level which is too small by one. I prefer (c) because it gives equal shares to all levels. I'm using integer arithmetic here although floating point numbers would be more accurate. This routine may, however, be called quite frequently, and the loss in accuray is acceptable as long as the values determined for 'step' are large compared to the number of levels. If you consider "large" as meaning "10 times as large", the critical boundary is at about 81 levels. The highest number of intensity levels at present supported by HP DeskJets is apparently 4. A more accurate implementation would determine 'step' as a floating point value, divide the intensity by it, and take the floor (entier) of the result as the component intensity. */ /* The order has to be (YMC)(K) from left to right */ if (eprn->colour_model != eprn_DeviceGray) { step = gx_max_color_value/eprn->non_black_levels; level = yellow/step; if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1; value = level << eprn->bits_per_colorant; level = magenta/step; if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1; value = (value | level) << eprn->bits_per_colorant; level = cyan/step; if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1; value = (value | level) << eprn->bits_per_colorant; } if (eprn->colour_model != eprn_DeviceCMY) { step = gx_max_color_value/eprn->black_levels; level = black/step; if (level >= eprn->black_levels) level = eprn->black_levels - 1; value |= level; } #ifdef EPRN_TRACE if_debug1(EPRN_TRACE_CHAR, " returning 0x%lX.\n", (unsigned long)value); #endif return value; }
/* * This is somewhat a clone of the tile_by_steps function but one * that performs filling from and to pdf14dev (transparency) buffers. * At some point it may be desirable to do some optimization here. */ static int tile_by_steps_trans(tile_fill_trans_state_t * ptfs, int x0, int y0, int w0, int h0, gx_pattern_trans_t *fill_trans_buffer, const gx_color_tile * ptile) { int x1 = x0 + w0, y1 = y0 + h0; int i0, i1, j0, j1, i, j; gs_matrix step_matrix; /* translated by phase */ gx_pattern_trans_t *ptrans_pat = ptile->ttrans; ptfs->x0 = x0, ptfs->w0 = w0; ptfs->y0 = y0, ptfs->h0 = h0; step_matrix = ptile->step_matrix; step_matrix.tx -= ptfs->phase.x; step_matrix.ty -= ptfs->phase.y; { gs_rect bbox; /* bounding box in device space */ gs_rect ibbox; /* bounding box in stepping space */ double bbw = ptile->bbox.q.x - ptile->bbox.p.x; double bbh = ptile->bbox.q.y - ptile->bbox.p.y; double u0, v0, u1, v1; bbox.p.x = x0, bbox.p.y = y0; bbox.q.x = x1, bbox.q.y = y1; gs_bbox_transform_inverse(&bbox, &step_matrix, &ibbox); if_debug10('T', "[T]x,y=(%d,%d) w,h=(%d,%d) => (%g,%g),(%g,%g), offset=(%g,%g)\n", x0, y0, w0, h0, ibbox.p.x, ibbox.p.y, ibbox.q.x, ibbox.q.y, step_matrix.tx, step_matrix.ty); /* * If the pattern is partly transparent and XStep/YStep is smaller * than the device space BBox, we need to ensure that we cover * each pixel of the rectangle being filled with *every* pattern * that overlaps it, not just *some* pattern copy. */ u0 = ibbox.p.x - max(ptile->bbox.p.x, 0) - 0.000001; v0 = ibbox.p.y - max(ptile->bbox.p.y, 0) - 0.000001; u1 = ibbox.q.x - min(ptile->bbox.q.x, 0) + 0.000001; v1 = ibbox.q.y - min(ptile->bbox.q.y, 0) + 0.000001; if (!ptile->is_simple) u0 -= bbw, v0 -= bbh, u1 += bbw, v1 += bbh; i0 = (int)fastfloor(u0); j0 = (int)fastfloor(v0); i1 = (int)ceil(u1); j1 = (int)ceil(v1); } if_debug4('T', "[T]i=(%d,%d) j=(%d,%d)\n", i0, i1, j0, j1); for (i = i0; i < i1; i++) for (j = j0; j < j1; j++) { int x = (int)fastfloor(step_matrix.xx * i + step_matrix.yx * j + step_matrix.tx); int y = (int)fastfloor(step_matrix.xy * i + step_matrix.yy * j + step_matrix.ty); int w = ptrans_pat->width; int h = ptrans_pat->height; int xoff, yoff; int px, py; if_debug4('T', "[T]i=%d j=%d x,y=(%d,%d)", i, j, x, y); if (x < x0) xoff = x0 - x, x = x0, w -= xoff; else xoff = 0; if (y < y0) yoff = y0 - y, y = y0, h -= yoff; else yoff = 0; if (x + w > x1) w = x1 - x; if (y + h > y1) h = y1 - y; if_debug6('T', "=>(%d,%d) w,h=(%d,%d) x/yoff=(%d,%d)\n", x, y, w, h, xoff, yoff); if (w > 0 && h > 0) { px = imod(xoff - x, ptile->ttrans->width); py = imod(yoff - y, ptile->ttrans->height); /* Set the offsets for colored pattern fills */ ptfs->xoff = xoff; ptfs->yoff = yoff; /* We only go through blending during tiling, if there was overlap as defined by the step matrix and the bounding box */ ptile->ttrans->pat_trans_fill(x, y, x+w, y+h, px, py, ptile, fill_trans_buffer); } } return 0; }
/* * Fill with non-standard X and Y stepping. * ptile is pdevc->colors.pattern.{m,p}_tile. * tbits_or_tmask is whichever of tbits and tmask is supplying * the tile size. * This implementation could be sped up considerably! */ static int tile_by_steps(tile_fill_state_t * ptfs, int x0, int y0, int w0, int h0, const gx_color_tile * ptile, const gx_strip_bitmap * tbits_or_tmask, int (*fill_proc) (const tile_fill_state_t * ptfs, int x, int y, int w, int h)) { int x1 = x0 + w0, y1 = y0 + h0; int i0, i1, j0, j1, i, j; gs_matrix step_matrix; /* translated by phase */ int code; ptfs->x0 = x0, ptfs->w0 = w0; ptfs->y0 = y0, ptfs->h0 = h0; step_matrix = ptile->step_matrix; step_matrix.tx -= ptfs->phase.x; step_matrix.ty -= ptfs->phase.y; { gs_rect bbox; /* bounding box in device space */ gs_rect ibbox; /* bounding box in stepping space */ double bbw = ptile->bbox.q.x - ptile->bbox.p.x; double bbh = ptile->bbox.q.y - ptile->bbox.p.y; double u0, v0, u1, v1; bbox.p.x = x0, bbox.p.y = y0; bbox.q.x = x1, bbox.q.y = y1; gs_bbox_transform_inverse(&bbox, &step_matrix, &ibbox); if_debug10('T', "[T]x,y=(%d,%d) w,h=(%d,%d) => (%g,%g),(%g,%g), offset=(%g,%g)\n", x0, y0, w0, h0, ibbox.p.x, ibbox.p.y, ibbox.q.x, ibbox.q.y, step_matrix.tx, step_matrix.ty); /* * If the pattern is partly transparent and XStep/YStep is smaller * than the device space BBox, we need to ensure that we cover * each pixel of the rectangle being filled with *every* pattern * that overlaps it, not just *some* pattern copy. */ u0 = ibbox.p.x - max(ptile->bbox.p.x, 0) - 0.000001; v0 = ibbox.p.y - max(ptile->bbox.p.y, 0) - 0.000001; u1 = ibbox.q.x - min(ptile->bbox.q.x, 0) + 0.000001; v1 = ibbox.q.y - min(ptile->bbox.q.y, 0) + 0.000001; if (!ptile->is_simple) u0 -= bbw, v0 -= bbh, u1 += bbw, v1 += bbh; i0 = (int)fastfloor(u0); j0 = (int)fastfloor(v0); i1 = (int)ceil(u1); j1 = (int)ceil(v1); } if_debug4('T', "[T]i=(%d,%d) j=(%d,%d)\n", i0, i1, j0, j1); for (i = i0; i < i1; i++) for (j = j0; j < j1; j++) { int x = (int)fastfloor(step_matrix.xx * i + step_matrix.yx * j + step_matrix.tx); int y = (int)fastfloor(step_matrix.xy * i + step_matrix.yy * j + step_matrix.ty); int w = tbits_or_tmask->size.x; int h = tbits_or_tmask->size.y; int xoff, yoff; if_debug4('T', "[T]i=%d j=%d x,y=(%d,%d)", i, j, x, y); if (x < x0) xoff = x0 - x, x = x0, w -= xoff; else xoff = 0; if (y < y0) yoff = y0 - y, y = y0, h -= yoff; else yoff = 0; if (x + w > x1) w = x1 - x; if (y + h > y1) h = y1 - y; if_debug6('T', "=>(%d,%d) w,h=(%d,%d) x/yoff=(%d,%d)\n", x, y, w, h, xoff, yoff); if (w > 0 && h > 0) { if (ptfs->pcdev == (gx_device *) & ptfs->cdev) tile_clip_set_phase(&ptfs->cdev, imod(xoff - x, ptfs->tmask->rep_width), imod(yoff - y, ptfs->tmask->rep_height)); /* Set the offsets for colored pattern fills */ ptfs->xoff = xoff; ptfs->yoff = yoff; code = (*fill_proc) (ptfs, x, y, w, h); if (code < 0) return code; } } return 0; }
/* TODO: consider using source.position and source.count (and possibly also phase) */ static int read_mode10_bitmap_data(byte ** pdata, px_args_t * par, px_state_t * pxs, bool mode9031) { px_vendor_state_t *v_state = pxs->vendor_state; mode10_state_t *mode10_state = &v_state->mode10_state; uint avail = min(par->source.available, (v_state->tag.bytes_expected - v_state->tag.bytes_so_far)); const byte *pin = par->source.data; byte *pout; bool end_of_row = false; uint32_t pixel; int i; update_pout(pout); if ((v_state->state == vu_body) && v_state->rowwritten == v_state->BlockHeight) { int code = pl_end_image(pxs->pgs, v_state->info, true); if (code < 0) return code; v_state->state = vu_blank; v_state->rowwritten = 0; return 0; } /* initialize at begin of image */ if (v_state->state == vu_tagged) { int code = vu_begin_image(pxs); if (code < 0) return code; mode10_state->state = next_is_cmd; mode10_state->cursor = 0; v_state->rowwritten = 0; v_state->state = vu_body; } /* one byte at a time until end of input or end of row */ while ((avail || mode10_state->state == process_rle) /* process_rle does not consume */ &&(!end_of_row)) { switch (mode10_state->state) { case next_is_cmd:{ mode10_state->cmd = *pin++; --avail; if_debug4('w', "command:%02X row written:%d cursor:%d cached=%08X\n", mode10_state->cmd, v_state->rowwritten, mode10_state->cursor, mode10_state->cached_pixel); mode10_state->offset = (mode10_state->cmd >> 3) & 0x03; mode10_state->count = mode10_state->cmd & 0x07; mode10_state->cursor += mode10_state->offset; /* may be partial */ if ((mode10_state->offset < 3) && (mode10_state->count < 7) && (!srcNEW(mode10_state->cmd)) ) { /* completed command */ if (mode10_state->cmd & eRLE) { mode10_state->state = process_rle; } else { /* literal, non-new */ update_pout(pout); pixel = get_pixel(pout, &mode10_state->cached_pixel, mode10_state->cmd, v_state->color_space); copy_pixel(pout, pixel); mode10_state->cursor += 1; if (mode10_state->count > 0) { mode10_state->count--; mode10_state->state = next_is_pixel; } else mode10_state->state = next_is_cmd; } } else if (mode10_state->offset == 3) mode10_state->state = partial_offset; else if (srcNEW(mode10_state->cmd)) { if ((mode10_state->cmd & eRLE) && (mode10_state->cursor >= v_state->SourceWidth)) { /* special case */ if_debug0('w', "special\n"); mode10_state->cursor = 0; end_of_row = 1; mode10_state->state = next_is_cmd; } else mode10_state->state = next_is_pixel; } else if (mode10_state->count == 7) mode10_state->state = partial_count; else mode10_state->state = next_is_cmd; /* does not happen */ break; } case partial_offset:{ uint offset = *pin++; avail--; mode10_state->offset += offset; mode10_state->cursor += offset; if (offset == 0xff) mode10_state->state = partial_offset; else { /* completed offset */ if_debug5('w', "%02X row=%d offset=%d cursor=%d/%d\n", mode10_state->cmd, v_state->rowwritten, mode10_state->offset, mode10_state->cursor, v_state->SourceWidth); if (srcNEW(mode10_state->cmd)) { if ((mode10_state->cmd & eRLE) && (mode10_state->cursor >= v_state->SourceWidth)) { /* special case */ if_debug0('w', "special\n"); mode10_state->cursor = 0; end_of_row = 1; mode10_state->state = next_is_cmd; } else mode10_state->state = next_is_pixel; } else if (mode10_state->count == 7) { mode10_state->state = partial_count; } else { /* not new pixels, counts under 7, so we need to process there */ if (mode10_state->cmd & eRLE) { mode10_state->state = process_rle; } else { /* literal non-new */ update_pout(pout); pixel = get_pixel(pout, &mode10_state->cached_pixel, mode10_state->cmd, v_state->color_space); copy_pixel(pout, pixel); mode10_state->cursor += 1; if (mode10_state->count > 0) { mode10_state->count--; mode10_state->state = next_is_pixel; } else mode10_state->state = next_is_cmd; } } } break; } case partial_count:{ uint count = *pin++; avail--; mode10_state->count += count; if (count == 0xff) mode10_state->state = partial_count; else { /* finished count - partial count only happens on RLE */ if_debug1('w', "count=%d\n", mode10_state->count); mode10_state->state = process_rle; } break; } case next_is_pixel:{ if (!mode9031 && (avail < 3)) { /* get to outer loop to get more data */ avail = 0; break; } if_debug3('w', "pixel:%02X%02X%02X\n", pin[0], pin[1], pin[2]); if (v_state->color_space == eGraySub) { /* bug in recent hpijs */ mode10_state->cached_pixel = (pin[0] << 16 | pin[0] << 8 | pin[0]) ^ 0x00ffffff; } else if (mode9031) { mode10_state->cached_pixel = (pin[0] << 16 | pin[0] << 8 | pin[0]); } else mode10_state->cached_pixel = (pin[0] << 16 | pin[1] << 8 | pin[2]); update_pout(pout); update_advance_pixel(pout, pin, mode9031); if (mode9031) { pin += 1; avail -= 1; } else { pin += 3; avail -= 3; } mode10_state->cursor++; if ((mode10_state->cmd & eRLE) && (mode10_state->count == 7)) mode10_state->state = partial_count; else if (mode10_state->cmd & eRLE) { mode10_state->state = process_rle; } else if (mode10_state->count > 0) { /* literal */ mode10_state->count--; mode10_state->state = next_is_pixel; } else mode10_state->state = next_is_cmd; break; } case process_rle:{ update_pout(pout); pixel = get_pixel(pout, &mode10_state->cached_pixel, mode10_state->cmd, v_state->color_space); mode10_state->cursor += mode10_state->count + 2; i = mode10_state->count + 2; if (srcNEW(mode10_state->cmd)) { i--; /* already moved cursor in the case of new pixel */ mode10_state->cursor--; } while (i > 0) { copy_pixel(pout, pixel); i--; } mode10_state->state = next_is_cmd; break; } } /* end switch */ /* conditional on state may not be necessary */ if ((mode10_state->state == next_is_cmd) && (mode10_state->cursor >= v_state->SourceWidth)) { mode10_state->cursor = 0; end_of_row = 1; } } /* end of while */ par->source.available -= pin - par->source.data; /* subtract compressed data used */ par->source.position += pin - par->source.data; par->source.data = pin; /* new compressed data position */ if (end_of_row) { v_state->rowwritten++; return 1; } return pxNeedData; /* not end of row so request more data */ }
/* Process a buffer */ static int s_DCTE_process(stream_state * st, stream_cursor_read * pr, stream_cursor_write * pw, bool last) { stream_DCT_state *const ss = (stream_DCT_state *) st; jpeg_compress_data *jcdp = ss->data.compress; struct jpeg_destination_mgr *dest = jcdp->cinfo.dest; if_debug2('w', "[wde]process avail=%u, last=%d\n", (uint) (pr->limit - pr->ptr), last); dest->next_output_byte = pw->ptr + 1; dest->free_in_buffer = pw->limit - pw->ptr; switch (ss->phase) { case 0: /* not initialized yet */ if (gs_jpeg_start_compress(ss, TRUE) < 0) return ERRC; if_debug4('w', "[wde]width=%u, height=%u, components=%d, scan_line_size=%u\n", jcdp->cinfo.image_width, jcdp->cinfo.image_height, jcdp->cinfo.input_components, ss->scan_line_size); pw->ptr = dest->next_output_byte - 1; ss->phase = 1; /* falls through */ case 1: /* initialized, Markers not written */ if (pw->limit - pw->ptr < ss->Markers.size) return 1; memcpy(pw->ptr + 1, ss->Markers.data, ss->Markers.size); pw->ptr += ss->Markers.size; ss->phase = 2; /* falls through */ case 2: /* still need to write Adobe marker */ if (!ss->NoMarker) { static const byte Adobe[] = { 0xFF, JPEG_APP0 + 14, 0, 14, /* parameter length */ 'A', 'd', 'o', 'b', 'e', 0, 100, /* Version */ 0, 0, /* Flags0 */ 0, 0, /* Flags1 */ 0 /* ColorTransform */ }; #define ADOBE_MARKER_LEN sizeof(Adobe) if (pw->limit - pw->ptr < ADOBE_MARKER_LEN) return 1; memcpy(pw->ptr + 1, Adobe, ADOBE_MARKER_LEN); pw->ptr += ADOBE_MARKER_LEN; *pw->ptr = ss->ColorTransform; #undef ADOBE_MARKER_LEN } dest->next_output_byte = pw->ptr + 1; dest->free_in_buffer = pw->limit - pw->ptr; ss->phase = 3; /* falls through */ case 3: /* If we have it, then write out the ICC profile */ /* Due to size limitations allowed in APP0 markers, the profile may have to be written in mutiple markers */ if (ss->icc_profile != NULL) { static const char marker[2] = {0xFF, 0xE2}; /* JPEG_APP0 + 2 */ byte num_mark; /* Number of markers */ num_mark = ss->icc_profile->buffer_size / MAX_MARKER_DATA_SIZE; if (num_mark * MAX_MARKER_DATA_SIZE < ss->icc_profile->buffer_size) { num_mark++; } while (ss->icc_marker < num_mark) { ulong offset = ss->icc_marker * MAX_MARKER_DATA_SIZE; ulong size; size = ss->icc_profile->buffer_size - offset; if (size > MAX_MARKER_DATA_SIZE) size = MAX_MARKER_DATA_SIZE; /* In this case we are just getting started with the header of the marker. Write that portion out */ if (ss->icc_position == -1) { byte length_byte[2]; byte curr_mark = ss->icc_marker + 1; ulong total_length; if ((uint) (pw->limit - pw->ptr) < (sizeof(marker) + ICC_OVERHEAD)) return 1; total_length = size + ICC_OVERHEAD; memcpy(pw->ptr + 1, marker, sizeof(marker)); length_byte[0] = total_length >> 8; length_byte[1] = total_length & 0xFF; memcpy(pw->ptr + 3, length_byte, sizeof(length_byte)); memcpy(pw->ptr + 5, "ICC_PROFILE", 12); /* Null included */ memcpy(pw->ptr + 17, &curr_mark, 1); memcpy(pw->ptr + 18, &num_mark, 1); pw->ptr += sizeof(marker) + ICC_OVERHEAD; ss->icc_position = 0; } /* Now write out the actual profile data */ while (ss->icc_position < size) { ulong avail_bytes, num_bytes; avail_bytes = (ulong) (pw->limit - pw->ptr); if (avail_bytes == 0) return 1; num_bytes = (size - ss->icc_position); if (num_bytes > avail_bytes) num_bytes = avail_bytes; memcpy(pw->ptr + 1, ss->icc_profile->buffer + offset + ss->icc_position, num_bytes); ss->icc_position += num_bytes; pw->ptr += num_bytes; } /* Move on to the next marker */ ++ss->icc_marker; ss->icc_position = -1; } dest->next_output_byte = pw->ptr + 1; dest->free_in_buffer = pw->limit - pw->ptr; } ss->phase = 4; /* falls through */ case 4: /* markers written, processing data */ while (jcdp->cinfo.image_height > jcdp->cinfo.next_scanline) { int written; /* * The data argument for jpeg_write_scanlines is * declared as a JSAMPARRAY. There is no corresponding * const type, so we must remove const from the * argument that we are passing here. (Tom Lane of IJG * judges that providing const analogues of the * interface types wouldn't be worth the trouble.) */ /*const */ byte *samples = (byte *) (pr->ptr + 1); if_debug1('w', "[wde]next_scanline=%u\n", jcdp->cinfo.next_scanline); if ((uint) (pr->limit - pr->ptr) < ss->scan_line_size) { if (last) return ERRC; /* premature EOD */ return 0; /* need more data */ } written = gs_jpeg_write_scanlines(ss, &samples, 1); if (written < 0) return ERRC; if_debug3('w', "[wde]write returns %d, used=%u, written=%u\n", written, (uint) (samples - 1 - pr->ptr), (uint) (dest->next_output_byte - 1 - pw->ptr)); pw->ptr = dest->next_output_byte - 1; if (!written) return 1; /* output full */ pr->ptr += ss->scan_line_size; } ss->phase = 5; /* falls through */ case 5: /* all data processed, finishing */ /* jpeg_finish_compress can't suspend, so write its output * to a fixed-size internal buffer. */ dest->next_output_byte = jcdp->finish_compress_buf; dest->free_in_buffer = sizeof(jcdp->finish_compress_buf); if (gs_jpeg_finish_compress(ss) < 0) return ERRC; jcdp->fcb_size = dest->next_output_byte - jcdp->finish_compress_buf; jcdp->fcb_pos = 0; ss->phase = 6; /* falls through */ case 6: /* copy the final data to the output */ if (jcdp->fcb_pos < jcdp->fcb_size) { int count = min(jcdp->fcb_size - jcdp->fcb_pos, pw->limit - pw->ptr); if_debug1('w', "[wde]copying final %d\n", count); memcpy(pw->ptr + 1, jcdp->finish_compress_buf + jcdp->fcb_pos, count); jcdp->fcb_pos += count; pw->ptr += count; if (jcdp->fcb_pos < jcdp->fcb_size) return 1; } return EOFC; }