/* Common code shared between remap and concretize */ static int gx_ciea_to_icc(gs_color_space **ppcs_icc, gs_color_space *pcs, gs_memory_t *memory) { int code; gs_color_space *palt_cs = pcs->base_space; gx_cie_vector_cache *a_cache = &(pcs->params.a->caches.DecodeA); gx_cie_scalar_cache *lmn_caches = &(pcs->params.a->common.caches.DecodeLMN[0]); if_debug0m(gs_debug_flag_icc, memory, "[icc] Creating ICC profile from CIEA object"); /* build the ICC color space object */ code = gs_cspace_build_ICC(ppcs_icc, NULL, memory); if (code < 0) return gs_rethrow(code, "Failed to create ICC profile"); /* record the cie alt space as the icc alternative color space */ (*ppcs_icc)->base_space = palt_cs; rc_increment_cs(palt_cs); (*ppcs_icc)->cmm_icc_profile_data = gsicc_profile_new(NULL, memory, NULL, 0); if ((*ppcs_icc)->cmm_icc_profile_data == NULL) gs_throw(gs_error_VMerror, "Failed to create ICC profile"); code = gsicc_create_froma(pcs, &((*ppcs_icc)->cmm_icc_profile_data->buffer), &((*ppcs_icc)->cmm_icc_profile_data->buffer_size), memory, a_cache, lmn_caches); if (code < 0) return gs_rethrow(code, "Failed to create ICC profile from CIEA"); code = gsicc_init_profile_info((*ppcs_icc)->cmm_icc_profile_data); if (code < 0) return gs_rethrow(code, "Failed to build ICC profile from CIEDEF"); (*ppcs_icc)->cmm_icc_profile_data->default_match = CIE_A; /* Assign to the icc_equivalent member variable */ pcs->icc_equivalent = *ppcs_icc; pcs->icc_equivalent->cmm_icc_profile_data->data_cs = gsGRAY; return 0; }
/* Install a ICC type color space and use the ICC LABLUT profile. */ int seticc_lab(i_ctx_t * i_ctx_p, float *white, float *black, float *range_buff) { int code; gs_color_space * pcs; gs_color_space * palt_cs; gs_imager_state * pis = (gs_imager_state *)igs; int i; static const char *const rfs = LAB_ICC; gs_param_string val, *pval; val.data = (const byte *)rfs; val.size = strlen(rfs); val.persistent = true; pval = &val; palt_cs = gs_currentcolorspace(igs); /* build the color space object */ code = gs_cspace_build_ICC(&pcs, NULL, gs_state_memory(igs)); if (code < 0) return gs_rethrow(code, "building color space object"); /* record the current space as the alternative color space */ /* pcs->base_space = palt_cs; rc_increment_cs(palt_cs); */ /* Get the lab profile. It may already be set in the icc manager. If not then lets populate it. */ if (pis->icc_manager->lab_profile == NULL ) { /* This can't happen as the profile should be initialized during the setting of the user params */ return gs_rethrow(code, "cannot find lab icc profile"); } /* Assign the LAB to LAB profile to this color space */ code = gsicc_set_gscs_profile(pcs, pis->icc_manager->lab_profile, gs_state_memory(igs)); rc_increment(pis->icc_manager->lab_profile); if (code < 0) return gs_rethrow(code, "installing the lab profile"); pcs->cmm_icc_profile_data->Range.ranges[0].rmin = 0.0; pcs->cmm_icc_profile_data->Range.ranges[0].rmax = 100.0; for (i = 1; i < 3; i++) { pcs->cmm_icc_profile_data->Range.ranges[i].rmin = range_buff[2 * (i-1)]; pcs->cmm_icc_profile_data->Range.ranges[i].rmax = range_buff[2 * (i-1) + 1]; } /* Set the color space. We are done. */ code = gs_setcolorspace(igs, pcs); return code; }
/* Render a CIEBasedA color. */ int gx_concretize_CIEA(const gs_client_color * pc, const gs_color_space * pcs_in, frac * pconc, const gs_imager_state * pis, gx_device *dev) { int code = 0; gs_color_space *pcs_icc; gs_client_color scale_pc; gs_color_space *pcs = (gs_color_space *) pcs_in; if_debug1m('c', dev->memory, "[c]concretize CIEA %g\n", pc->paint.values[0]); /* If we are comming in here then we have not completed the conversion of the CIE A space to an ICC type. We will finish that process now. */ if (pcs->icc_equivalent == NULL) { code = gx_ciea_to_icc(&pcs_icc, pcs, pis->memory->stable_memory); if (code < 0) return gs_rethrow(code, "Failed to create ICC profile from CIEA"); } else { /* Once the ICC color space is set, we should be doing all the remaps through the ICC equivalent */ 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.a->RangeA), 1)) { return (pcs_icc->type->concretize_color)(pc, pcs_icc, pconc, pis, dev); } /* Do the rescale from 0 to 1 */ rescale_input_color(&(pcs->params.a->RangeA), 1, pc, &scale_pc); /* Now the icc remap */ return (pcs_icc->type->concretize_color)(&scale_pc, pcs_icc, pconc, pis, dev); }
static int xps_paint_tiling_brush(const gs_client_color *pcc, gs_state *pgs) { const gs_client_pattern *ppat = gs_getpattern(pcc); struct tile_closure_s *c = ppat->client_data; xps_context_t *ctx = c->ctx; gs_state *saved_pgs; int code; saved_pgs = ctx->pgs; ctx->pgs = pgs; gs_gsave(ctx->pgs); code = xps_paint_tiling_brush_clipped(c); if (code) goto cleanup; gs_grestore(ctx->pgs); if (c->tile_mode == TILE_FLIP_X || c->tile_mode == TILE_FLIP_X_Y) { gs_gsave(ctx->pgs); gs_translate(ctx->pgs, c->viewbox.q.x * 2, 0.0); gs_scale(ctx->pgs, -1.0, 1.0); code = xps_paint_tiling_brush_clipped(c); if (code) goto cleanup; gs_grestore(ctx->pgs); } if (c->tile_mode == TILE_FLIP_Y || c->tile_mode == TILE_FLIP_X_Y) { gs_gsave(ctx->pgs); gs_translate(ctx->pgs, 0.0, c->viewbox.q.y * 2); gs_scale(ctx->pgs, 1.0, -1.0); code = xps_paint_tiling_brush_clipped(c); if (code) goto cleanup; gs_grestore(ctx->pgs); } if (c->tile_mode == TILE_FLIP_X_Y) { gs_gsave(ctx->pgs); gs_translate(ctx->pgs, c->viewbox.q.x * 2, c->viewbox.q.y * 2); gs_scale(ctx->pgs, -1.0, -1.0); code = xps_paint_tiling_brush_clipped(c); if (code) goto cleanup; gs_grestore(ctx->pgs); } ctx->pgs = saved_pgs; return 0; cleanup: gs_grestore(ctx->pgs); ctx->pgs = saved_pgs; return gs_rethrow(code, "cannot draw tile"); }
static int xps_remap_pattern(const gs_client_color *pcc, gs_state *pgs) { const gs_client_pattern *ppat = gs_getpattern(pcc); struct tile_closure_s *c = ppat->client_data; xps_context_t *ctx = c->ctx; int code; /* pgs->device is the newly created pattern accumulator, but we want to test the device * that is 'behind' that, the actual output device, so we use the one from * the saved XPS graphics state. */ code = dev_proc(ctx->pgs->device, dev_spec_op)(ctx->pgs->device, gxdso_pattern_can_accum, ppat, ppat->uid.id); if (code == 1) { /* Device handles high-level patterns, so return 'remap'. * This closes the internal accumulator device, as we no longer need * it, and the error trickles back up to the PDL client. The client * must then take action to start the device's accumulator, draw the * pattern, close the device's accumulator and generate a cache entry. */ return gs_error_Remap_Color; } else { code = xps_paint_tiling_brush(pcc, pgs); if (code) return gs_rethrow(code, "remap pattern brush function failed"); return 0; } }
int gx_concretize_CIEABC(const gs_client_color * pc, const gs_color_space * pcs_in, frac * pconc, const gs_imager_state * pis, gx_device *dev) { gs_color_space *pcs_icc; gs_client_color scale_pc; bool islab; gs_color_space *pcs = (gs_color_space *) pcs_in; int code = 0; if_debug3m('c', pis->memory, "[c]concretize CIEABC [%g %g %g]\n", pc->paint.values[0], pc->paint.values[1], pc->paint.values[2]); /* If we are comming in here then we have not completed the conversion of the ABC space to an ICC type. We will finish that process now. */ if (pcs->icc_equivalent == NULL) { code = gx_cieabc_to_icc(&pcs_icc, pcs, &islab, pis->memory->stable_memory); if (code < 0) return gs_rethrow(code, "Failed to create ICC profile from CIEABC"); } 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.abc->RangeABC.ranges[0]), 3)) { return (pcs_icc->type->concretize_color)(pc, pcs_icc, pconc, pis, dev); } /* Do the rescale from 0 to 1 */ rescale_input_color(&(pcs->params.abc->RangeABC.ranges[0]), 3, pc, &scale_pc); /* Now the icc remap */ return (pcs_icc->type->concretize_color)(&scale_pc, pcs_icc, pconc, pis, dev); }
gslt_font_t * gslt_new_font(gs_memory_t *mem, gs_font_dir *fontdir, char *buf, int buflen, int subfontid) { gslt_font_t *xf; int t; xf = (void*) gs_alloc_bytes(mem, sizeof(gslt_font_t), "gslt_font struct"); if (!xf) { gs_throw(-1, "out of memory"); return NULL; } xf->data = (byte*)buf; xf->length = buflen; xf->font = NULL; xf->subfontid = subfontid; xf->cmaptable = 0; xf->cmapsubcount = 0; xf->cmapsubtable = 0; xf->usepua = 0; xf->cffdata = 0; xf->cffend = 0; xf->gsubrs = 0; xf->subrs = 0; xf->charstrings = 0; if (memcmp(xf->data, "OTTO", 4) == 0) t = gslt_init_postscript_font(mem, fontdir, xf); else if (memcmp(xf->data, "\0\1\0\0", 4) == 0) t = gslt_init_truetype_font(mem, fontdir, xf); else if (memcmp(xf->data, "true", 4) == 0) t = gslt_init_truetype_font(mem, fontdir, xf); else if (memcmp(xf->data, "ttcf", 4) == 0) t = gslt_init_truetype_font(mem, fontdir, xf); else { gslt_free_font(mem, xf); gs_throw(-1, "not an opentype font"); return NULL; } if (t < 0) { gslt_free_font(mem, xf); gs_rethrow(-1, "cannot init font"); return NULL; } t = gslt_load_sfnt_cmap(xf); if (t < 0) { errprintf("warning: no cmap table found in font\n"); } return xf; }
int xps_begin_opacity(xps_context_t *ctx, char *base_uri, xps_resource_t *dict, char *opacity_att, xps_item_t *opacity_mask_tag) { gs_transparency_group_params_t tgp; gs_transparency_mask_params_t tmp; gs_rect bbox; float opacity; int save; int code; if (!opacity_att && !opacity_mask_tag) return 0; opacity = 1.0; if (opacity_att) opacity = atof(opacity_att); gs_setopacityalpha(ctx->pgs, opacity); xps_bounds_in_user_space(ctx, &bbox); if (opacity_mask_tag) { gs_trans_mask_params_init(&tmp, TRANSPARENCY_MASK_Luminosity); gs_begin_transparency_mask(ctx->pgs, &tmp, &bbox, 0); gs_gsave(ctx->pgs); /* Need a path to fill/clip for the brush */ gs_moveto(ctx->pgs, bbox.p.x, bbox.p.y); gs_lineto(ctx->pgs, bbox.p.x, bbox.q.y); gs_lineto(ctx->pgs, bbox.q.x, bbox.q.y); gs_lineto(ctx->pgs, bbox.q.x, bbox.p.y); gs_closepath(ctx->pgs); /* opacity-only mode: use alpha value as gray color to create luminosity mask */ save = ctx->opacity_only; ctx->opacity_only = 1; code = xps_parse_brush(ctx, base_uri, dict, opacity_mask_tag); if (code) { gs_grestore(ctx->pgs); gs_end_transparency_mask(ctx->pgs, TRANSPARENCY_CHANNEL_Opacity); ctx->opacity_only = save; return gs_rethrow(code, "cannot parse opacity mask brush"); } gs_grestore(ctx->pgs); gs_end_transparency_mask(ctx->pgs, TRANSPARENCY_CHANNEL_Opacity); ctx->opacity_only = save; } gs_trans_group_params_init(&tgp); gs_begin_transparency_group(ctx->pgs, &tgp, &bbox); return 0; }
/* Install an ICC space from the PDF CalRGB or CalGray types */ int seticc_cal(i_ctx_t * i_ctx_p, float *white, float *black, float *gamma, float *matrix, int num_colorants, ulong dictkey) { int code; gs_color_space * pcs; gs_imager_state * pis = (gs_imager_state *)igs; gs_memory_t *mem = pis->memory; int i; cmm_profile_t *cal_profile; /* See if the color space is in the profile cache */ pcs = gsicc_find_cs(dictkey, igs); if (pcs == NULL ) { /* build the color space object. Since this is cached in the profile cache which is a member variable of the graphic state, we will want to use stable memory here */ code = gs_cspace_build_ICC(&pcs, NULL, mem->stable_memory); if (code < 0) return gs_rethrow(code, "building color space object"); /* There is no alternate for this. Perhaps we should set DeviceRGB? */ pcs->base_space = NULL; /* Create the ICC profile from the CalRGB or CalGray parameters */ cal_profile = gsicc_create_from_cal(white, black, gamma, matrix, mem->stable_memory, num_colorants); if (cal_profile == NULL) return gs_rethrow(-1, "creating the cal profile"); /* Assign the profile to this color space */ code = gsicc_set_gscs_profile(pcs, cal_profile, mem->stable_memory); if (code < 0) return gs_rethrow(code, "installing the cal profile"); for (i = 0; i < num_colorants; i++) { pcs->cmm_icc_profile_data->Range.ranges[i].rmin = 0; pcs->cmm_icc_profile_data->Range.ranges[i].rmax = 1; } /* Add the color space to the profile cache */ gsicc_add_cs(igs, pcs,dictkey); } /* Set the color space. We are done. */ code = gs_setcolorspace(igs, pcs); return code; }
xps_font_t * xps_new_font(xps_context_t *ctx, byte *buf, int buflen, int index) { xps_font_t *font; int code; font = xps_alloc(ctx, sizeof(xps_font_t)); if (!font) { gs_throw(gs_error_VMerror, "out of memory"); return NULL; } font->data = buf; font->length = buflen; font->font = NULL; font->subfontid = index; font->cmaptable = 0; font->cmapsubcount = 0; font->cmapsubtable = 0; font->usepua = 0; font->cffdata = 0; font->cffend = 0; font->gsubrs = 0; font->subrs = 0; font->charstrings = 0; if (memcmp(font->data, "OTTO", 4) == 0) code = xps_init_postscript_font(ctx, font); else if (memcmp(font->data, "\0\1\0\0", 4) == 0) code = xps_init_truetype_font(ctx, font); else if (memcmp(font->data, "true", 4) == 0) code = xps_init_truetype_font(ctx, font); else if (memcmp(font->data, "ttcf", 4) == 0) code = xps_init_truetype_font(ctx, font); else { xps_free_font(ctx, font); gs_throw(-1, "not an opentype font"); return NULL; } if (code < 0) { xps_free_font(ctx, font); gs_rethrow(-1, "cannot init font"); return NULL; } xps_load_sfnt_cmap(font); return font; }
static int xps_paint_tiling_brush_clipped(struct tile_closure_s *c) { xps_context_t *ctx = c->ctx; int code; gs_moveto(ctx->pgs, c->viewbox.p.x, c->viewbox.p.y); gs_lineto(ctx->pgs, c->viewbox.p.x, c->viewbox.q.y); gs_lineto(ctx->pgs, c->viewbox.q.x, c->viewbox.q.y); gs_lineto(ctx->pgs, c->viewbox.q.x, c->viewbox.p.y); gs_closepath(ctx->pgs); gs_clip(ctx->pgs); gs_newpath(ctx->pgs); code = c->func(c->ctx, c->base_uri, c->dict, c->tag, c->user); if (code < 0) return gs_rethrow(code, "cannot draw clipped tile"); return 0; }
/* needs to be efficient. */ int gx_remap_CIEABC(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; gs_client_color scale_pc; bool islab; int i, code; gs_color_space *pcs = (gs_color_space *) pcs_in; if_debug3m('c', pis->memory, "[c]remap CIEABC [%g %g %g]\n", pc->paint.values[0], pc->paint.values[1], pc->paint.values[2]); /* If we are comming in here then we have not completed the conversion of the ABC space to an ICC type. We will finish that process now. */ if (pcs->icc_equivalent == NULL) { code = gx_cieabc_to_icc(&pcs_icc, pcs, &islab, pis->memory->stable_memory); if (code < 0) return gs_rethrow(code, "Failed to create ICC profile from CIEABC"); } 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.abc->RangeABC.ranges[0]), 3)) { 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.abc->RangeABC.ranges[0]), 3, 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 < 3; i++) pdc->ccolor.paint.values[i] = pc->paint.values[i]; pdc->ccolor_valid = true; /* Now the icc remap */ return code; }
/* * Switch on file magic to decode an image. */ gslt_image_t * gslt_image_decode(gs_memory_t *mem, byte *buf, int len) { gslt_image_t *image = NULL; int error = gs_okay; if (buf[0] == 0xff && buf[1] == 0xd8) image = gslt_image_decode_jpeg(mem, buf, len); else if (memcmp(buf, "\211PNG\r\n\032\n", 8) == 0) image = gslt_image_decode_png(mem, buf, len); else if (memcmp(buf, "MM", 2) == 0) image = gslt_image_decode_tiff(mem, buf, len); else if (memcmp(buf, "II", 2) == 0) image = gslt_image_decode_tiff(mem, buf, len); else error = gs_throw(-1, "unknown image file format"); if (image == NULL) error = gs_rethrow(error, "could not decode image"); return image; }
int gx_remap_CIEA(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) { int code; gs_color_space *pcs_icc; gs_client_color scale_pc; gs_color_space *pcs = (gs_color_space *) pcs_in; if_debug1m('c', dev->memory, "[c]remap CIEA [%g]\n",pc->paint.values[0]); /* If we are coming in here then we may have not completed the conversion of the CIE A space to an ICC type. We will finish that process now. */ if (pcs->icc_equivalent == NULL) { code = gx_ciea_to_icc(&pcs_icc, pcs, pis->memory->stable_memory); if (code < 0) return gs_rethrow(code, "Failed to create ICC profile from CIEA"); } else { /* Once the ICC color space is set, we should be doing all the remaps through the ICC equivalent */ 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.a->RangeA), 1)) { 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.a->RangeA), 1, 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) */ pdc->ccolor.paint.values[0] = pc->paint.values[0]; pdc->ccolor_valid = true; return code; }
int xps_parse_fixed_page(xps_context_t *ctx, xps_part_t *part) { xps_item_t *root, *node; xps_resource_t *dict; char *width_att; char *height_att; char base_uri[1024]; char *s; int code; if_debug1m('|', ctx->memory, "doc: parsing page %s\n", part->name); xps_strlcpy(base_uri, part->name, sizeof base_uri); s = strrchr(base_uri, '/'); if (s) s[1] = 0; root = xps_parse_xml(ctx, part->data, part->size); if (!root) return gs_rethrow(-1, "cannot parse xml"); if (strcmp(xps_tag(root), "FixedPage")) return gs_throw1(-1, "expected FixedPage element (found %s)", xps_tag(root)); width_att = xps_att(root, "Width"); height_att = xps_att(root, "Height"); if (!width_att) return gs_throw(-1, "FixedPage missing required attribute: Width"); if (!height_att) return gs_throw(-1, "FixedPage missing required attribute: Height"); dict = NULL; /* Setup new page */ { gs_memory_t *mem = ctx->memory; gs_state *pgs = ctx->pgs; gx_device *dev = gs_currentdevice(pgs); gs_param_float_array fa; float fv[2]; gs_c_param_list list; gs_c_param_list_write(&list, mem); fv[0] = atoi(width_att) / 96.0 * 72.0; fv[1] = atoi(height_att) / 96.0 * 72.0; fa.persistent = false; fa.data = fv; fa.size = 2; code = param_write_float_array((gs_param_list *)&list, ".MediaSize", &fa); if ( code >= 0 ) { gs_c_param_list_read(&list); code = gs_putdeviceparams(dev, (gs_param_list *)&list); } gs_c_param_list_release(&list); /* nb this is for the demo it is wrong and should be removed */ gs_initgraphics(pgs); /* 96 dpi default - and put the origin at the top of the page */ gs_initmatrix(pgs); code = gs_scale(pgs, 72.0/96.0, -72.0/96.0); if (code < 0) return gs_rethrow(code, "cannot set page transform"); code = gs_translate(pgs, 0.0, -atoi(height_att)); if (code < 0) return gs_rethrow(code, "cannot set page transform"); code = gs_erasepage(pgs); if (code < 0) return gs_rethrow(code, "cannot clear page"); } /* Pre-parse looking for transparency */ ctx->has_transparency = 0; for (node = xps_down(root); node; node = xps_next(node)) { if (!strcmp(xps_tag(node), "FixedPage.Resources") && xps_down(node)) if (xps_resource_dictionary_has_transparency(ctx, base_uri, xps_down(node))) ctx->has_transparency = 1; if (xps_element_has_transparency(ctx, base_uri, node)) ctx->has_transparency = 1; } /* save the state with the original device before we push */ gs_gsave(ctx->pgs); if (ctx->use_transparency && ctx->has_transparency) { code = gs_push_pdf14trans_device(ctx->pgs, false); if (code < 0) { gs_grestore(ctx->pgs); return gs_rethrow(code, "cannot install transparency device"); } } /* Draw contents */ for (node = xps_down(root); node; node = xps_next(node)) { if (!strcmp(xps_tag(node), "FixedPage.Resources") && xps_down(node)) { code = xps_parse_resource_dictionary(ctx, &dict, base_uri, xps_down(node)); if (code) { gs_pop_pdf14trans_device(ctx->pgs, false); gs_grestore(ctx->pgs); return gs_rethrow(code, "cannot load FixedPage.Resources"); } } code = xps_parse_element(ctx, base_uri, dict, node); if (code) { gs_pop_pdf14trans_device(ctx->pgs, false); gs_grestore(ctx->pgs); return gs_rethrow(code, "cannot parse child of FixedPage"); } } if (ctx->use_transparency && ctx->has_transparency) { code = gs_pop_pdf14trans_device(ctx->pgs, false); if (code < 0) { gs_grestore(ctx->pgs); return gs_rethrow(code, "cannot uninstall transparency device"); } } /* Flush page */ { code = xps_show_page(ctx, 1, true); /* copies, flush */ if (code < 0) { gs_grestore(ctx->pgs); return gs_rethrow(code, "cannot flush page"); } } /* restore the original device, discarding the pdf14 compositor */ gs_grestore(ctx->pgs); if (dict) { xps_free_resource_dictionary(ctx, dict); } xps_free_item(ctx, root); return 0; }
int xps_high_level_pattern(xps_context_t *ctx) { gs_matrix m; gs_rect bbox; gs_fixed_rect clip_box; int code; gx_device_color *pdc = gs_currentdevicecolor_inline(ctx->pgs); const gs_client_pattern *ppat = gs_getpattern(&pdc->ccolor); gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)gs_currentcolor(ctx->pgs)->pattern; code = gx_pattern_cache_add_dummy_entry((gs_imager_state *)ctx->pgs, pinst, ctx->pgs->device->color_info.depth); if (code < 0) return code; code = gs_gsave(ctx->pgs); if (code < 0) return code; dev_proc(ctx->pgs->device, get_initial_matrix)(ctx->pgs->device, &m); gs_setmatrix(ctx->pgs, &m); code = gs_bbox_transform(&ppat->BBox, &ctm_only(ctx->pgs), &bbox); if (code < 0) { gs_grestore(ctx->pgs); return code; } clip_box.p.x = float2fixed(bbox.p.x); clip_box.p.y = float2fixed(bbox.p.y); clip_box.q.x = float2fixed(bbox.q.x); clip_box.q.y = float2fixed(bbox.q.y); code = gx_clip_to_rectangle(ctx->pgs, &clip_box); if (code < 0) { gs_grestore(ctx->pgs); return code; } { pattern_accum_param_s param; param.pinst = (void *)pinst; param.graphics_state = (void *)ctx->pgs; param.pinst_id = pinst->id; code = (*dev_proc(ctx->pgs->device, dev_spec_op))((gx_device *)ctx->pgs->device, gxdso_pattern_start_accum, ¶m, sizeof(pattern_accum_param_s)); } if (code < 0) { gs_grestore(ctx->pgs); return code; } code = xps_paint_tiling_brush(&pdc->ccolor, ctx->pgs); if (code) { gs_grestore(ctx->pgs); return gs_rethrow(code, "high level pattern brush function failed"); } code = gs_grestore(ctx->pgs); if (code < 0) return code; { pattern_accum_param_s param; param.pinst = (void *)pinst; param.graphics_state = (void *)ctx->pgs; param.pinst_id = pinst->id; code = (*dev_proc(ctx->pgs->device, dev_spec_op))((gx_device *)ctx->pgs->device, gxdso_pattern_finish_accum, ¶m, sizeof(pattern_accum_param_s)); } return code; }
int seticc(i_ctx_t * i_ctx_p, int ncomps, ref *ICCdict, float *range_buff) { int code, k; gs_color_space * pcs; gs_color_space * palt_cs; ref * pstrmval; stream * s = 0L; cmm_profile_t *picc_profile; gs_imager_state * pis = (gs_imager_state *)igs; int i, expected = 0; ref * pnameval; static const char *const icc_std_profile_names[] = { GSICC_STANDARD_PROFILES }; static const char *const icc_std_profile_keys[] = { GSICC_STANDARD_PROFILES_KEYS }; palt_cs = gs_currentcolorspace(igs); /* verify the DataSource entry */ if (dict_find_string(ICCdict, "DataSource", &pstrmval) <= 0) return_error(e_undefined); check_read_file(i_ctx_p, s, pstrmval); /* build the color space object */ code = gs_cspace_build_ICC(&pcs, NULL, gs_state_memory(igs)); if (code < 0) return gs_rethrow(code, "building color space object"); /* For now, dump the profile into a buffer and obtain handle from the buffer when we need it. We may want to change this later. This depends to some degree on what the CMS is capable of doing. I don't want to get bogged down on stream I/O at this point. Note also, if we are going to be putting these into the clist we will want to have this buffer. */ /* Check if we have the /Name entry. This is used to associate with specs that have enumerated types to indicate sRGB sGray etc */ if (dict_find_string(ICCdict, "Name", &pnameval) > 0){ uint size = r_size(pnameval); char *str = (char *)gs_alloc_bytes(gs_state_memory(igs), size+1, "seticc"); memcpy(str, (const char *)pnameval->value.bytes, size); str[size] = 0; /* Compare this to the standard profile names */ picc_profile = NULL; for (k = 0; k < GSICC_NUMBER_STANDARD_PROFILES; k++) { if ( strcmp( str, icc_std_profile_keys[k] ) == 0 ) { picc_profile = gsicc_get_profile_handle_file(icc_std_profile_names[k], strlen(icc_std_profile_names[k]), gs_state_memory(igs)); break; } } } else { picc_profile = gsicc_profile_new(s, gs_state_memory(igs), NULL, 0); } if (picc_profile == NULL) { rc_decrement(picc_profile,"seticc"); rc_decrement(pcs,"seticc"); return -1; } code = gsicc_set_gscs_profile(pcs, picc_profile, gs_state_memory(igs)); if (code < 0) { rc_decrement(picc_profile,"seticc"); rc_decrement(pcs,"seticc"); return code; } picc_profile->num_comps = ncomps; /* We have to get the profile handle due to the fact that we need to know if it has a data space that is CIELAB */ picc_profile->profile_handle = gsicc_get_profile_handle_buffer(picc_profile->buffer, picc_profile->buffer_size, gs_state_memory(igs)); if (picc_profile->profile_handle == NULL) { /* Free up everything, the profile is not valid. We will end up going ahead and using a default based upon the number of components */ rc_decrement(picc_profile,"seticc"); rc_decrement(pcs,"seticc"); return -1; } picc_profile->data_cs = gscms_get_profile_data_space(picc_profile->profile_handle); switch( picc_profile->data_cs ) { case gsCIEXYZ: case gsCIELAB: case gsRGB: expected = 3; break; case gsGRAY: expected = 1; break; case gsCMYK: expected = 4; break; case gsNCHANNEL: case gsNAMED: /* Silence warnings */ case gsUNDEFINED: /* Silence warnings */ break; } if (!expected || ncomps != expected) { rc_decrement(picc_profile,"seticc"); rc_decrement(pcs,"seticc"); return_error(e_rangecheck); } /* Lets go ahead and get the hash code and check if we match one of the default spaces */ /* Later we may want to delay this, but for now lets go ahead and do it */ gsicc_init_hash_cs(picc_profile, pis); /* Set the range according to the data type that is associated with the ICC input color type. Occasionally, we will run into CIELAB to CIELAB profiles for spot colors in PDF documents. These spot colors are typically described as separation colors with tint transforms that go from a tint value to a linear mapping between the CIELAB white point and the CIELAB tint color. This results in a CIELAB value that we need to use to fill. We need to detect this to make sure we do the proper scaling of the data. For CIELAB images in PDF, the source is always normal 8 or 16 bit encoded data in the range from 0 to 255 or 0 to 65535. In that case, there should not be any encoding and decoding to CIELAB. The PDF content will not include an ICC profile but will set the color space to \Lab. In this case, we use our seticc_lab operation to install the LAB to LAB profile, but we detect that we did that through the use of the is_lab flag in the profile descriptor. When then avoid the CIELAB encode and decode */ if (picc_profile->data_cs == gsCIELAB) { /* If the input space to this profile is CIELAB, then we need to adjust the limits */ /* See ICC spec ICC.1:2004-10 Section 6.3.4.2 and 6.4. I don't believe we need to worry about CIEXYZ profiles or any of the other odds ones. Need to check that though at some point. */ picc_profile->Range.ranges[0].rmin = 0.0; picc_profile->Range.ranges[0].rmax = 100.0; picc_profile->Range.ranges[1].rmin = -128.0; picc_profile->Range.ranges[1].rmax = 127.0; picc_profile->Range.ranges[2].rmin = -128.0; picc_profile->Range.ranges[2].rmax = 127.0; picc_profile->islab = true; } else { for (i = 0; i < ncomps; i++) { picc_profile->Range.ranges[i].rmin = range_buff[2 * i]; picc_profile->Range.ranges[i].rmax = range_buff[2 * i + 1]; } } /* Now see if we are in an overide situation. We have to wait until now in case this is an LAB profile which we will not overide */ if (gs_currentoverrideicc(pis) && picc_profile->data_cs != gsCIELAB) { /* Free up the profile structure */ switch( picc_profile->data_cs ) { case gsRGB: pcs->cmm_icc_profile_data = pis->icc_manager->default_rgb; break; case gsGRAY: pcs->cmm_icc_profile_data = pis->icc_manager->default_gray; break; case gsCMYK: pcs->cmm_icc_profile_data = pis->icc_manager->default_cmyk; break; default: break; } /* Have one increment from the color space. Having these tied together is not really correct. Need to fix that. ToDo. MJV */ rc_adjust(picc_profile, -2, "seticc"); rc_increment(pcs->cmm_icc_profile_data); } /* Set the color space. We are done. No joint cache here... */ code = gs_setcolorspace(igs, pcs); /* The context has taken a reference to the colorspace. We no longer need * ours, so drop it. */ rc_decrement_only(pcs, "seticc"); /* In this case, we already have a ref count of 2 on the icc profile one for when it was created and one for when it was set. We really only want one here so adjust */ rc_decrement(picc_profile,"seticc"); /* Remove the ICC dict from the stack */ pop(1); return code; }
int xps_parse_tiling_brush(xps_context_t *ctx, char *base_uri, xps_resource_t *dict, xps_item_t *root, int (*func)(xps_context_t*, char*, xps_resource_t*, xps_item_t*, void*), void *user) { xps_item_t *node; int code; char *opacity_att; char *transform_att; char *viewbox_att; char *viewport_att; char *tile_mode_att; /*char *viewbox_units_att;*/ /*char *viewport_units_att;*/ xps_item_t *transform_tag = NULL; gs_matrix transform; gs_rect viewbox; gs_rect viewport; float scalex, scaley; int tile_mode; opacity_att = xps_att(root, "Opacity"); transform_att = xps_att(root, "Transform"); viewbox_att = xps_att(root, "Viewbox"); viewport_att = xps_att(root, "Viewport"); tile_mode_att = xps_att(root, "TileMode"); /*viewbox_units_att = xps_att(root, "ViewboxUnits");*/ /*viewport_units_att = xps_att(root, "ViewportUnits");*/ for (node = xps_down(root); node; node = xps_next(node)) { if (!strcmp(xps_tag(node), "ImageBrush.Transform")) transform_tag = xps_down(node); if (!strcmp(xps_tag(node), "VisualBrush.Transform")) transform_tag = xps_down(node); } xps_resolve_resource_reference(ctx, dict, &transform_att, &transform_tag, NULL); gs_make_identity(&transform); if (transform_att) xps_parse_render_transform(ctx, transform_att, &transform); if (transform_tag) xps_parse_matrix_transform(ctx, transform_tag, &transform); viewbox.p.x = 0.0; viewbox.p.y = 0.0; viewbox.q.x = 1.0; viewbox.q.y = 1.0; if (viewbox_att) xps_parse_rectangle(ctx, viewbox_att, &viewbox); viewport.p.x = 0.0; viewport.p.y = 0.0; viewport.q.x = 1.0; viewport.q.y = 1.0; if (viewport_att) xps_parse_rectangle(ctx, viewport_att, &viewport); /* some sanity checks on the viewport/viewbox size */ if (fabs(viewport.q.x - viewport.p.x) < 0.01) { gs_warn("skipping tile with zero width view port"); return 0; } if (fabs(viewport.q.y - viewport.p.y) < 0.01) { gs_warn("skipping tile with zero height view port"); return 0; } if (fabs(viewbox.q.x - viewbox.p.x) < 0.01) { gs_warn("skipping tile with zero width view box"); return 0; } if (fabs(viewbox.q.y - viewbox.p.y) < 0.01) { gs_warn("skipping tile with zero height view box"); return 0; } scalex = (viewport.q.x - viewport.p.x) / (viewbox.q.x - viewbox.p.x); scaley = (viewport.q.y - viewport.p.y) / (viewbox.q.y - viewbox.p.y); tile_mode = TILE_NONE; if (tile_mode_att) { if (!strcmp(tile_mode_att, "None")) tile_mode = TILE_NONE; if (!strcmp(tile_mode_att, "Tile")) tile_mode = TILE_TILE; if (!strcmp(tile_mode_att, "FlipX")) tile_mode = TILE_FLIP_X; if (!strcmp(tile_mode_att, "FlipY")) tile_mode = TILE_FLIP_Y; if (!strcmp(tile_mode_att, "FlipXY")) tile_mode = TILE_FLIP_X_Y; } gs_gsave(ctx->pgs); code = xps_begin_opacity(ctx, base_uri, dict, opacity_att, NULL, false, false); if (code) { gs_grestore(ctx->pgs); return gs_rethrow(code, "cannot create transparency group"); } /* TODO(tor): check viewport and tiling to see if we can set it to TILE_NONE */ if (tile_mode != TILE_NONE) { struct tile_closure_s closure; gs_client_pattern gspat; gs_client_color gscolor; gs_color_space *cs; bool sa; closure.ctx = ctx; closure.base_uri = base_uri; closure.dict = dict; closure.tag = root; closure.tile_mode = tile_mode; closure.user = user; closure.func = func; closure.viewbox.p.x = viewbox.p.x; closure.viewbox.p.y = viewbox.p.y; closure.viewbox.q.x = viewbox.q.x; closure.viewbox.q.y = viewbox.q.y; gs_pattern1_init(&gspat); uid_set_UniqueID(&gspat.uid, gs_next_ids(ctx->memory, 1)); gspat.PaintType = 1; gspat.TilingType = 2; gspat.PaintProc = xps_remap_pattern; gspat.client_data = &closure; /* We need to know if this tiling brush includes transparency. We could do a proper scan, but for now we'll be lazy and just look at the flag from scanning the page. */ gspat.uses_transparency = ctx->has_transparency; gspat.XStep = viewbox.q.x - viewbox.p.x; gspat.YStep = viewbox.q.y - viewbox.p.y; gspat.BBox.p.x = viewbox.p.x; gspat.BBox.p.y = viewbox.p.y; gspat.BBox.q.x = viewbox.q.x; gspat.BBox.q.y = viewbox.q.y; if (tile_mode == TILE_FLIP_X || tile_mode == TILE_FLIP_X_Y) { gspat.BBox.q.x += gspat.XStep; gspat.XStep *= 2; } if (tile_mode == TILE_FLIP_Y || tile_mode == TILE_FLIP_X_Y) { gspat.BBox.q.y += gspat.YStep; gspat.YStep *= 2; } gs_matrix_translate(&transform, viewport.p.x, viewport.p.y, &transform); gs_matrix_scale(&transform, scalex, scaley, &transform); gs_matrix_translate(&transform, -viewbox.p.x, -viewbox.p.y, &transform); cs = ctx->srgb; gs_setcolorspace(ctx->pgs, cs); gsicc_profile_reference(cs->cmm_icc_profile_data, 1); sa = gs_currentstrokeadjust(ctx->pgs); gs_setstrokeadjust(ctx->pgs, false); gs_makepattern(&gscolor, &gspat, &transform, ctx->pgs, NULL); gs_setpattern(ctx->pgs, &gscolor); xps_fill(ctx); gs_setstrokeadjust(ctx->pgs, sa); gsicc_profile_reference(cs->cmm_icc_profile_data, -1); /* gs_makepattern increments the pattern count stored in the color * structure. We will discard the color struct (its on the stack) * so we need to decrement the reference before we throw away * the structure. */ gs_pattern_reference(&gscolor, -1); } else { xps_clip(ctx); gs_concat(ctx->pgs, &transform); gs_translate(ctx->pgs, viewport.p.x, viewport.p.y); gs_scale(ctx->pgs, scalex, scaley); gs_translate(ctx->pgs, -viewbox.p.x, -viewbox.p.y); gs_moveto(ctx->pgs, viewbox.p.x, viewbox.p.y); gs_lineto(ctx->pgs, viewbox.p.x, viewbox.q.y); gs_lineto(ctx->pgs, viewbox.q.x, viewbox.q.y); gs_lineto(ctx->pgs, viewbox.q.x, viewbox.p.y); gs_closepath(ctx->pgs); gs_clip(ctx->pgs); gs_newpath(ctx->pgs); code = func(ctx, base_uri, dict, root, user); if (code < 0) { xps_end_opacity(ctx, base_uri, dict, opacity_att, NULL); gs_grestore(ctx->pgs); return gs_rethrow(code, "cannot draw tile"); } } xps_end_opacity(ctx, base_uri, dict, opacity_att, NULL); gs_grestore(ctx->pgs); return 0; }
int gxht_thresh_image_init(gx_image_enum *penum) { int code = 0; fixed ox, oy; int temp; int dev_width, max_height; int spp_out; int k; gx_ht_order *d_order; if (gx_device_must_halftone(penum->dev)) { if (penum->pis != NULL && penum->pis->dev_ht != NULL) { for (k = 0; k < penum->pis->dev_ht->num_comp; k++) { d_order = &(penum->pis->dev_ht->components[k].corder); code = gx_ht_construct_threshold(d_order, penum->dev, penum->pis, k); if (code < 0 ) { return gs_rethrow(code, "threshold creation failed"); } } } else { return -1; } } spp_out = penum->dev->color_info.num_components; /* If the image is landscaped then we want to maintain a buffer that is sufficiently large so that we can hold a byte of halftoned data along the column. This way we avoid doing multiple writes into the same position over and over. The size of the buffer we need depends upon the bitdepth of the output device, the number of device coloranants and the number of colorants in the source space. Note we will need to eventually consider multi-level halftone case here too. For now, to make use of the SSE2 stuff, we would like to have 16 bytes of data to process at a time. So we will collect the columns of data in a buffer that is 16 wide. We will also keep track of the widths of each column. When the total width count reaches 16, we will create our threshold array and apply it. We may have one column that is buffered between calls in this case. Also if a call is made with h=0 we will flush the buffer as we are at the end of the data. */ if (penum->posture == image_landscape) { int col_length = fixed2int_var_rounded(any_abs(penum->x_extent.y)) * spp_out; ox = dda_current(penum->dda.pixel0.x); oy = dda_current(penum->dda.pixel0.y); temp = (int) ceil((float) col_length/16.0); penum->line_size = temp * 16; /* The stride */ /* Now we need at most 16 of these */ penum->line = gs_alloc_bytes(penum->memory, 16 * penum->line_size + 16, "gxht_thresh"); /* Same with this */ penum->thresh_buffer = gs_alloc_bytes(penum->memory, penum->line_size * 16 + 16, "gxht_thresh"); /* That maps into 2 bytes of Halftone data */ penum->ht_buffer = gs_alloc_bytes(penum->memory, penum->line_size * 2, "gxht_thresh"); penum->ht_stride = penum->line_size; if (penum->line == NULL || penum->thresh_buffer == NULL || penum->ht_buffer == NULL) return -1; penum->ht_landscape.count = 0; penum->ht_landscape.num_contones = 0; if (penum->y_extent.x < 0) { /* Going right to left */ penum->ht_landscape.curr_pos = 15; penum->ht_landscape.index = -1; } else { /* Going left to right */ penum->ht_landscape.curr_pos = 0; penum->ht_landscape.index = 1; } if (penum->x_extent.y < 0) { penum->ht_landscape.flipy = true; penum->ht_landscape.y_pos = fixed2int_pixround_perfect(dda_current(penum->dda.pixel0.y) + penum->x_extent.y); } else { penum->ht_landscape.flipy = false; penum->ht_landscape.y_pos = fixed2int_pixround_perfect(dda_current(penum->dda.pixel0.y)); } memset(&(penum->ht_landscape.widths[0]), 0, sizeof(int)*16); penum->ht_landscape.offset_set = false; penum->ht_offset_bits = 0; /* Will get set in call to render */ if (code >= 0) { #if defined(DEBUG) || defined(PACIFY_VALGRIND) memset(penum->line, 0, 16 * penum->line_size + 16); memset(penum->ht_buffer, 0, penum->line_size * 2); memset(penum->thresh_buffer, 0, 16 * penum->line_size + 16); #endif } } else { /* In the portrait case we allocate a single line buffer in device width, a threshold buffer of the same size and possibly wider and the buffer for the halftoned bits. We have to do a bit of work to enable 16 byte boundary after an offset to ensure that we can make use of the SSE2 operations for thresholding. We do the allocations now to avoid doing them with every line */ /* Initialize the ht_landscape stuff to zero */ memset(&(penum->ht_landscape), 0, sizeof(ht_landscape_info_t)); ox = dda_current(penum->dda.pixel0.x); oy = dda_current(penum->dda.pixel0.y); dev_width = (int) fabs((long) fixed2long_pixround(ox + penum->x_extent.x) - fixed2long_pixround(ox)); /* Get the bit position so that we can do a copy_mono for the left remainder and then 16 bit aligned copies for the rest. The right remainder will be OK as it will land in the MSBit positions. Note the #define chunk bits16 in gdevm1.c. Allow also for a 15 sample over run. */ penum->ht_offset_bits = (-fixed2int_var_pixround(ox)) & 15; if (penum->ht_offset_bits > 0) { penum->ht_stride = ((7 + (dev_width + 4)) / 8) + ARCH_SIZEOF_LONG; } else { penum->ht_stride = ((7 + (dev_width + 2)) / 8) + ARCH_SIZEOF_LONG; } /* We want to figure out the maximum height that we may have in taking a single source row and going to device space */ max_height = (int) ceil(fixed2float(any_abs(penum->dst_height)) / (float) penum->Height); penum->ht_buffer = gs_alloc_bytes(penum->memory, penum->ht_stride * max_height * spp_out, "gxht_thresh"); /* We want to have 128 bit alignement for our contone and threshold strips so that we can use SSE operations in the threshold operation. Add in a minor buffer and offset to ensure this. If gs_alloc_bytes provides at least 16 bit alignment so we may need to move 14 bytes. However, the HT process is split in two operations. One that involves the HT of a left remainder and the rest which ensures that we pack in the HT data in the bits with no skew for a fast copy into the gdevm1 device (16 bit copies). So, we need to account for those pixels which occur first and which are NOT aligned for the contone buffer. After we offset by this remainder portion we should be 128 bit aligned. Also allow a 15 sample over run during the execution. */ temp = (int) ceil((float) ((dev_width + 15.0) + 15.0)/16.0); penum->line_size = temp * 16; /* The stride */ penum->line = gs_alloc_bytes(penum->memory, penum->line_size * spp_out, "gxht_thresh"); penum->thresh_buffer = gs_alloc_bytes(penum->memory, penum->line_size * max_height * spp_out, "gxht_thresh"); if (penum->line == NULL || penum->thresh_buffer == NULL || penum->ht_buffer == NULL) { return -1; } else { #if defined(DEBUG) || defined(PACIFY_VALGRIND) memset(penum->line, 0, penum->line_size * spp_out); memset(penum->ht_buffer, 0, penum->ht_stride * max_height * spp_out); memset(penum->thresh_buffer, 0, penum->line_size * max_height * spp_out); #endif } } /* Precompute values needed for rasterizing. */ penum->dxx = float2fixed(penum->matrix.xx + fixed2float(fixed_epsilon) / 2); return code; }
/* This performs a thresholding operation on a single plane of data and performs a copy mono operation to the device */ int gxht_thresh_plane(gx_image_enum *penum, gx_ht_order *d_order, fixed xrun, int dest_width, int dest_height, byte *thresh_align, byte *contone_align, int contone_stride, gx_device * dev) { int thresh_width, thresh_height, dx; int left_rem_end, left_width, vdi; int num_full_tiles, right_tile_width; int k, jj, dy; byte *thresh_tile; int position; bool replicate_tile; image_posture posture = penum->posture; const int y_pos = penum->yci; int width; byte *ptr_out, *row_ptr, *ptr_out_temp; byte *threshold = d_order->threshold; int init_tile, in_row_offset, ii, num_tiles, tile_remainder; int offset_bits = penum->ht_offset_bits; byte *halftone = penum->ht_buffer; int dithered_stride = penum->ht_stride; /* Go ahead and fill the threshold line buffer with tiled threshold values. First just grab the row or column that we are going to tile with and then do memcpy into the buffer */ thresh_width = d_order->width; thresh_height = d_order->height; /* Figure out the tile steps. Left offset, Number of tiles, Right offset. */ switch (posture) { case image_portrait: vdi = penum->hci; /* Compute the tiling positions with dest_width */ dx = fixed2int_var(xrun) % thresh_width; /* Left remainder part */ left_rem_end = min(dx + dest_width, thresh_width); left_width = left_rem_end - dx; /* The left width of our tile part */ /* Now the middle part */ num_full_tiles = (int)fastfloor((dest_width - left_width)/ (float) thresh_width); /* Now the right part */ right_tile_width = dest_width - num_full_tiles * thresh_width - left_width; /* Those dimensions stay the same across the set of lines that we fill in our buffer. Iterate over the vdi and fill up our threshold buffer */ for (k = 0; k < vdi; k++) { /* Get a pointer to our tile row */ dy = (penum->yci + k + penum->dev->band_offset_y) % thresh_height; thresh_tile = threshold + d_order->width * dy; /* Fill the buffer, can be multiple rows. Make sure to update with stride */ position = contone_stride * k; /* Tile into the 128 bit aligned threshold strip */ fill_threshhold_buffer(&(thresh_align[position]), thresh_tile, thresh_width, dx, left_width, num_full_tiles, right_tile_width); } /* Apply the threshold operation */ #if RAW_HT_DUMP gx_ht_threshold_row_byte(contone_align, thresh_align, contone_stride, halftone, dithered_stride, dest_width, vdi); sprintf(file_name,"HT_Portrait_%d_%dx%dx%d.raw", penum->id, dest_width, dest_height, spp_out); fid = fopen(file_name,"a+b"); fwrite(halftone,1,dest_width * vdi,fid); fclose(fid); #else if (offset_bits > dest_width) offset_bits = dest_width; gx_ht_threshold_row_bit(contone_align, thresh_align, contone_stride, halftone, dithered_stride, dest_width, vdi, offset_bits); /* FIXME: An improvement here would be to generate the initial * offset_bits at the correct offset within the byte so that they * align with the remainder of the line. This would mean not * always packing them into the first offset_bits (in MSB order) * of our 16 bit word, but rather into the last offset_bits * (in MSB order) (except when the entire run is small!). * * This would enable us to do just one aligned copy_mono call for * the entire scanline. */ /* Now do the copy mono operation */ /* First the left remainder bits */ if (offset_bits > 0) { int x_pos = fixed2int_var(xrun); (*dev_proc(dev, copy_mono)) (dev, halftone, 0, dithered_stride, gx_no_bitmap_id, x_pos, y_pos, offset_bits, vdi, (gx_color_index) 0, (gx_color_index) 1); } if ((dest_width - offset_bits) > 0 ) { /* Now the primary aligned bytes */ byte *curr_ptr = halftone; int curr_width = dest_width - offset_bits; int x_pos = fixed2int_var(xrun) + offset_bits; if (offset_bits > 0) { curr_ptr += 2; /* If the first 2 bytes had the left part then increment */ } (*dev_proc(dev, copy_mono)) (dev, curr_ptr, 0, dithered_stride, gx_no_bitmap_id, x_pos, y_pos, curr_width, vdi, (gx_color_index) 0, (gx_color_index) 1); } #endif break; case image_landscape: /* Go ahead and paint the chunk if we have 16 values or a partial to get us in sync with the 1 bit devices 16 bit positions */ vdi = penum->wci; while (penum->ht_landscape.count > 15 || ((penum->ht_landscape.count >= offset_bits) && penum->ht_landscape.offset_set)) { /* Go ahead and 2D tile in the threshold buffer at this time */ /* Always work the tiling from the upper left corner of our 16 columns */ if (penum->ht_landscape.offset_set) { width = offset_bits; } else { width = 16; } if (penum->y_extent.x < 0) { dx = (penum->ht_landscape.xstart - width + 1) % thresh_width; } else { dx = penum->ht_landscape.xstart % thresh_width; } dy = (penum->dev->band_offset_y + penum->ht_landscape.y_pos) % thresh_height; if (dy < 0) dy += thresh_height; /* Left remainder part */ left_rem_end = min(dx + 16, thresh_width); left_width = left_rem_end - dx; /* Now the middle part */ num_full_tiles = (int)fastfloor((float) (16 - left_width)/ (float) thresh_width); /* Now the right part */ right_tile_width = 16 - num_full_tiles * thresh_width - left_width; /* Now loop over the y stuff */ ptr_out = thresh_align; /* Do this in three parts. We do a top part, followed by larger mem copies followed by a bottom partial. After a slower initial fill we are able to do larger faster expansions */ if (dest_height <= 2 * thresh_height) { init_tile = dest_height; replicate_tile = false; } else { init_tile = thresh_height; replicate_tile = true; } for (jj = 0; jj < init_tile; jj++) { in_row_offset = (jj + dy) % thresh_height; row_ptr = threshold + in_row_offset * thresh_width; ptr_out_temp = ptr_out; /* Left part */ memcpy(ptr_out_temp, row_ptr + dx, left_width); ptr_out_temp += left_width; /* Now the full tiles */ for (ii = 0; ii < num_full_tiles; ii++) { memcpy(ptr_out_temp, row_ptr, thresh_width); ptr_out_temp += thresh_width; } /* Now the remainder */ memcpy(ptr_out_temp, row_ptr, right_tile_width); ptr_out += 16; } if (replicate_tile) { /* Find out how many we need to copy */ num_tiles = (int)fastfloor((float) (dest_height - thresh_height)/ (float) thresh_height); tile_remainder = dest_height - (num_tiles + 1) * thresh_height; for (jj = 0; jj < num_tiles; jj ++) { memcpy(ptr_out, thresh_align, 16 * thresh_height); ptr_out += 16 * thresh_height; } /* Now fill in the remainder */ memcpy(ptr_out, thresh_align, 16 * tile_remainder); } /* Apply the threshold operation */ gx_ht_threshold_landscape(contone_align, thresh_align, penum->ht_landscape, halftone, dest_height); /* Perform the copy mono */ penum->ht_landscape.offset_set = false; if (penum->ht_landscape.index < 0) { (*dev_proc(dev, copy_mono)) (dev, halftone, 0, 2, gx_no_bitmap_id, penum->ht_landscape.xstart - width + 1, penum->ht_landscape.y_pos, width, dest_height, (gx_color_index) 0, (gx_color_index) 1); } else { (*dev_proc(dev, copy_mono)) (dev, halftone, 0, 2, gx_no_bitmap_id, penum->ht_landscape.xstart, penum->ht_landscape.y_pos, width, dest_height, (gx_color_index) 0, (gx_color_index) 1); } /* Clean up and reset our buffer. We may have a line left over that has to be maintained due to line replication in the resolution conversion */ if (width != penum->ht_landscape.count) { reset_landscape_buffer(&(penum->ht_landscape), contone_align, dest_height, width); } else { /* Reset the whole buffer */ penum->ht_landscape.count = 0; if (penum->ht_landscape.index < 0) { /* Going right to left */ penum->ht_landscape.curr_pos = 15; } else { /* Going left to right */ penum->ht_landscape.curr_pos = 0; } penum->ht_landscape.num_contones = 0; memset(&(penum->ht_landscape.widths[0]), 0, sizeof(int)*16); } } break; default: return gs_rethrow(-1, "Invalid orientation for thresholding"); } return 0; }
int xps_parse_canvas(xps_context_t *ctx, char *base_uri, xps_resource_t *dict, xps_item_t *root) { xps_resource_t *new_dict = NULL; xps_item_t *node; char *opacity_mask_uri; int code; char *transform_att; char *clip_att; char *opacity_att; char *opacity_mask_att; xps_item_t *transform_tag = NULL; xps_item_t *clip_tag = NULL; xps_item_t *opacity_mask_tag = NULL; gs_matrix transform; transform_att = xps_att(root, "RenderTransform"); clip_att = xps_att(root, "Clip"); opacity_att = xps_att(root, "Opacity"); opacity_mask_att = xps_att(root, "OpacityMask"); for (node = xps_down(root); node; node = xps_next(node)) { if (!strcmp(xps_tag(node), "Canvas.Resources") && xps_down(node)) { code = xps_parse_resource_dictionary(ctx, &new_dict, base_uri, xps_down(node)); if (code) return gs_rethrow(code, "cannot load Canvas.Resources"); if (new_dict && new_dict != dict) { new_dict->parent = dict; dict = new_dict; } } if (!strcmp(xps_tag(node), "Canvas.RenderTransform")) transform_tag = xps_down(node); if (!strcmp(xps_tag(node), "Canvas.Clip")) clip_tag = xps_down(node); if (!strcmp(xps_tag(node), "Canvas.OpacityMask")) opacity_mask_tag = xps_down(node); } opacity_mask_uri = base_uri; xps_resolve_resource_reference(ctx, dict, &transform_att, &transform_tag, NULL); xps_resolve_resource_reference(ctx, dict, &clip_att, &clip_tag, NULL); xps_resolve_resource_reference(ctx, dict, &opacity_mask_att, &opacity_mask_tag, &opacity_mask_uri); gs_gsave(ctx->pgs); gs_make_identity(&transform); if (transform_att) xps_parse_render_transform(ctx, transform_att, &transform); if (transform_tag) xps_parse_matrix_transform(ctx, transform_tag, &transform); gs_concat(ctx->pgs, &transform); if (clip_att || clip_tag) { if (clip_att) xps_parse_abbreviated_geometry(ctx, clip_att); if (clip_tag) xps_parse_path_geometry(ctx, dict, clip_tag, 0); xps_clip(ctx); } code = xps_begin_opacity(ctx, opacity_mask_uri, dict, opacity_att, opacity_mask_tag, false, false); if (code) { gs_grestore(ctx->pgs); return gs_rethrow(code, "cannot create transparency group"); } for (node = xps_down(root); node; node = xps_next(node)) { code = xps_parse_element(ctx, base_uri, dict, node); if (code) { xps_end_opacity(ctx, opacity_mask_uri, dict, opacity_att, opacity_mask_tag); gs_grestore(ctx->pgs); return gs_rethrow(code, "cannot parse child of Canvas"); } } xps_end_opacity(ctx, opacity_mask_uri, dict, opacity_att, opacity_mask_tag); gs_grestore(ctx->pgs); if (new_dict) xps_free_resource_dictionary(ctx, new_dict); return 0; }