static int bbox_image_plane_data(gx_image_enum_common_t * info, const gx_image_plane_t * planes, int height, int *rows_used) { gx_device *dev = info->dev; gx_device_bbox *const bdev = (gx_device_bbox *)dev; gx_device *tdev = bdev->target; bbox_image_enum *pbe = (bbox_image_enum *) info; const gx_clip_path *pcpath = pbe->pcpath; gs_rect sbox, dbox; gs_point corners[4]; gs_fixed_rect ibox; int code; code = gx_image_plane_data_rows(pbe->target_info, planes, height, rows_used); if (code != 1 && !pbe->params_are_const) bbox_image_copy_target_info(pbe); sbox.p.x = pbe->x0; sbox.p.y = pbe->y; sbox.q.x = pbe->x1; sbox.q.y = pbe->y = min(pbe->y + height, pbe->height); gs_bbox_transform_only(&sbox, &pbe->matrix, corners); gs_points_bbox(corners, &dbox); ibox.p.x = float2fixed(dbox.p.x); ibox.p.y = float2fixed(dbox.p.y); ibox.q.x = float2fixed(dbox.q.x); ibox.q.y = float2fixed(dbox.q.y); if (pcpath != NULL && !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y) ) { /* Let the target do the drawing, but drive two triangles */ /* through the clipping path to get an accurate bounding box. */ gx_device_clip cdev; gx_drawing_color devc; fixed x0 = float2fixed(corners[0].x), y0 = float2fixed(corners[0].y); fixed bx2 = float2fixed(corners[2].x) - x0, by2 = float2fixed(corners[2].y) - y0; gx_make_clip_device_on_stack(&cdev, pcpath, dev); set_nonclient_dev_color(&devc, bdev->black); /* any non-white color will do */ bdev->target = NULL; gx_default_fill_triangle((gx_device *) & cdev, x0, y0, float2fixed(corners[1].x) - x0, float2fixed(corners[1].y) - y0, bx2, by2, &devc, lop_default); gx_default_fill_triangle((gx_device *) & cdev, x0, y0, float2fixed(corners[3].x) - x0, float2fixed(corners[3].y) - y0, bx2, by2, &devc, lop_default); bdev->target = tdev; } else { /* Just use the bounding box. */ BBOX_ADD_RECT(bdev, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y); } return code; }
/* Create an image enumerator given image parameters and a graphics state. */ int gs_image_begin_typed(const gs_image_common_t * pic, gs_state * pgs, bool uses_color, gx_image_enum_common_t ** ppie) { gx_device *dev = gs_currentdevice(pgs); gx_clip_path *pcpath; int code = gx_effective_clip_path(pgs, &pcpath); gx_device *dev2 = dev; gx_device_color dc_temp, *pdevc = pgs->dev_color; if (code < 0) return code; /* Processing an image object operation */ gs_set_object_tag(pgs, GS_IMAGE_TAG); if (uses_color) { gx_set_dev_color(pgs); code = gs_state_color_load(pgs); if (code < 0) return code; } /* Imagemask with shading color needs a special optimization with converting the image into a clipping. Check for such case after gs_state_color_load is done, because it can cause interpreter callout. */ if (pic->type->begin_typed_image == &gx_begin_image1) { gs_image_t *image = (gs_image_t *)pic; if(image->ImageMask) { code = gx_image_fill_masked_start(dev, pgs->dev_color, pcpath, pgs->memory, &dev2); if (code < 0) return code; } if (dev2 != dev) { set_nonclient_dev_color(&dc_temp, 1); pdevc = &dc_temp; } } code = gx_device_begin_typed_image(dev2, (const gs_imager_state *)pgs, NULL, pic, NULL, pdevc, pcpath, pgs->memory, ppie); if (code < 0) return code; code = is_image_visible(pic, pgs, pcpath); if (code < 0) return code; if (!code) (*ppie)->skipping = true; return 0; }
static int gx_dc_no_fill_rectangle(const gx_device_color *pdevc, int x, int y, int w, int h, gx_device *dev, gs_logical_operation_t lop, const gx_rop_source_t *source) { gx_device_color filler; if (w <= 0 || h <= 0) return 0; if (lop_uses_T(lop)) return_error(gs_error_Fatal); set_nonclient_dev_color(&filler, 0); /* any valid value for dev will do */ return gx_dc_pure_fill_rectangle(&filler, x, y, w, h, dev, lop, source); }
irender_proc_t gs_image_class_1_simple(gx_image_enum * penum) { irender_proc_t rproc; fixed ox = dda_current(penum->dda.pixel0.x); fixed oy = dda_current(penum->dda.pixel0.y); if (penum->use_rop || penum->spp != 1 || penum->bps != 1) return 0; switch (penum->posture) { case image_portrait: { /* Use fast portrait algorithm. */ long dev_width = fixed2long_pixround(ox + penum->x_extent.x) - fixed2long_pixround(ox); if (dev_width != penum->rect.w) { /* * Add an extra align_bitmap_mod of padding so that * we can align scaled rows with the device. */ long line_size = bitmap_raster(any_abs(dev_width)) + align_bitmap_mod; if (penum->adjust != 0 || line_size > max_uint) return 0; /* Must buffer a scan line. */ penum->line_width = any_abs(dev_width); penum->line_size = (uint) line_size; penum->line = gs_alloc_bytes(penum->memory, penum->line_size, "image line"); if (penum->line == 0) { gx_default_end_image(penum->dev, (gx_image_enum_common_t *)penum, false); return 0; } } if_debug2('b', "[b]render=simple, unpack=copy; rect.w=%d, dev_width=%ld\n", penum->rect.w, dev_width); rproc = image_render_simple; break; } case image_landscape: { /* Use fast landscape algorithm. */ long dev_width = fixed2long_pixround(oy + penum->x_extent.y) - fixed2long_pixround(oy); long line_size = (dev_width = any_abs(dev_width), bitmap_raster(dev_width) * 8 + ROUND_UP(dev_width, 8) * align_bitmap_mod); if ((dev_width != penum->rect.w && penum->adjust != 0) || line_size > max_uint ) return 0; /* Must buffer a group of 8N scan lines. */ penum->line_width = dev_width; penum->line_size = (uint) line_size; penum->line = gs_alloc_bytes(penum->memory, penum->line_size, "image line"); if (penum->line == 0) { gx_default_end_image(penum->dev, (gx_image_enum_common_t *) penum, false); return 0; } penum->xi_next = penum->line_xy = fixed2int_var_rounded(ox); if_debug3('b', "[b]render=landscape, unpack=copy; rect.w=%d, dev_width=%ld, line_size=%ld\n", penum->rect.w, dev_width, line_size); rproc = image_render_landscape; /* Precompute values needed for rasterizing. */ penum->dxy = float2fixed(penum->matrix.xy + fixed2float(fixed_epsilon) / 2); break; } default: return 0; } /* Precompute values needed for rasterizing. */ penum->dxx = float2fixed(penum->matrix.xx + fixed2float(fixed_epsilon) / 2); /* * We don't want to spread the samples, but we have to reset unpack_bps * to prevent the buffer pointer from being incremented by 8 bytes per * input byte. */ penum->unpack = sample_unpack_copy; penum->unpack_bps = 8; if (penum->use_mask_color) { /* * Set the masked color as 'no_color' to make it transparent * according to the mask color range and the decoding. */ penum->masked = true; if (penum->mask_color.values[0] == 1) { /* if v0 == 1, 1 is transparent since v1 must be == 1 to be a valid range */ set_nonclient_dev_color(penum->map[0].inverted ? penum->icolor0 : penum->icolor1, gx_no_color_index); } else if (penum->mask_color.values[1] == 0) { /* if v1 == 0, 0 is transparent since v0 must be == 0 to be a valid range */ set_nonclient_dev_color(penum->map[0].inverted ? penum->icolor1 : penum->icolor0, gx_no_color_index); } else { /* * The only other possible in-range value is v0 = 0, v1 = 1. * The image is completely transparent! */ rproc = image_render_skip; } penum->map[0].decoding = sd_none; } return rproc; }
static int test5(gs_state * pgs, gs_memory_t * mem) { gx_device *dev = gs_currentdevice(pgs); gx_image_enum_common_t *info; gx_image_plane_t planes[5]; gx_drawing_color dcolor; int code; static const byte data3[] = { 0x00, 0x44, 0x88, 0xcc, 0x44, 0x88, 0xcc, 0x00, 0x88, 0xcc, 0x00, 0x44, 0xcc, 0x00, 0x44, 0x88 }; gs_color_space *gray_cs = gs_cspace_new_DeviceGray(mem); /* * Neither ImageType 3 nor 4 needs a current color, * but some intermediate code assumes it's valid. */ set_nonclient_dev_color(&dcolor, 0); /* Scale everything up, and fill the background. */ { gs_matrix mat; gs_currentmatrix(pgs, &mat); mat.xx = gs_copysign(98.6, mat.xx); mat.yy = gs_copysign(98.6, mat.yy); mat.tx = floor(mat.tx) + 0.499; mat.ty = floor(mat.ty) + 0.499; gs_setmatrix(pgs, &mat); } gs_setrgbcolor(pgs, 1.0, 0.9, 0.9); fill_rect1(pgs, 0.25, 0.25, 4.0, 6.0); gs_setrgbcolor(pgs, 0.5, 1.0, 0.5); #if 0 /* Make things a little more interesting.... */ gs_translate(pgs, 1.0, 1.0); gs_rotate(pgs, 10.0); gs_scale(pgs, 1.3, 0.9); #endif #define do_image(image, idata)\ BEGIN\ code = gx_device_begin_typed_image(dev, (gs_imager_state *)pgs, NULL,\ (gs_image_common_t *)&image, NULL, &dcolor, NULL, mem, &info);\ /****** TEST code >= 0 ******/\ planes[0].data = idata;\ planes[0].data_x = 0;\ planes[0].raster = (image.Height * image.BitsPerComponent + 7) >> 3;\ code = gx_image_plane_data(info, planes, image.Height);\ /****** TEST code == 1 ******/\ code = gx_image_end(info, true);\ /****** TEST code >= 0 ******/\ END #define W 4 #define H 4 /* Test an unmasked image. */ gs_gsave(pgs); { gs_image1_t image1; void *info1; gs_color_space *cs; cs = gs_cspace_new_DeviceGray(mem); gs_image_t_init(&image1, cs); /* image */ image1.ImageMatrix.xx = W; image1.ImageMatrix.yy = -H; image1.ImageMatrix.ty = H; /* data_image */ image1.Width = W; image1.Height = H; image1.BitsPerComponent = 8; gs_translate(pgs, 0.5, 4.0); code = gx_device_begin_image(dev, (gs_imager_state *) pgs, &image1, gs_image_format_chunky, NULL, &dcolor, NULL, mem, &info1); /****** TEST code >= 0 ******/ planes[0].data = data3; planes[0].data_x = 0; planes[0].raster = (image1.Height * image1.BitsPerComponent + 7) >> 3; /* Use the old image_data API. */ code = gx_image_data(info1, &planes[0].data, 0, planes[0].raster, image1.Height); /****** TEST code == 1 ******/ code = gx_image_end(info1, true); /****** TEST code >= 0 ******/ gs_free_object(mem, cs, "colorspace"); } gs_grestore(pgs); /* Test an explicitly masked image. */ gs_gsave(pgs); { gs_image3_t image3; static const byte data3mask[] = { 0x60, 0x90, 0x90, 0x60 }; static const byte data3x2mask[] = { 0x66, 0x99, 0x99, 0x66, 0x66, 0x99, 0x99, 0x66 }; gs_image3_t_init(&image3, gray_cs, interleave_scan_lines); /* image */ image3.ImageMatrix.xx = W; image3.ImageMatrix.yy = -H; image3.ImageMatrix.ty = H; /* data_image */ image3.Width = W; image3.Height = H; image3.BitsPerComponent = 8; /* MaskDict */ image3.MaskDict.ImageMatrix = image3.ImageMatrix; image3.MaskDict.Width = image3.Width; image3.MaskDict.Height = image3.Height; /* Display with 1-for-1 mask and image. */ gs_translate(pgs, 0.5, 2.0); code = gx_device_begin_typed_image(dev, (gs_imager_state *) pgs, NULL, (gs_image_common_t *) & image3, NULL, &dcolor, NULL, mem, &info); /****** TEST code >= 0 ******/ planes[0].data = data3mask; planes[0].data_x = 0; planes[0].raster = (image3.MaskDict.Height + 7) >> 3; planes[1].data = data3; planes[1].data_x = 0; planes[1].raster = (image3.Height * image3.BitsPerComponent + 7) >> 3; code = gx_image_plane_data(info, planes, image3.Height); /****** TEST code == 1 ******/ code = gx_image_end(info, true); /****** TEST code >= 0 ******/ /* Display with 2-for-1 mask and image. */ image3.MaskDict.ImageMatrix.xx *= 2; image3.MaskDict.ImageMatrix.yy *= 2; image3.MaskDict.ImageMatrix.ty *= 2; image3.MaskDict.Width *= 2; image3.MaskDict.Height *= 2; gs_translate(pgs, 1.5, 0.0); code = gx_device_begin_typed_image(dev, (gs_imager_state *) pgs, NULL, (gs_image_common_t *) & image3, NULL, &dcolor, NULL, mem, &info); /****** TEST code >= 0 ******/ planes[0].data = data3x2mask; planes[0].raster = (image3.MaskDict.Width + 7) >> 3; { int i; for (i = 0; i < H; ++i) { planes[1].data = 0; code = gx_image_plane_data(info, planes, 1); planes[0].data += planes[0].raster; /****** TEST code == 0 ******/ planes[1].data = data3 + i * planes[1].raster; code = gx_image_plane_data(info, planes, 1); planes[0].data += planes[0].raster; /****** TEST code >= 0 ******/ } } /****** TEST code == 1 ******/ code = gx_image_end(info, true); /****** TEST code >= 0 ******/ } gs_grestore(pgs); /* Test a chroma-keyed masked image. */ gs_gsave(pgs); { gs_image4_t image4; const byte *data4 = data3; gs_image4_t_init(&image4, gray_cs); /* image */ image4.ImageMatrix.xx = W; image4.ImageMatrix.yy = -H; image4.ImageMatrix.ty = H; /* data_image */ image4.Width = W; image4.Height = H; image4.BitsPerComponent = 8; /* Display with a single mask color. */ gs_translate(pgs, 0.5, 0.5); image4.MaskColor_is_range = false; image4.MaskColor[0] = 0xcc; do_image(image4, data4); /* Display a second time with a color range. */ gs_translate(pgs, 1.5, 0.0); image4.MaskColor_is_range = true; image4.MaskColor[0] = 0x40; image4.MaskColor[1] = 0x90; do_image(image4, data4); } gs_grestore(pgs); gs_free_object(mem, gray_cs, "test5 gray_cs"); #undef W #undef H #undef do_image return 0; }
static int bbox_stroke_path(gx_device * dev, const gs_imager_state * pis, gx_path * ppath, const gx_stroke_params * params, const gx_drawing_color * pdevc, const gx_clip_path * pcpath) { gx_device_bbox *const bdev = (gx_device_bbox *) dev; gx_device *tdev = bdev->target; /* Skip the call if there is no target. */ int code = (tdev == 0 ? 0 : dev_proc(tdev, stroke_path)(tdev, pis, ppath, params, pdevc, pcpath)); if (!GX_DC_IS_TRANSPARENT(pdevc, bdev)) { gs_fixed_rect ibox; gs_fixed_point expand; if (gx_stroke_path_expansion(pis, ppath, &expand) == 0 && gx_path_bbox(ppath, &ibox) >= 0 ) { /* The fast result is exact. */ adjust_box(&ibox, expand); } else { /* * The result is not exact. Compute an exact result using * strokepath. */ gx_path *spath = gx_path_alloc(pis->memory, "bbox_stroke_path"); int code = 0; if (spath) code = gx_imager_stroke_add(ppath, spath, dev, pis); else code = -1; if (code >= 0) code = gx_path_bbox(spath, &ibox); if (code < 0) { ibox.p.x = ibox.p.y = min_fixed; ibox.q.x = ibox.q.y = max_fixed; } if (spath) gx_path_free(spath, "bbox_stroke_path"); } if (pcpath != NULL && !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y) ) { /* Let the target do the drawing, but break down the */ /* fill path into pieces for computing the bounding box. */ gx_drawing_color devc; set_nonclient_dev_color(&devc, bdev->black); /* any non-white color will do */ bdev->target = NULL; gx_default_stroke_path(dev, pis, ppath, params, &devc, pcpath); bdev->target = tdev; } else { /* Just use the path bounding box. */ BBOX_ADD_RECT(bdev, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y); } } return code; }
static int bbox_fill_path(gx_device * dev, const gs_imager_state * pis, gx_path * ppath, const gx_fill_params * params, const gx_device_color * pdevc, const gx_clip_path * pcpath) { gx_device_bbox *const bdev = (gx_device_bbox *) dev; gx_device *tdev = bdev->target; dev_proc_fill_path((*fill_path)) = (tdev == 0 ? dev_proc(&gs_null_device, fill_path) : dev_proc(tdev, fill_path)); int code; if (ppath == NULL) { /* A special handling of shfill with no path. */ gs_fixed_rect ibox; gs_fixed_point adjust; if (pcpath == NULL) return 0; gx_cpath_inner_box(pcpath, &ibox); adjust = params->adjust; adjust_box(&ibox, adjust); BBOX_ADD_RECT(bdev, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y); return 0; } else if (!GX_DC_IS_TRANSPARENT(pdevc, bdev) && !gx_path_is_void(ppath)) { gs_fixed_rect ibox; gs_fixed_point adjust; if (gx_path_bbox(ppath, &ibox) < 0) return 0; adjust = params->adjust; adjust_box(&ibox, adjust); /* * If the path lies within the already accumulated box, just draw * on the target. */ if (BBOX_IN_RECT(bdev, &ibox)) return fill_path(tdev, pis, ppath, params, pdevc, pcpath); /* * If the target uses the default algorithm, just draw on the * bbox device. */ if (tdev != 0 && fill_path == gx_default_fill_path) return fill_path(dev, pis, ppath, params, pdevc, pcpath); /* Draw on the target now. */ code = fill_path(tdev, pis, ppath, params, pdevc, pcpath); if (code < 0) return code; if (pcpath != NULL && !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y) ) { /* * Let the target do the drawing, but break down the * fill path into pieces for computing the bounding box. */ gx_drawing_color devc; set_nonclient_dev_color(&devc, bdev->black); /* any non-white color will do */ bdev->target = NULL; code = gx_default_fill_path(dev, pis, ppath, params, &devc, pcpath); bdev->target = tdev; } else { /* Just use the path bounding box. */ BBOX_ADD_RECT(bdev, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y); } return code; } else return fill_path(tdev, pis, ppath, params, pdevc, pcpath); }