diff options
-rw-r--r-- | gs/src/gsimage.c | 161 | ||||
-rw-r--r-- | gs/src/gsimage.h | 29 | ||||
-rw-r--r-- | gs/src/zimage.c | 74 |
3 files changed, 161 insertions, 103 deletions
diff --git a/gs/src/gsimage.c b/gs/src/gsimage.c index 1430bec54..0be1d4e92 100644 --- a/gs/src/gsimage.c +++ b/gs/src/gsimage.c @@ -23,7 +23,7 @@ typedef struct image_enum_plane_s { /* Change dynamically */ uint pos; /* byte position within the scan line */ - gs_const_string source; /* source data, [0 .. plane_index - 1] */ + gs_const_string source; /* source data, [0 .. num_planes - 1] */ gs_string row; /* row buffers, [0 .. num_planes - 1] */ } image_enum_plane_t; struct gs_image_enum_s { @@ -35,7 +35,8 @@ struct gs_image_enum_s { int height; bool wanted_varies; /* The following are updated dynamically. */ - int plane_index; /* index of next plane of data */ + int plane_index; /* index of next plane of data, */ + /* only needed for gs_image_next */ int y; bool error; byte wanted[gs_image_max_planes]; @@ -188,6 +189,7 @@ gs_image_common_init(gs_image_enum * penum, gx_image_enum_common_t * pie, penum->height = pim->Height; for (i = 0; i < pie->num_planes; ++i) { penum->planes[i].pos = 0; + penum->planes[i].source.size = 0; /* for gs_image_next_planes */ penum->planes[i].row.data = 0; /* for GC */ penum->planes[i].row.size = 0; /* ditto */ } @@ -253,11 +255,11 @@ int gs_image_next(gs_image_enum * penum, const byte * dbytes, uint dsize, uint * pused) { - const gx_image_enum_common_t *pie = penum->info; int px = penum->plane_index; - gx_device *dev; int num_planes = penum->num_planes; - int code; + int i, code; + uint used[gs_image_max_planes]; + gs_const_string plane_data[gs_image_max_planes]; /* * Handle the following differences between gs_image_next and @@ -266,52 +268,80 @@ gs_image_next(gs_image_enum * penum, const byte * dbytes, uint dsize, * - image_data requires an array of planes; gs_image_next * expects planes in successive calls. * + * This function is now deprecated -- gs_image_next_planes does + * the real work of buffering. + */ + for (i = 0; i < num_planes; i++) + plane_data[i].size = 0; + plane_data[px].data = dbytes; + plane_data[px].size = dsize; + penum->error = false; + code = gs_image_next_planes(penum, plane_data, used); + if (code >= 0) { + /* Advance px to the next plane that needs data. */ + do { + if (++px == num_planes) + px = 0; + } while (!penum->wanted[px]); + penum->plane_index = px; + } + *pused = used[px]; + return code; +} + +int +gs_image_next_planes(gs_image_enum * penum, gs_const_string *plane_data, + uint * used) +{ + gx_image_plane_t planes[gs_image_max_planes]; + gx_device *dev = penum->dev; + int num_planes = penum->num_planes; + int i; + int code = 0; + bool need_planes = false; + + /* + * Handle the following differences between gs_image_next_planes and + * the device image_data procedure: + * + * - image_data requires an array of planes; not all of the + * planes may be available on any given call. + * * - image_data requires that each call pass entire rows; - * gs_image_next allows arbitrary amounts of data. + * gs_image_next_planes allows arbitrary amounts of data. */ - if (penum->error) { - /* - * We were interrupted by an error. The current data are the - * same as the data presented at the last call. - */ - penum->error = false; - } else { - if (px != 0 && dsize != penum->planes[0].source.size && - pie->plane_depths[px] == pie->plane_depths[0] && - pie->plane_widths[px] == pie->plane_widths[0]) - return_error(gs_error_rangecheck); - penum->planes[px].source.data = dbytes; - penum->planes[px].source.size = dsize; - while (++px < num_planes && !penum->wanted[px]) - DO_NOTHING; - if (px < num_planes) { - /* We need more planes. */ - penum->plane_index = px; - return 0; + for (i = 0; i < num_planes; ++i) { + used[i] = 0; + if (!penum->wanted[i]) + planes[i].data = 0; + else { + if (plane_data[i].size != 0) { + penum->planes[i].source.size = plane_data[i].size; + penum->planes[i].source.data = plane_data[i].data; + planes[i].data_x = 0; + planes[i].raster = gs_image_bytes_per_plane_row(penum, i); + } + if (penum->planes[i].source.size == 0) + need_planes = true; /* can't proceed until we have all planes */ } } - /* We have a full set of planes. */ - dev = penum->dev; - code = 0; - /****** HOW TO STOP IN TIME IF TOO MUCH DATA? ******/ + if (need_planes) + return 0; /* exit for more data, nothing used */ while (!code) { - gx_image_plane_t planes[gs_image_max_planes]; - int i; int direct = max_int; bool filled = true; + bool empty = false; + /* see if we can do some rows without buffering (i.e., direct) */ for (i = 0; i < num_planes; ++i) { - if (!penum->wanted[i]) - planes[i].data = 0; - else { - planes[i].data_x = 0; + /* need to reset planes[].raster if wanted_varies */ + if (penum->wanted_varies) planes[i].raster = gs_image_bytes_per_plane_row(penum, i); - if (penum->planes[i].pos == 0) - direct = min(direct, penum->planes[i].source.size / - planes[i].raster); - else - direct = 0; - } + if (penum->planes[i].pos == 0) /* nothing buffered for this row */ + direct = min(direct, + penum->planes[i].source.size / planes[i].raster); + else + direct = 0; } if (direct) { /* @@ -324,26 +354,30 @@ gs_image_next(gs_image_enum * penum, const byte * dbytes, uint dsize, if (penum->wanted[i]) planes[i].data = penum->planes[i].source.data; code = copy_planes(dev, penum, planes, direct, &direct); + if (code < 0) + return code; /* don't update */ for (i = 0; i < num_planes; ++i) if (planes[i].data) { - uint used = direct * planes[i].raster; + uint direct_used = direct * planes[i].raster; - penum->planes[i].source.data += used; - penum->planes[i].source.size -= used; + used[i] += direct_used; + penum->planes[i].source.data += direct_used; + penum->planes[i].source.size -= direct_used; + if (penum->planes[i].source.size == 0) + empty = true; } penum->y += direct; if (code < 0) break; } else { /* Buffer a partial row. */ - bool empty = false; uint count[gs_image_max_planes]; - /* Make sure the row buffers are allocated. */ - for (i = 0; i < num_planes; ++i) - if (penum->wanted[i]) { + for (i = 0; i < num_planes; ++i) { + if (penum->planes[i].source.size != 0) { uint raster = planes[i].raster; uint old_size = penum->planes[i].row.size; + /* Make sure the row buffers are allocated. */ if (raster > old_size) { byte *old_data = penum->planes[i].row.data; byte *row = @@ -362,15 +396,15 @@ gs_image_next(gs_image_enum * penum, const byte * dbytes, uint dsize, penum->planes[i].row.data = row; penum->planes[i].row.size = raster; } - count[i] = min(raster - penum->planes[i].pos, - penum->planes[i].source.size); - memcpy(penum->planes[i].row.data + penum->planes[i].pos, + if ((count[i] = min(raster - penum->planes[i].pos, + penum->planes[i].source.size)) > 0) { + memcpy(penum->planes[i].row.data + penum->planes[i].pos, penum->planes[i].source.data, count[i]); - if ((penum->planes[i].pos += count[i]) < raster) { - filled = false; - empty |= count[i] == 0; + if ((penum->planes[i].pos += count[i]) < raster) + filled = false; } } + } if (code < 0) break; if (filled) { @@ -385,26 +419,25 @@ gs_image_next(gs_image_enum * penum, const byte * dbytes, uint dsize, penum->planes[i].pos -= count[i]; break; } - for (i = 0; i < num_planes; ++i) + for (i = 0; i < num_planes; ++i) { penum->planes[i].pos = 0; + } penum->y++; } - for (i = 0; i < num_planes; ++i) + for (i = 0; i < num_planes; ++i) { if (penum->wanted[i]) { + used[i] += count[i]; penum->planes[i].source.data += count[i]; - penum->planes[i].source.size -= count[i]; + if ((penum->planes[i].source.size -= count[i]) == 0) + empty = true; } - if (empty) - break; + } } if (filled & !code) begin_planes(penum); + if (empty) + break; } - /* - * We only set *pused for the last plane of a group. We will have to - * rethink this in order to handle varying-size planes. - */ - *pused = penum->planes[penum->plane_index].source.data - dbytes; return code; } diff --git a/gs/src/gsimage.h b/gs/src/gsimage.h index dc861cf51..fc172031b 100644 --- a/gs/src/gsimage.h +++ b/gs/src/gsimage.h @@ -53,12 +53,10 @@ int gs_image_enum_init(P4(gs_image_enum * penum, const gs_data_image_t * pim, gs_state *pgs)); int gs_image_init(P4(gs_image_enum * penum, const gs_image_t * pim, bool MultipleDataSources, gs_state * pgs)); -int gs_image_next(P4(gs_image_enum * penum, const byte * dbytes, - uint dsize, uint * pused)); /* * Return the number of bytes of data per row - * (per plane, if MultipleDataSources is true). + * (per plane, if there are multiple data sources). */ uint gs_image_bytes_per_plane_row(P2(const gs_image_enum * penum, int plane)); @@ -74,4 +72,29 @@ const byte *gs_image_planes_wanted(P1(const gs_image_enum *penum)); /* Clean up after processing an image. */ void gs_image_cleanup(P1(gs_image_enum * penum)); +/* + * Pass multiple or selected planes of data for an image. + * *plane_data is an array of size num_planes of gs_const_string type + * which contains the pointer and the length for each. + * *used is also of size num_planes and will be set to the number of + * bytes consumed for each plane. + * The amount of data available for planes can be 0 in order to provide + * data for a single plane or only some of the planes. + * + * Returns 1 if end of image, < 0 error code, otherwise 0. + * + * ****** NEEDS DOC FROM RAY ABOUT RETENTION OF SOURCE DATA ****** + */ +int gs_image_next_planes(P3(gs_image_enum *penum, + gs_const_string *plane_data, + uint *used)); + +/* + * Pass the next plane of data for an image. This procedure should no + * longer be used: use gs_image_next_planes instead. + */ +int gs_image_next(P4(gs_image_enum * penum, const byte * dbytes, + uint dsize, uint * pused)); + + #endif /* gsimage_INCLUDED */ diff --git a/gs/src/zimage.c b/gs/src/zimage.c index 80cb7b7e1..502c5470b 100644 --- a/gs/src/zimage.c +++ b/gs/src/zimage.c @@ -276,8 +276,11 @@ image_proc_continue(i_ctx_t *i_ctx_p) { os_ptr op = osp; gs_image_enum *penum = r_ptr(esp, gs_image_enum); - uint size, used; - int code; + int px = ETOP_PLANE_INDEX(esp)->value.intval; + int num_sources = ETOP_NUM_SOURCES(esp)->value.intval; + uint size, used[gs_image_max_planes]; + gs_const_string plane_data[gs_image_max_planes]; + int i, code; if (!r_has_type_attrs(op, t_string, a_read)) { check_op(1); @@ -290,9 +293,14 @@ image_proc_continue(i_ctx_t *i_ctx_p) if (size == 0) code = 1; else { - code = gs_image_next(penum, op->value.bytes, size, &used); + for (i = 0; i < num_sources; i++) + plane_data[i].size = 0; + plane_data[px].data = op->value.bytes; + plane_data[px].size = size; + code = gs_image_next_planes(penum, plane_data, used); if (code == e_RemapColor) return code; + size -= used[px]; /* how much unused in this string */ } if (code) { /* Stop now. */ esp = zimage_pop_estack(esp); @@ -301,6 +309,11 @@ image_proc_continue(i_ctx_t *i_ctx_p) return (code < 0 ? code : o_pop_estack); } pop(1); + if (size != 0) { /* need a different plane of data */ + if (++px == num_sources) + px = 0; + ETOP_PLANE_INDEX(esp)->value.intval = px; + } return image_proc_process(i_ctx_p); } private int @@ -310,20 +323,17 @@ image_proc_process(i_ctx_t *i_ctx_p) gs_image_enum *penum = r_ptr(esp, gs_image_enum); const byte *wanted = gs_image_planes_wanted(penum); int num_sources = ETOP_NUM_SOURCES(esp)->value.intval; + const ref *pp; - for (;;) { - const ref *pp = ETOP_SOURCE(esp, px); - bool xmit = wanted[px]; - + while (!wanted[px]) { if (++px == num_sources) px = 0; - if (xmit) { - ETOP_PLANE_INDEX(esp)->value.intval = px; - push_op_estack(image_proc_continue); - *++esp = *pp; - return o_push_estack; - } + ETOP_PLANE_INDEX(esp)->value.intval = px; } + pp = ETOP_SOURCE(esp, px); + push_op_estack(image_proc_continue); + *++esp = *pp; + return o_push_estack; } /* Continue processing data from an image with file data sources. */ private int @@ -333,15 +343,15 @@ image_file_continue(i_ctx_t *i_ctx_p) int num_sources = ETOP_NUM_SOURCES(esp)->value.intval; for (;;) { - uint size = max_uint; + uint min_avail = max_int; + gs_const_string plane_data[gs_image_max_planes]; int code; int px; const ref *pp; /* - * Do a first pass through the files to ensure that they all - * have data available in their buffers, and compute the min - * of the available amounts. + * Do a first pass through the files to ensure that at least + * one has data available in its buffer. */ for (px = 0, pp = ETOP_SOURCE(esp, 0); px < num_sources; @@ -376,38 +386,30 @@ image_file_continue(i_ctx_t *i_ctx_p) } /* Note that in the EOF case, we can get here with */ /* avail < min_left. */ - if (avail >= min_left) { + if (avail >= min_left) avail = (avail - min_left) / num_aliases; - if (avail < size) - size = avail; - } else - size = 0; + if (avail < min_avail) + min_avail = avail; + plane_data[px].data = sbufptr(s); + plane_data[px].size = avail; } - /* Now pass the min of the available buffered data to */ - /* the image processor. */ + /* Now pass the available buffered data to the image processor. */ - if (size == 0) + if (min_avail == 0) code = 1; else { int pi; - uint used; /* only set for the last plane */ - - /****** WRONG IF ALIASING ******/ - /****** CHECK wanted ******/ - for (px = 0, pp = ETOP_SOURCE(esp, 0), code = 0; - px < num_sources && !code; - ++px, pp -= 2 - ) - code = gs_image_next(penum, sbufptr(pp->value.pfile), - size, &used); + uint used[gs_image_max_planes]; + + code = gs_image_next_planes(penum, plane_data, used); if (code == e_RemapColor) return code; /* Now that used has been set, update the streams. */ for (pi = 0, pp = ETOP_SOURCE(esp, 0); pi < num_sources; ++pi, pp -= 2 ) - sbufskip(pp->value.pfile, used); + sbufskip(pp->value.pfile, used[pi]); } if (code) { esp = zimage_pop_estack(esp); |