[gs-cvs] rev 7222 - trunk/gs/src

leonardo at ghostscript.com leonardo at ghostscript.com
Thu Nov 23 11:01:21 PST 2006


Author: leonardo
Date: 2006-11-23 11:01:20 -0800 (Thu, 23 Nov 2006)
New Revision: 7222

Modified:
   trunk/gs/src/gsimage.c
   trunk/gs/src/gxcpath.c
   trunk/gs/src/gximage.c
   trunk/gs/src/gxiparam.h
   trunk/gs/src/gxpath.h
   trunk/gs/src/lib.mak
   trunk/gs/src/zimage.c
Log:
Fix : Skip images outside the clipping path.

DETAILS :

Bug 689000 "Ghostscript generates very large PDF file compared to Distiller".


1. New functions gx_cpath_rect_visible, is_image_visible
   check whether the image is entirely clipped out.

2. A new flag gx_image_enum_common_s::skipping stores that fact.

3. If so happens, interpreter checks whether the image
   has string datasources only. Such images may be safely skipped 
   from the interpretation (zimage.c).

Note : This optimization works for ImageType 1 only - see comment 
in is_image_visible. Unfortunately We have no time to improve this now. 
Need to analyze why does gs_image2_t need a floating size of the source image.

EXPECTED DIFFERENCES :

None.


Modified: trunk/gs/src/gsimage.c
===================================================================
--- trunk/gs/src/gsimage.c	2006-11-23 15:01:16 UTC (rev 7221)
+++ trunk/gs/src/gsimage.c	2006-11-23 19:01:20 UTC (rev 7222)
@@ -14,6 +14,7 @@
 /* $Id$ */
 /* Image setup procedures for Ghostscript library */
 #include "memory_.h"
+#include "math_.h"
 #include "gx.h"
 #include "gserrors.h"
 #include "gsstruct.h"
@@ -146,6 +147,43 @@
 }
 RELOC_PTRS_END
 
+private int
+is_image_visible(const gs_image_common_t * pic, gs_state * pgs, gx_clip_path *pcpath)
+{
+    /* HACK : We need the source image size here, 
+       but gs_image_common_t doesn't pass it.
+       We would like to move Width, Height to gs_image_common,
+       but gs_image2_t appears to have those fields of double type.
+     */
+    if (pic->type->begin_typed_image == gx_begin_image1) {
+	gs_image1_t *pim = (gs_image1_t *) pic;
+	gs_rect image_rect = {{0, 0}, {0, 0}};
+	gs_rect device_rect;
+	gs_int_rect device_int_rect;
+	gs_matrix mat;
+	int code;
+
+	image_rect.q.x = pim->Width;
+	image_rect.q.y = pim->Height;
+	code = gs_matrix_invert(&pic->ImageMatrix, &mat);
+	if (code < 0)
+	    return code;
+	code = gs_matrix_multiply(&mat, &ctm_only(pgs), &mat);
+	if (code < 0)
+	    return code;
+	code = gs_bbox_transform(&image_rect, &mat, &device_rect);
+	if (code < 0)
+	    return code;
+	device_int_rect.p.x = (int)floor(device_rect.p.x);
+	device_int_rect.p.y = (int)floor(device_rect.p.y);
+	device_int_rect.q.x = (int)ceil(device_rect.q.x);
+	device_int_rect.q.y = (int)ceil(device_rect.q.y);
+	if (!gx_cpath_rect_visible(pcpath, &device_int_rect))
+	    return 0;
+    }
+    return 1;
+}
+
 /* 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,
@@ -178,8 +216,16 @@
 		return code;
 	}
     }
-    return gx_device_begin_typed_image(dev2, (const gs_imager_state *)pgs,
+    code = gx_device_begin_typed_image(dev2, (const gs_imager_state *)pgs,
 		NULL, pic, NULL, pgs->dev_color, 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;
 }
 
 /* Allocate an image enumerator. */

Modified: trunk/gs/src/gxcpath.c
===================================================================
--- trunk/gs/src/gxcpath.c	2006-11-23 15:01:16 UTC (rev 7221)
+++ trunk/gs/src/gxcpath.c	2006-11-23 19:01:20 UTC (rev 7222)
@@ -984,6 +984,36 @@
     gx_clip_list_init(clp);
 }
 
+/* Check whether a rectangle has a non-empty intersection with a clipping patch. */
+bool 
+gx_cpath_rect_visible(gx_clip_path * pcpath, gs_int_rect *prect)
+{
+    const gx_clip_rect *pr;
+    const gx_clip_list *list = &pcpath->rect_list->list;
+
+    switch (list->count) {
+	case 0:
+	    return false;
+	case 1:
+	    pr = &list->single;
+	    break;
+	default:
+	    pr = list->head;
+    }
+    for (; pr != 0; pr = pr->next) {
+	if (pr->xmin > prect->q.x)
+	    continue;
+	if (pr->xmax < prect->p.x)
+	    continue;
+	if (pr->ymin > prect->q.y)
+	    continue;
+	if (pr->ymax < prect->p.y)
+	    continue;
+	return true;
+    }
+    return false;
+}
+
 /* ------ Debugging printout ------ */
 
 #ifdef DEBUG

Modified: trunk/gs/src/gximage.c
===================================================================
--- trunk/gs/src/gximage.c	2006-11-23 15:01:16 UTC (rev 7221)
+++ trunk/gs/src/gximage.c	2006-11-23 19:01:20 UTC (rev 7222)
@@ -85,6 +85,7 @@
     piec->procs = piep;
     piec->dev = dev;
     piec->id = gs_next_ids(dev->memory, 1);
+    piec->skipping = false;
     switch (format) {
 	case gs_image_format_chunky:
 	    piec->num_planes = 1;

Modified: trunk/gs/src/gxiparam.h
===================================================================
--- trunk/gs/src/gxiparam.h	2006-11-23 15:01:16 UTC (rev 7221)
+++ trunk/gs/src/gxiparam.h	2006-11-23 19:01:20 UTC (rev 7222)
@@ -214,6 +214,7 @@
 	const gx_image_enum_procs_t *procs;\
 	gx_device *dev;\
 	gs_id id;\
+	bool skipping; /* don't render, just consume image streams. */\
 	int num_planes;\
 	int plane_depths[gs_image_max_planes];	/* [num_planes] */\
 	int plane_widths[gs_image_max_planes]	/* [num_planes] */

Modified: trunk/gs/src/gxpath.h
===================================================================
--- trunk/gs/src/gxpath.h	2006-11-23 15:01:16 UTC (rev 7221)
+++ trunk/gs/src/gxpath.h	2006-11-23 19:01:20 UTC (rev 7222)
@@ -341,6 +341,7 @@
     gx_cpath_includes_rectangle(const gx_clip_path *, fixed, fixed,
 				fixed, fixed);
 const gs_fixed_rect *cpath_is_rectangle(const gx_clip_path * pcpath);
+bool gx_cpath_rect_visible(gx_clip_path * pcpath, gs_int_rect *prect);
 
 /* Enumerate a clipping path.  This interface does not copy the path. */
 /* However, it does write into the path's "visited" flags. */

Modified: trunk/gs/src/lib.mak
===================================================================
--- trunk/gs/src/lib.mak	2006-11-23 15:01:16 UTC (rev 7221)
+++ trunk/gs/src/lib.mak	2006-11-23 19:01:20 UTC (rev 7222)
@@ -821,7 +821,7 @@
  $(gsstruct_h) $(gxarith_h) $(gxdevice_h) $(gzht_h) $(gzstate_h) $(gswts_h)
 	$(GLCC) $(GLO_)gshtscr.$(OBJ) $(C_) $(GLSRC)gshtscr.c
 
-$(GLOBJ)gsimage.$(OBJ) : $(GLSRC)gsimage.c $(GXERR) $(memory__h)\
+$(GLOBJ)gsimage.$(OBJ) : $(GLSRC)gsimage.c $(GXERR) $(memory__h) $(math__h)\
  $(gscspace_h) $(gsimage_h) $(gsmatrix_h) $(gsstruct_h) $(gsptype2_h)\
  $(gxarith_h) $(gxdevice_h) $(gxiparam_h) $(gxpath_h) $(gximask_h) $(gzstate_h)
 	$(GLCC) $(GLO_)gsimage.$(OBJ) $(C_) $(GLSRC)gsimage.c

Modified: trunk/gs/src/zimage.c
===================================================================
--- trunk/gs/src/zimage.c	2006-11-23 15:01:16 UTC (rev 7221)
+++ trunk/gs/src/zimage.c	2006-11-23 19:01:20 UTC (rev 7222)
@@ -248,6 +248,7 @@
     gs_image_enum *penum;
     int px;
     const ref *pp;
+    bool string_sources = true;
 
     check_estack(inumpush + 2);	/* stuff above, + continuation + proc */
     make_int(EBOT_NUM_SOURCES(esp), num_sources);
@@ -284,6 +285,7 @@
 			    break;
 			}
 		}
+		string_sources = false;
 		/* falls through */
 	    case t_string:
 		if (r_type(pp) != r_type(sources)) {
@@ -302,6 +304,7 @@
 		    return_error(e_typecheck);
 		}
 		check_proc(*pp);
+		string_sources = false;
 	}
 	*ep = *pp;
     }
@@ -312,7 +315,7 @@
     if ((penum = gs_image_enum_alloc(imemory_local, "image_setup")) == 0)
 	return_error(e_VMerror);
     code = gs_image_enum_init(penum, pie, (const gs_data_image_t *)pim, igs);
-    if (code != 0) {		/* error, or empty image */
+    if (code != 0 || pie->skipping && string_sources) {		/* error, or empty image */
 	int code1 = gs_image_cleanup_and_free_enum(penum, igs);
 
 	if (code >= 0)		/* empty image */



More information about the gs-cvs mailing list