diff options
Diffstat (limited to 'devices/vector/gdevpdfi.c')
-rw-r--r-- | devices/vector/gdevpdfi.c | 512 |
1 files changed, 291 insertions, 221 deletions
diff --git a/devices/vector/gdevpdfi.c b/devices/vector/gdevpdfi.c index c6bdee9d..08e217fa 100644 --- a/devices/vector/gdevpdfi.c +++ b/devices/vector/gdevpdfi.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2020 Artifex Software, Inc. +/* Copyright (C) 2001-2021 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or @@ -958,6 +958,86 @@ static int setup_image_colorspace(gx_device_pdf *pdev, image_union_t *image, con return 0; } +/* Basically, sets up the BBox for Eps2Write case */ +static int +pdf_image_handle_eps(gx_device_pdf *pdev, const gs_gstate * pgs, + const gs_matrix *pmat, const gs_image_common_t *pic, + const gs_int_rect *prect, + const gx_clip_path * pcpath) +{ + int code = 0; + gs_rect sbox, dbox, *Box; + gs_point corners[4]; + gs_fixed_rect ibox; + gs_matrix * pmat1 = (gs_matrix *)pmat; + gs_matrix mat; + + if (!pdev->Eps2Write) + return 0; + + if (!pdev->accumulating_charproc) + Box = &pdev->BBox; + else + Box = &pdev->charproc_BBox; + if (pmat1 == 0) + pmat1 = (gs_matrix *)&ctm_only(pgs); + if ((code = gs_matrix_invert(&pic->ImageMatrix, &mat)) < 0 || + (code = gs_matrix_multiply(&mat, pmat1, &mat)) < 0) + goto exit; + sbox.p.x = prect->p.x; + sbox.p.y = prect->p.y; + sbox.q.x = prect->q.x; + sbox.q.y = prect->q.y; + gs_bbox_transform_only(&sbox, &mat, 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; + + pdev->AccumulatingBBox++; + gx_make_clip_device_on_stack(&cdev, pcpath, (gx_device *)pdev); + set_nonclient_dev_color(&devc, gx_device_black((gx_device *)pdev)); /* any non-white color will do */ + 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); + pdev->AccumulatingBBox--; + } else { + /* Just use the bounding box. */ + float x0, y0, x1, y1; + x0 = fixed2float(ibox.p.x) / (pdev->HWResolution[0] / 72.0); + y0 = fixed2float(ibox.p.y) / (pdev->HWResolution[1] / 72.0); + x1 = fixed2float(ibox.q.x) / (pdev->HWResolution[0] / 72.0); + y1 = fixed2float(ibox.q.y) / (pdev->HWResolution[1] / 72.0); + if (Box->p.x > x0) + Box->p.x = x0; + if (Box->p.y > y0) + Box->p.y = y0; + if (Box->q.x < x1) + Box->q.x = x1; + if (Box->q.y < y1) + Box->q.y = y1; + } + exit: + return code; +} + static int pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, const gs_matrix *pmat, const gs_image_common_t *pic, @@ -967,7 +1047,7 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, gx_image_enum_common_t ** pinfo, pdf_typed_image_context_t context) { - int code, i; + int code = 0, i; unsigned int use_fallback = 0, in_line = 0, is_mask = 0, force_lossless = 0, convert_to_process_colors = 0; int width, height; @@ -976,9 +1056,9 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, const gs_pixel_image_t *pim; gs_int_rect rect; gs_image_format_t format; - gs_color_space *pcs; + gs_color_space *pcs = NULL; int num_components; - pdf_image_enum *pie; + pdf_image_enum *pie = NULL; const pdf_color_space_names_t *names; gs_color_space *pcs_orig = NULL; gs_color_space *pcs_device = NULL; @@ -1006,14 +1086,15 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, until the mask is completed due to equal image merging. */ pdev->image_mask_id = gs_no_id; + pim = (const gs_pixel_image_t *)pic; + /* Check for the image types we can handle. */ switch (pic->type->index) { case 1: is_mask = ((const gs_image_t *)pic)->ImageMask; code = setup_type1_image(pdev, pic, pdcolor, image, context); - if (code < 0) { + if (code < 0) use_fallback = 1; - } else in_line = code; break; @@ -1039,55 +1120,107 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, (prect && !(prect->p.x == 0 && prect->p.y == 0 && prect->q.x == ((const gs_image3_t *)pic)->Width && prect->q.y == ((const gs_image3_t *)pic)->Height))) { - gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), - "pdf_begin_typed_image(image)"); - return (gx_default_begin_typed_image((gx_device *)pdev, pgs, pmat, pic, prect, pdcolor, - pcpath, mem, pinfo)); + use_fallback = 1; + goto exit; } - gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), - "pdf_begin_typed_image(image)"); - return (setup_type3_image(pdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem, pinfo, image)); - break; + code = setup_type3_image(pdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem, pinfo, image); + goto exit; case IMAGE3X_IMAGETYPE: pdev->JPEG_PassThrough = 0; - gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), - "pdf_begin_typed_image(image)"); if (pdev->CompatibilityLevel < 1.4 || (prect && !(prect->p.x == 0 && prect->p.y == 0 && prect->q.x == ((const gs_image3x_t *)pic)->Width && prect->q.y == ((const gs_image3x_t *)pic)->Height))) { - return (gx_default_begin_typed_image((gx_device *)pdev, pgs, pmat, pic, prect, pdcolor, - pcpath, mem, pinfo)); + use_fallback = 1; + goto exit; } pdev->image_mask_is_SMask = true; - return gx_begin_image3x_generic((gx_device *)pdev, pgs, pmat, pic, + code = gx_begin_image3x_generic((gx_device *)pdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem, pdf_image3x_make_mid, pdf_image3x_make_mcde, pinfo); - break; + goto exit; case 4: + /* If we are colour converting then we may not be able to preserve the + * type 4 image, if it has a /Mask entry which is a range of colours + * (chroma-key masking). If its a stencil mask then we can just conver the + * underlying image and leave the mask alone. + */ + if (pdev->params.ColorConversionStrategy != ccs_LeaveColorUnchanged) { + gs_color_space *pcs2; + int csi = 0; + bool fallback = false; + gs_image4_t *pim4 = (gs_image4_t *)pic; + + /* If the /Mask is chroma-key rather than a stencil */ + if (pim4->MaskColor_is_range) { + /* Find the colour space */ + pcs2 = pim->ColorSpace; + csi = gs_color_space_get_index(pcs2); + /* If its /Indexed, get the base space */ + if (csi == gs_color_space_index_Indexed) { + pcs2 = pim->ColorSpace->base_space; + csi = gs_color_space_get_index(pcs2); + } + if (csi == gs_color_space_index_ICC) + csi = gsicc_get_default_type(pcs2->cmm_icc_profile_data); + /* If the base space matches the target for colour conversion + * then no conversion is needed, so we can preserve the type + * 4 image. + */ + switch(csi) { + case gs_color_space_index_DeviceGray: + if (pdev->params.ColorConversionStrategy != ccs_Gray) + fallback = true; + break; + case gs_color_space_index_DeviceRGB: + if (pdev->params.ColorConversionStrategy != ccs_RGB) + fallback = true; + break; + case gs_color_space_index_DeviceCMYK: + if (pdev->params.ColorConversionStrategy != ccs_CMYK) + fallback = true; + break; + default: + fallback = true; + break; + } + if (fallback == true && pdev->CompatibilityLevel > 1.2) { + /* We've arrived at the point where we have a chroma-keyed + * type 4 image, and the image needs to be converted to a + * different space. We can't do that, so fall back to a + * default implementation, create a clip path and apply it to + * the image. + */ + pdev->JPEG_PassThrough = 0; + use_fallback = 0; + code = convert_type4_to_masked_image(pdev, pgs, pic, prect, pdcolor, + pcpath, mem,pinfo); + goto exit; + } + /* Note that we fall through to the original code, so if we are not + * producing at least PDF 1.2 (for image mask support) then we will + * fall back further filled to rectangles. + */ + } + } pdev->JPEG_PassThrough = 0; code = convert_type4_image(pdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem, pinfo, context, image, pnamed); - if (code < 0) { + if (code < 0) use_fallback = 1; - } - if (code == 0) { - gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), - "pdf_begin_typed_image(image)"); - return code; - } + if (code == 0) + goto exit; /* No luck. Masked images require PDF 1.3 or higher. */ - if (pdev->CompatibilityLevel < 1.2) { + if (pdev->CompatibilityLevel < 1.2) use_fallback = 1; - } if (pdev->CompatibilityLevel < 1.3 && !pdev->PatternImagemask) { - gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), - "pdf_begin_typed_image(image)"); - return (convert_type4_to_masked_image(pdev, pgs, pic, prect, pdcolor, - pcpath, mem,pinfo)); + use_fallback = 0; + code = convert_type4_to_masked_image(pdev, pgs, pic, prect, pdcolor, + pcpath, mem,pinfo); + goto exit; } image[0].type4 = *(const gs_image4_t *)pic; break; @@ -1097,7 +1230,6 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, break; } - pim = (const gs_pixel_image_t *)pic; format = pim->format; switch (format) { case gs_image_format_chunky: @@ -1115,14 +1247,12 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, case 2: case 4: case 8: - break; case 12: case 16: break; default: - gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), - "pdf_begin_typed_image(image)"); - return_error(gs_error_rangecheck); + code = gs_note_error(gs_error_rangecheck); + goto exit; } if (prect) rect = *prect; @@ -1135,82 +1265,15 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, (is_mask && pim->CombineWithColor)) use_fallback = 1; - if (pdev->Eps2Write) { - gs_rect sbox, dbox, *Box; - gs_point corners[4]; - gs_fixed_rect ibox; - gs_matrix * pmat1 = (gs_matrix *)pmat; - gs_matrix mat; - - if (!pdev->accumulating_charproc) - Box = &pdev->BBox; - else - Box = &pdev->charproc_BBox; - if (pmat1 == 0) - pmat1 = (gs_matrix *)&ctm_only(pgs); - if ((code = gs_matrix_invert(&pic->ImageMatrix, &mat)) < 0 || - (code = gs_matrix_multiply(&mat, pmat1, &mat)) < 0) - return code; - sbox.p.x = rect.p.x; - sbox.p.y = rect.p.y; - sbox.q.x = rect.q.x; - sbox.q.y = rect.q.y; - gs_bbox_transform_only(&sbox, &mat, 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; - - pdev->AccumulatingBBox++; - gx_make_clip_device_on_stack(&cdev, pcpath, (gx_device *)pdev); - set_nonclient_dev_color(&devc, gx_device_black((gx_device *)pdev)); /* any non-white color will do */ - 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); - pdev->AccumulatingBBox--; - } else { - /* Just use the bounding box. */ - float x0, y0, x1, y1; - x0 = fixed2float(ibox.p.x) / (pdev->HWResolution[0] / 72.0); - y0 = fixed2float(ibox.p.y) / (pdev->HWResolution[1] / 72.0); - x1 = fixed2float(ibox.q.x) / (pdev->HWResolution[0] / 72.0); - y1 = fixed2float(ibox.q.y) / (pdev->HWResolution[1] / 72.0); - if (Box->p.x > x0) - Box->p.x = x0; - if (Box->p.y > y0) - Box->p.y = y0; - if (Box->q.x < x1) - Box->q.x = x1; - if (Box->q.y < y1) - Box->q.y = y1; - } + /* Handle BBox for Eps2Write, if applicable */ + code = pdf_image_handle_eps(pdev, pgs, pmat, pic, &rect, pcpath); + if (code < 0) { + use_fallback = 0; + goto exit; } - if (use_fallback) { - pdev->JPEG_PassThrough = 0; - gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), - "pdf_begin_typed_image(image)"); - return gx_default_begin_typed_image - ((gx_device *)pdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem, - pinfo); - } + if (use_fallback) + goto exit; pcs = pim->ColorSpace; rc_increment_cs(pcs); @@ -1218,19 +1281,13 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, code = pdf_check_soft_mask(pdev, (gs_gstate *)pgs); if (code < 0) - return code; + goto exit; if (pdf_must_put_clip_path(pdev, pcpath)) code = pdf_unclip(pdev); else code = pdf_open_page(pdev, PDF_IN_STREAM); - if (code < 0) { - pdev->JPEG_PassThrough = 0; - gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), - "pdf_begin_typed_image(image)"); - return gx_default_begin_typed_image - ((gx_device *)pdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem, - pinfo); - } + if (code < 0) + goto fail_and_fallback; if (context == PDF_IMAGE_TYPE3_MASK) { /* @@ -1247,21 +1304,14 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, code = pdf_prepare_imagemask(pdev, pgs, pdcolor); else code = pdf_prepare_image(pdev, pgs); - if (code < 0) { - pdev->JPEG_PassThrough = 0; - gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), - "pdf_begin_typed_image(image)"); - return gx_default_begin_typed_image - ((gx_device *)pdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem, - pinfo); - } + if (code < 0) + goto fail_and_fallback; pie = gs_alloc_struct(mem, pdf_image_enum, &st_pdf_image_enum, "pdf_begin_image"); if (pie == 0) { - gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), - "pdf_begin_typed_image(image)"); - return_error(gs_error_VMerror); + code = gs_note_error(gs_error_VMerror); + goto exit; } memset(pie, 0, sizeof(*pie)); /* cleanup entirely for GC to work in all cases. */ *pinfo = (gx_image_enum_common_t *) pie; @@ -1305,24 +1355,18 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, if ((code = gs_matrix_invert(&pim->ImageMatrix, &mat)) < 0 || (code = gs_matrix_multiply(&bmat, &mat, &mat)) < 0 || (code = gs_matrix_multiply(&mat, pmat, &pie->mat)) < 0 - ) { - gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), - "pdf_begin_typed_image(image)"); - gs_free_object(mem, pie, "pdf_begin_image"); - return code; - } + ) + goto exit; /* AR3,AR4 show no image when CTM is singular; AR5 reports an error */ - if (pie->mat.xx * pie->mat.yy == pie->mat.xy * pie->mat.yx) + if (pie->mat.xx * pie->mat.yy == pie->mat.xy * pie->mat.yx) { + use_fallback = 1; goto fail_and_fallback; + } } code = pdf_put_clip_path(pdev, pcpath); - if (code < 0) { - gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), - "pdf_begin_typed_image(image)"); - gs_free_object(mem, pie, "pdf_begin_image"); - return code; - } + if (code < 0) + goto exit; pdf_image_writer_init(&pie->writer); /* Note : Possible values for alt_writer_count are 1,2,3,4. 1 means no alternative streams. @@ -1352,8 +1396,10 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, if (image[0].pixel.ColorSpace != NULL && !(context == PDF_IMAGE_TYPE3_MASK)) convert_to_process_colors = setup_image_colorspace(pdev, &image[0], pcs, &pcs_orig, names, &cs_value); - if (pim->BitsPerComponent > 8 && convert_to_process_colors) + if (pim->BitsPerComponent > 8 && convert_to_process_colors) { + use_fallback = 1; goto fail_and_fallback; + } if (convert_to_process_colors == 4) { code = convert_DeviceN_alternate(pdev, pgs, pcs, NULL, NULL, NULL, NULL, &cs_value, in_line); if (code < 0) @@ -1368,6 +1414,7 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, code = make_device_color_space(pdev, pdev->pcm_color_info_index, &pcs_device); if (code < 0) goto fail_and_fallback; + rc_decrement(image[0].pixel.ColorSpace, "pdf_begin_typed_image(pixel.ColorSpace)"); image[0].pixel.ColorSpace = pcs_device; image[0].pixel.BitsPerComponent = 8; code = pdf_color_space_named(pdev, pgs, &cs_value, &pranges, pcs_device, names, @@ -1400,53 +1447,6 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, if (code < 0) goto fail_and_fallback; - if (pdev->params.TransferFunctionInfo == tfi_Apply && pdev->transfer_not_identity && !is_mask) - pdev->JPEG_PassThrough = 0; - - /* Code below here deals with setting up the multiple data stream writing. - * We can have up to 4 stream writers, which we keep in an array. We must - * always have at least one which writes the uncompressed stream. If we - * are writing compressed streams, we have one for the compressed stream - * and one for the compression chooser. - * For type 4 images being converted (for old versions of PDF or for ps2write) - * we need an additional stream to write a mask, which masks the real - * image. - * For colour conversion we will place an additional filter in front of all - * the streams which does the conversion. - */ - if (in_line) { - pdev->JPEG_PassThrough = 0; - code = new_setup_lossless_filters((gx_device_psdf *) pdev, - &pie->writer.binary[0], - &image[0].pixel, in_line, convert_to_process_colors, (gs_matrix *)pmat, (gs_gstate *)pgs); - } else { - if (force_lossless) { - /* - * Some regrettable PostScript code (such as LanguageLevel 1 output - * from Microsoft's PSCRIPT.DLL driver) misuses the transfer - * function to accomplish the equivalent of indexed color. - * Downsampling (well, only averaging) or JPEG compression are not - * compatible with this. Play it safe by using only lossless - * filters if the transfer function(s) is/are other than the - * identity and by setting the downsample type to Subsample.. - */ - int saved_downsample = pdev->params.ColorImage.DownsampleType; - - pdev->params.ColorImage.DownsampleType = ds_Subsample; - code = new_setup_image_filters((gx_device_psdf *) pdev, - &pie->writer.binary[0], &image[0].pixel, - pmat, pgs, true, in_line, convert_to_process_colors); - pdev->params.ColorImage.DownsampleType = saved_downsample; - } else { - code = new_setup_image_filters((gx_device_psdf *) pdev, - &pie->writer.binary[0], &image[0].pixel, - pmat, pgs, true, in_line, convert_to_process_colors); - } - } - - if (code < 0) - goto fail_and_fallback; - if (!convert_to_process_colors) { gs_color_space_index csi; @@ -1501,10 +1501,53 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, } } } - /* If we are not preserving the colour space unchanged, thenwe can't pass through JPEG */ + /* If we are not preserving the colour space unchanged, then we can't pass through JPEG */ else pdev->JPEG_PassThrough = 0; + /* Code below here deals with setting up the multiple data stream writing. + * We can have up to 4 stream writers, which we keep in an array. We must + * always have at least one which writes the uncompressed stream. If we + * are writing compressed streams, we have one for the compressed stream + * and one for the compression chooser. + * For type 4 images being converted (for old versions of PDF or for ps2write) + * we need an additional stream to write a mask, which masks the real + * image. + * For colour conversion we will place an additional filter in front of all + * the streams which does the conversion. + */ + if (in_line) { + pdev->JPEG_PassThrough = 0; + code = new_setup_lossless_filters((gx_device_psdf *) pdev, + &pie->writer.binary[0], + &image[0].pixel, in_line, convert_to_process_colors, (gs_matrix *)pmat, (gs_gstate *)pgs); + } else { + if (force_lossless) { + /* + * Some regrettable PostScript code (such as LanguageLevel 1 output + * from Microsoft's PSCRIPT.DLL driver) misuses the transfer + * function to accomplish the equivalent of indexed color. + * Downsampling (well, only averaging) or JPEG compression are not + * compatible with this. Play it safe by using only lossless + * filters if the transfer function(s) is/are other than the + * identity and by setting the downsample type to Subsample.. + */ + int saved_downsample = pdev->params.ColorImage.DownsampleType; + + pdev->params.ColorImage.DownsampleType = ds_Subsample; + code = new_setup_image_filters((gx_device_psdf *) pdev, + &pie->writer.binary[0], &image[0].pixel, + pmat, pgs, true, in_line, convert_to_process_colors); + pdev->params.ColorImage.DownsampleType = saved_downsample; + } else { + code = new_setup_image_filters((gx_device_psdf *) pdev, + &pie->writer.binary[0], &image[0].pixel, + pmat, pgs, true, in_line, convert_to_process_colors); + } + } + + if (code < 0) + goto fail_and_fallback; if (convert_to_process_colors) { image[0].pixel.ColorSpace = pcs_orig; @@ -1529,9 +1572,8 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, if (pie->writer.alt_writer_count > 1) { code = pdf_make_alt_stream(pdev, &pie->writer.binary[1]); - if (code) { + if (code < 0) goto fail_and_fallback; - } code = new_setup_image_filters((gx_device_psdf *) pdev, &pie->writer.binary[1], &image[1].pixel, pmat, pgs, force_lossless, in_line, convert_to_process_colors); @@ -1542,8 +1584,11 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, cos_stream_t *pcos = cos_stream_from_pipeline(pie->writer.binary[i].strm); s_close_filters(&s, NULL); gs_free_object(pdev->pdf_memory, s, "compressed image stream"); - if (pcos == 0L) - return gs_note_error(gs_error_ioerror); + if (pcos == 0L) { + /* TODO: Seems like something should be freed here */ + code = gs_note_error(gs_error_ioerror); + goto exit; + } pcos->cos_procs->release((cos_object_t *)pcos, "pdf_begin_typed_image_impl"); gs_free_object(pdev->pdf_memory, pcos, "compressed image cos_stream"); } @@ -1558,9 +1603,8 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, image[1].pixel.BitsPerComponent = pim->BitsPerComponent; code = psdf_setup_image_colors_filter(&pie->writer.binary[1], (gx_device_psdf *)pdev, pim, &image[1].pixel, pgs); - if (code < 0) { + if (code < 0) goto fail_and_fallback; - } image[1].pixel.ColorSpace = pcs_device; } } @@ -1588,7 +1632,7 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, /* Won't use image[2]. */ code = pdf_begin_write_image(pdev, &pie->writer, gs_no_id, width, height, NULL, false); - if (code) + if (code < 0) goto fail_and_fallback; code = psdf_setup_image_filters((gx_device_psdf *) pdev, &pie->writer.binary[i], &image[i].pixel, @@ -1609,20 +1653,38 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, ++pie->writer.alt_writer_count; } - gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), - "pdf_begin_typed_image(image)"); - rc_decrement(pcs, "pdf_begin_typed_image(pcs)"); - return 0; + /* use_fallback = 0, so this will drop through the below labels, doing only the cleanup parts */ + code = 0; + + /* This label is used when code < 0 and we want to do the fallback code */ + fail_and_fallback: + if (code != 0) + use_fallback = 1; -fail_and_fallback: + /* This label is used either when there's no error and we are just exiting normally + * (possibly with use_fallback=1), or there is an error but we don't want to do + * the fallback code. + */ + exit: + /* Free everything */ rc_decrement(pcs, "pdf_begin_typed_image(pcs)"); - pdev->JPEG_PassThrough = 0; + rc_decrement(pcs_device, "pdf_begin_typed_image(pcs_device)"); gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), "pdf_begin_typed_image(image)"); - gs_free_object(mem, pie, "pdf_begin_image"); - return gx_default_begin_typed_image - ((gx_device *)pdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem, - pinfo); + + /* Free pie only if there was an error or we are falling back */ + if (code < 0 || use_fallback) { + if (pie) + gs_free_object(mem, pie, "pdf_begin_typed_image(pie)"); + *pinfo = NULL; + } + /* Do the fallback */ + if (use_fallback) { + pdev->JPEG_PassThrough = 0; + code = gx_default_begin_typed_image + ((gx_device *)pdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem, pinfo); + } + return code; } int @@ -1730,7 +1792,7 @@ pdf_image_plane_data(gx_image_enum_common_t * info, if (pie->JPEG_PassThrough) { pie->rows_left -= height; *rows_used = height; - return 0; + return !pie->rows_left; } for (i = 0; i < pie->writer.alt_writer_count; i++) { @@ -1922,6 +1984,10 @@ pdf_image_end_image_data(gx_image_enum_common_t * info, bool draw_last, } else code = pdf_end_and_do_image(pdev, &pie->writer, &pie->mat, info->id, do_image); pie->writer.alt_writer_count--; /* For GC. */ + } else { + code = pdf_end_image_binary(pdev, &pie->writer, data_height); + code = pdf_end_abort_image(pdev, &pie->writer); + pie->writer.alt_writer_count--; /* For GC. */ } if (pie->initial_colorspace != pdev->pcm_color_info_index) pdf_set_process_color_model(pdev, pie->initial_colorspace); @@ -2286,7 +2352,7 @@ gdev_pdf_dev_spec_op(gx_device *pdev1, int dev_spec_op, void *data, int size) if (code < 0) return code; pcd = cos_stream_dict((cos_stream_t *)pres->object); - pcd_Resources = cos_dict_alloc(pdev, "pdf_pattern(Resources)"); + pcd_Resources = cos_dict_alloc(pdev, "pdf_form(Resources)"); if (pcd == NULL || pcd_Resources == NULL) return_error(gs_error_VMerror); code = cos_dict_put_c_strings(pcd, "/Type", "/XObject"); @@ -2467,6 +2533,13 @@ gdev_pdf_dev_spec_op(gx_device *pdev1, int dev_spec_op, void *data, int size) pres->where_used |= pdev->used_mask; } else if (pres->object->id < 0) pdf_reserve_object_id(pdev, pres, 0); + pdev->LastFormID = pdf_resource_id(pres); + pdev->HighLevelForm--; + if (pdev->accumulating_substream_resource) { + code = pdf_add_resource(pdev, pdev->substream_Resources, "/XObject", pres); + if (code < 0) + return code; + } if (pdev->PDFFormName) { cos_value_t value; @@ -2476,19 +2549,14 @@ gdev_pdf_dev_spec_op(gx_device *pdev1, int dev_spec_op, void *data, int size) if (code < 0) return code; pdf_drop_resource_from_chain(pdev, pres, resourceXObject); + pres->object = NULL; + gs_free_object(pdev->pdf_memory, pres, "free redundant resource"); - gs_free_object(pdev->memory->non_gc_memory, pdev->PDFFormName, "free Name oof Form for pdfmark"); + gs_free_object(pdev->memory->non_gc_memory, pdev->PDFFormName, "free Name of Form for pdfmark"); pdev->PDFFormName = 0x00; } else { pprintld1(pdev->strm, "/R%ld Do Q\n", pdf_resource_id(pres)); } - pdev->HighLevelForm--; - if (pdev->accumulating_substream_resource) { - code = pdf_add_resource(pdev, pdev->substream_Resources, "/XObject", pres); - if (code < 0) - return code; - } - pdev->LastFormID = pdf_resource_id(pres); } return 0; case gxdso_get_form_ID: @@ -2690,6 +2758,8 @@ gdev_pdf_dev_spec_op(gx_device *pdev1, int dev_spec_op, void *data, int size) return 0; } break; + case gxdso_in_smask_construction: + return pdev->smask_construction; case gxdso_get_dev_param: { int code; |