summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-05-22 13:35:31 +0100
committerRobin Watts <robin.watts@artifex.com>2012-05-22 19:42:37 +0100
commit15cc33536ada0b4cb105110a48df0132539c54db (patch)
treedf9660d76eb72bf83156de928a367d8ccc1aaf28
parent4677f28c2a0bf72a6bc89e785cc651d3deedc043 (diff)
Add downscaler functionality to tiffsep.
Update tiffsep to call the downscaler. This means adding MinFeatureSize and DownScaleFactor to tiffsep. Also add BitsPerComponent to allow us to specify 8 (default) or 1 (monochrome). MinFeatureSize is ignored except in monochrome mode. This has meant slight reworking of the downscaler to cope with planar buffers, and its use of get_bits_rectangle rather than get_bits. Also updated docs, and fixed some leaks on memory allocation failures within tiffsep.
-rw-r--r--gs/base/gdevtsep.c185
-rw-r--r--gs/base/gxdownscale.c519
-rw-r--r--gs/base/gxdownscale.h48
-rw-r--r--gs/base/lib.mak2
-rw-r--r--gs/doc/Devices.htm11
5 files changed, 367 insertions, 398 deletions
diff --git a/gs/base/gdevtsep.c b/gs/base/gdevtsep.c
index 9f19d614d..0710c2093 100644
--- a/gs/base/gdevtsep.c
+++ b/gs/base/gdevtsep.c
@@ -36,6 +36,7 @@
#include "ctype_.h"
#include "gxgetbit.h"
#include "gdevppla.h"
+#include "gxdownscale.h"
/*
* Some of the code in this module is based upon the gdevtfnx.c module.
@@ -418,6 +419,9 @@ static dev_proc_output_page(tiffseps_output_page);
TIFFTAG_COMPRESSION */\
bool close_files; \
long MaxStripSize;\
+ long DownScaleFactor;\
+ long MinFeatureSize;\
+ long BitsPerComponent;\
gs_devn_params devn_params; /* DeviceN generated parameters */\
equivalent_cmyk_color_params equiv_cmyk_colors\
@@ -588,7 +592,10 @@ gs_private_st_composite_final(st_tiffsep_device, tiffsep_device,
arch_is_big_endian /* true = big endian; false = little endian */,\
compr /* COMPRESSION_* */,\
true, /* close_files */ \
- TIFF_DEFAULT_STRIP_SIZE /* MaxStripSize */
+ TIFF_DEFAULT_STRIP_SIZE,/* MaxStripSize */\
+ 1, /* DownScaleFactor */\
+ 0, /* MinFeatureSize */\
+ 8 /* BitsPerComponent */
/*
* Select the default number of components based upon the number of bits
@@ -860,6 +867,12 @@ tiffsep_get_params(gx_device * pdev, gs_param_list * plist)
ecode = code;
if ((code = param_write_long(plist, "MaxStripSize", &pdevn->MaxStripSize)) < 0)
ecode = code;
+ if ((code = param_write_long(plist, "DownScaleFactor", &pdevn->DownScaleFactor)) < 0)
+ ecode = code;
+ if ((code = param_write_long(plist, "MinFeatureSize", &pdevn->MinFeatureSize)) < 0)
+ ecode = code;
+ if ((code = param_write_long(plist, "BitsPerComponent", &pdevn->BitsPerComponent)) < 0)
+ ecode = code;
return ecode;
}
@@ -873,6 +886,9 @@ tiffsep_put_params(gx_device * pdev, gs_param_list * plist)
const char *param_name;
gs_param_string comprstr;
bool save_close_files = pdevn->close_files;
+ long downscale = pdevn->DownScaleFactor;
+ long mfs = pdevn->MinFeatureSize;
+ long bpc = pdevn->BitsPerComponent;
/* Read BigEndian option as bool */
switch (code = param_read_bool(plist, (param_name = "BigEndian"), &pdevn->BigEndian)) {
@@ -916,6 +932,45 @@ tiffsep_put_params(gx_device * pdev, gs_param_list * plist)
case 1:
break;
}
+ switch (code = param_read_long(plist,
+ (param_name = "DownScaleFactor"),
+ &pdevn->DownScaleFactor)) {
+ case 0:
+ if (downscale <= 0)
+ downscale = 1;
+ break;
+ case 1:
+ break;
+ default:
+ param_signal_error(plist, param_name, code);
+ return code;
+ }
+ switch (code = param_read_long(plist, (param_name = "MinFeatureSize"), &mfs)) {
+ case 0:
+ if ((mfs >= 0) && (mfs <= 4)) {
+ pdevn->MinFeatureSize = mfs;
+ break;
+ }
+ code = gs_error_rangecheck;
+ case 1:
+ break;
+ default:
+ param_signal_error(plist, param_name, code);
+ return code;
+ }
+ switch (code = param_read_long(plist, (param_name = "BitsPerComponent"), &bpc)) {
+ case 0:
+ if ((bpc == 1) || (bpc == 8)) {
+ pdevn->BitsPerComponent = bpc;
+ break;
+ }
+ code = gs_error_rangecheck;
+ case 1:
+ break;
+ default:
+ param_signal_error(plist, param_name, code);
+ return code;
+ }
pdevn->close_files = false;
@@ -1714,8 +1769,13 @@ tiffsep_print_page(gx_device_printer * pdev, FILE * file)
int save_numcomps = pdev->color_info.num_components;
const char *fmt;
gs_parsed_file_name_t parsed;
- int non_encodable_count = 0;
int plane_count = 0; /* quite compiler */
+ int factor = tfdev->DownScaleFactor;
+ int mfs = tfdev->MinFeatureSize;
+ int dst_bpc = tfdev->BitsPerComponent;
+ gx_downscaler_t ds;
+ int width = tfdev->width / factor;
+ int height = tfdev->height / factor;
/* Print the names of the spot colors */
if (num_order == 0) {
@@ -1734,14 +1794,14 @@ tiffsep_print_page(gx_device_printer * pdev, FILE * file)
strlen(tfdev->fname), pdev->memory);
/* Write the page directory for the CMYK equivalent file. */
- pdev->color_info.depth = 32; /* Create directory for 32 bit cmyk */
- if (tfdev->Compression==COMPRESSION_NONE &&
- pdev->height > ((unsigned long) 0xFFFFFFFF - ftell(file))/(pdev->width*4)) { /* note width is never 0 in print_page */
- dprintf("CMYK composite file would be too large! Reduce resolution or enable compression.\n");
- return_error(gs_error_rangecheck); /* this will overflow 32 bits */
- }
+ if (dst_bpc == 8 && !tfdev->comp_file) {
+ pdev->color_info.depth = 32; /* Create directory for 32 bit cmyk */
+ if (tfdev->Compression==COMPRESSION_NONE &&
+ height > ((unsigned long) 0xFFFFFFFF - ftell(file))/(pdev->width*4)) { /* note width is never 0 in print_page */
+ dprintf("CMYK composite file would be too large! Reduce resolution or enable compression.\n");
+ return_error(gs_error_rangecheck); /* this will overflow 32 bits */
+ }
- if (!tfdev->comp_file) {
code = gx_device_open_output_file((gx_device *)pdev, pdev->fname, true, true, &(tfdev->comp_file));
if (code < 0)
return code;
@@ -1751,11 +1811,20 @@ tiffsep_print_page(gx_device_printer * pdev, FILE * file)
return_error(gs_error_invalidfileaccess);
}
- code = tiff_set_fields_for_printer(pdev, tfdev->tiff_comp, 1, 0);
- if (tfdev->Compression==COMPRESSION_NONE || tfdev->Compression==COMPRESSION_LZW || tfdev->Compression==COMPRESSION_PACKBITS)
- tiff_set_cmyk_fields(pdev, tfdev->tiff_comp, 8, tfdev->Compression, tfdev->MaxStripSize);
- else
- tiff_set_cmyk_fields(pdev, tfdev->tiff_comp, 8, COMPRESSION_LZW, tfdev->MaxStripSize);
+ if (dst_bpc == 8) {
+ code = tiff_set_fields_for_printer(pdev, tfdev->tiff_comp, factor, 0);
+ if (dst_bpc == 1 && (tfdev->Compression==COMPRESSION_NONE ||
+ tfdev->Compression==COMPRESSION_CCITTRLE ||
+ tfdev->Compression==COMPRESSION_CCITTFAX3 ||
+ tfdev->Compression==COMPRESSION_CCITTFAX4))
+ tiff_set_cmyk_fields(pdev, tfdev->tiff_comp, 1, tfdev->Compression, tfdev->MaxStripSize);
+ else if (dst_bpc == 8 && (tfdev->Compression==COMPRESSION_NONE ||
+ tfdev->Compression==COMPRESSION_LZW ||
+ tfdev->Compression==COMPRESSION_PACKBITS))
+ tiff_set_cmyk_fields(pdev, tfdev->tiff_comp, 8, tfdev->Compression, tfdev->MaxStripSize);
+ else
+ tiff_set_cmyk_fields(pdev, tfdev->tiff_comp, 8, COMPRESSION_LZW, tfdev->MaxStripSize);
+}
pdev->color_info.depth = save_depth;
if (code < 0)
return code;
@@ -1789,52 +1858,52 @@ tiffsep_print_page(gx_device_printer * pdev, FILE * file)
return_error(gs_error_ioerror);
}
- pdev->color_info.depth = 8; /* Create files for 8 bit gray */
+ pdev->color_info.depth = dst_bpc; /* Create files for 8 bit gray */
pdev->color_info.num_components = 1;
if (tfdev->Compression==COMPRESSION_NONE &&
- pdev->height > ((unsigned long) 0xFFFFFFFF - ftell(file))/(pdev->width)) /* note width is never 0 in print_page */
+ height*8/dst_bpc > ((unsigned long) 0xFFFFFFFF - ftell(file))/width) /* note width is never 0 in print_page */
return_error(gs_error_rangecheck); /* this will overflow 32 bits */
- code = tiff_set_fields_for_printer(pdev, tfdev->tiff[comp_num], 1, 0);
- tiff_set_gray_fields(pdev, tfdev->tiff[comp_num], 8, tfdev->Compression, tfdev->MaxStripSize);
+ code = tiff_set_fields_for_printer(pdev, tfdev->tiff[comp_num], factor, 0);
+ tiff_set_gray_fields(pdev, tfdev->tiff[comp_num], dst_bpc, tfdev->Compression, tfdev->MaxStripSize);
pdev->color_info.depth = save_depth;
pdev->color_info.num_components = save_numcomps;
if (code < 0)
return code;
}
- build_cmyk_map(tfdev, num_comp, cmyk_map);
+ if (dst_bpc == 8)
+ build_cmyk_map(tfdev, num_comp, cmyk_map);
{
- int raster_plane = bitmap_raster(pdev->width * 8);
+ int raster_plane = bitmap_raster(width * 8);
byte *planes[GS_CLIENT_COLOR_MAX_COMPONENTS];
- int width = tfdev->width;
int cmyk_raster = width * NUM_CMYK_COMPONENTS;
int pixel, y;
byte * sep_line;
- int plane_index, offset_plane;
+ int plane_index;
+ int offset_plane = 0;
sep_line =
gs_alloc_bytes(pdev->memory, cmyk_raster, "tiffsep_print_page");
for (comp_num = 0; comp_num < num_comp; comp_num++ )
TIFFCheckpointDirectory(tfdev->tiff[comp_num]);
- TIFFCheckpointDirectory(tfdev->tiff_comp);
+ if (dst_bpc == 8)
+ TIFFCheckpointDirectory(tfdev->tiff_comp);
/* Write the page data. */
{
- gs_int_rect rect;
gs_get_bits_params_t params;
- rect.q.x = pdev->width;
- rect.p.x = 0;
- /* Return planar data */
+ /* Return planar data */
params.options = (GB_RETURN_POINTER | GB_RETURN_COPY |
GB_ALIGN_STANDARD | GB_OFFSET_0 | GB_RASTER_STANDARD |
GB_PACKING_PLANAR | GB_COLORS_NATIVE | GB_ALPHA_NONE);
params.x_offset = 0;
- params.raster = bitmap_raster(pdev->width * pdev->color_info.depth);
+ params.raster = bitmap_raster(width * pdev->color_info.depth);
+ memset(planes, 0, sizeof(*planes) * plane_count);
if (num_order > 0) {
/* In this case, there was a specification for a separation
color order, which indicates what colorants we will
@@ -1844,10 +1913,12 @@ tiffsep_print_page(gx_device_printer * pdev, FILE * file)
still create the composite CMYK output file. */
for (comp_num = 0; comp_num < num_std_colorants; comp_num++) {
planes[comp_num] = gs_alloc_bytes(pdev->memory, raster_plane,
- "tiffsep_print_page");
+ "tiffsep_print_page");
params.data[comp_num] = planes[comp_num];
- if (params.data[comp_num] == NULL)
- return_error(gs_error_VMerror);
+ if (params.data[comp_num] == NULL) {
+ code = gs_error_VMerror;
+ goto cleanup;
+ }
}
offset_plane = num_std_colorants;
/* Now we need to make sure that we do not allocate extra
@@ -1865,8 +1936,10 @@ tiffsep_print_page(gx_device_printer * pdev, FILE * file)
"tiffsep_print_page");
/* Assign the new plane to the appropriate position */
params.data[plane_index] = planes[plane_count];
- if (params.data[plane_index] == NULL)
- return_error(gs_error_VMerror);
+ if (params.data[plane_index] == NULL) {
+ code = gs_error_VMerror;
+ goto cleanup;
+ }
plane_count += 1;
} else {
/* Assign params.data with the appropriate std.
@@ -1882,16 +1955,20 @@ tiffsep_print_page(gx_device_printer * pdev, FILE * file)
planes[comp_num] = gs_alloc_bytes(pdev->memory, raster_plane,
"tiffsep_print_page");
params.data[comp_num] = planes[comp_num];
- if (params.data[comp_num] == NULL)
- return_error(gs_error_VMerror);
+ if (params.data[comp_num] == NULL) {
+ code = gs_error_VMerror;
+ goto cleanup;
+ }
}
- offset_plane = 0;
}
- for (y = 0; y < pdev->height; ++y) {
- rect.p.y = y;
- rect.q.y = y + 1;
- code = dev_proc(pdev, get_bits_rectangle)
- ((gx_device *) pdev, &rect, &params, NULL);
+ code = gx_downscaler_init_planar(&ds, (gx_device *)pdev, &params,
+ num_comp, factor, mfs, dst_bpc);
+ if (code < 0)
+ goto cleanup;
+ for (y = 0; y < height; ++y) {
+ code = gx_downscaler_get_bits_rectangle(&ds, &params, y);
+ if (code < 0)
+ goto cleanup;
/* Write separation data (tiffgray format) */
for (comp_num = 0; comp_num < num_comp; comp_num++ ) {
byte *src;
@@ -1906,12 +1983,14 @@ tiffsep_print_page(gx_device_printer * pdev, FILE * file)
TIFFWriteScanline(tfdev->tiff[comp_num], (tdata_t)sep_line, y, 0);
}
/* Write CMYK equivalent data (tiff32nc format) */
- build_cmyk_raster_line_fromplanar(params, sep_line, width,
- num_comp, cmyk_map, num_order,
- tfdev);
- TIFFWriteScanline(tfdev->tiff_comp, (tdata_t)sep_line, y, 0);
+ if (dst_bpc == 8) {
+ build_cmyk_raster_line_fromplanar(params, sep_line, width,
+ num_comp, cmyk_map, num_order,
+ tfdev);
+ TIFFWriteScanline(tfdev->tiff_comp, (tdata_t)sep_line, y, 0);
+ }
}
- gs_free_object(pdev->memory, sep_line, "tiffsep_print_page");
+cleanup:
if (num_order > 0) {
/* Free up the standard colorants if num_order was set.
In this process, we need to make sure that none of them
@@ -1928,8 +2007,10 @@ tiffsep_print_page(gx_device_printer * pdev, FILE * file)
"tiffsep_print_page");
}
}
+ gx_downscaler_fin(&ds);
+ gs_free_object(pdev->memory, sep_line, "tiffsep_print_page");
}
- code1 = 0;
+ code1 = code;
for (comp_num = 0; comp_num < num_comp; comp_num++ ) {
TIFFWriteDirectory(tfdev->tiff[comp_num]);
if (fmt) {
@@ -1947,7 +2028,8 @@ tiffsep_print_page(gx_device_printer * pdev, FILE * file)
}
}
- TIFFWriteDirectory(tfdev->tiff_comp);
+ if (dst_bpc == 8)
+ TIFFWriteDirectory(tfdev->tiff_comp);
if (fmt) {
code = tiffsep_close_comp_file(tfdev, pdev->fname);
}
@@ -1961,13 +2043,6 @@ tiffsep_print_page(gx_device_printer * pdev, FILE * file)
max(16, num_comp));
#endif
- /*
- * If we have any non encodable pixels then signal an error.
- */
- if (non_encodable_count) {
- dlprintf1("WARNING: Non encodable pixels = %d\n", non_encodable_count);
- return_error(gs_error_rangecheck);
- }
/* After page is printed free up the separation list since we may have
different spots on the next page */
free_separation_names(tfdev->memory, &(tfdev->devn_params.separations));
diff --git a/gs/base/gxdownscale.c b/gs/base/gxdownscale.c
index 55badfc59..b80fe3ce8 100644
--- a/gs/base/gxdownscale.c
+++ b/gs/base/gxdownscale.c
@@ -37,7 +37,10 @@ enum {
/* Mono downscale/error diffusion/min feature size code */
static void down_core(gx_downscaler_t *ds,
byte *out_buffer,
- int row)
+ byte *in_buffer,
+ int row,
+ int plane,
+ int span)
{
int x, xx, y, value;
int mask;
@@ -47,19 +50,21 @@ static void down_core(gx_downscaler_t *ds,
int width = ds->width;
int awidth = ds->awidth;
int factor = ds->factor;
- int span = ds->span;
- int *errors = ds->errors;
+ int *errors = ds->errors + (awidth+3)*plane;
byte *mfs_data = ds->mfs_data;
const int threshold = factor*factor*128;
const int max_value = factor*factor*255;
+ if (mfs_data)
+ mfs_data += (awidth+1)*plane;
+
pad_white = (awidth - width) * factor;
if (pad_white < 0)
pad_white = 0;
if (pad_white)
{
- inp = ds->data + width*factor;
+ inp = in_buffer + width*factor;
for (y = factor; y > 0; y--)
{
memset(inp, 0xFF, pad_white);
@@ -67,7 +72,7 @@ static void down_core(gx_downscaler_t *ds,
}
}
- inp = ds->data;
+ inp = in_buffer;
if (mfs_data == NULL)
{
if ((row & 1) == 0)
@@ -300,23 +305,20 @@ static void down_core(gx_downscaler_t *ds,
}
/* Grey downscale code */
-#ifdef DO_STUPID_ERROR_DIFFUSION
static void down_core8(gx_downscaler_t *ds,
byte *outp,
- int row)
+ byte *in_buffer,
+ int row,
+ int plane,
+ int span)
{
- int x, xx, y, value;
- int mask;
- int e_downleft, e_down, e_forward = 0;
- int pad_white;
- byte *inp;
- int width = ds->width;
- int awidth = ds->awidth;
- int factor = ds->factor;
- int span = ds->span;
- int *errors = ds->errors;
- byte *mfs_data = ds->mfs_data;
- int div = factor*factor;
+ int x, xx, y, value;
+ int pad_white;
+ byte *inp;
+ int width = ds->width;
+ int awidth = ds->awidth;
+ int factor = ds->factor;
+ int div = factor*factor;
pad_white = (awidth - width) * factor;
if (pad_white < 0)
@@ -324,7 +326,7 @@ static void down_core8(gx_downscaler_t *ds,
if (pad_white)
{
- inp = ds->data + width*factor;
+ inp = in_buffer + width*factor;
for (y = factor; y > 0; y--)
{
memset(inp, 0xFF, pad_white);
@@ -332,104 +334,10 @@ static void down_core8(gx_downscaler_t *ds,
}
}
- inp = ds->data;
- if ((row & 1) == 0)
+ inp = in_buffer;
{
/* Left to Right pass (no min feature size) */
const int back = span * factor -1;
- errors += 2;
- for (x = awidth; x > 0; x--)
- {
- int res;
- value = e_forward + *errors;
- for (xx = factor; xx > 0; xx--)
- {
- for (y = factor; y > 0; y--)
- {
- value += *inp;
- inp += span;
- }
- inp -= back;
- }
- res = (value+(div>>1))/div;
- *outp++ = res;
- value -= res*div;
- e_forward = value * 7/16;
- e_downleft = value * 3/16;
- e_down = value * 5/16;
- value -= e_forward + e_downleft + e_down;
- errors[-2] += e_downleft;
- errors[-1] += e_down;
- *errors++ = value;
- }
- }
- else
- {
- /* Right to Left pass (no min feature size) */
- const int back = span * factor + 1;
- errors += awidth;
- inp += awidth*factor-1;
- outp += awidth-1;
- for (x = awidth; x > 0; x--)
- {
- int res;
- value = e_forward + *errors;
- for (xx = factor; xx > 0; xx--)
- {
- for (y = factor; y > 0; y--)
- {
- value += *inp;
- inp += span;
- }
- inp -= back;
- }
- res = (value + (div>>1))/div;
- *outp-- = res;
- value -= res*div;
- e_forward = value * 7/16;
- e_downleft = value * 3/16;
- e_down = value * 5/16;
- value -= e_forward + e_downleft + e_down;
- errors[2] += e_downleft;
- errors[1] += e_down;
- *errors-- = value;
- }
- }
-}
-#else
-static void down_core8(gx_downscaler_t *ds,
- byte *outp,
- int row)
-{
- int x, xx, y, value;
- int pad_white;
- byte *inp;
- int width = ds->width;
- int awidth = ds->awidth;
- int factor = ds->factor;
- int span = ds->span;
- int *errors = ds->errors;
- int div = factor*factor;
-
- pad_white = (awidth - width) * factor;
- if (pad_white < 0)
- pad_white = 0;
-
- if (pad_white)
- {
- inp = ds->data + width*factor;
- for (y = factor; y > 0; y--)
- {
- memset(inp, 0xFF, pad_white);
- inp += span;
- }
- }
-
- inp = ds->data;
- {
- /* Left to Right pass (no min feature size) */
- const int back = span * factor -1;
- errors += 2;
for (x = awidth; x > 0; x--)
{
value = 0;
@@ -446,29 +354,23 @@ static void down_core8(gx_downscaler_t *ds,
}
}
}
-#endif
-/* RGB downscale/error diffusion code */
-#ifdef DO_STUPID_ERROR_DIFFUSION
+/* RGB downscale (no error diffusion) code */
+
static void down_core24(gx_downscaler_t *ds,
byte *outp,
- int row)
+ byte *in_buffer,
+ int row,
+ int plane,
+ int span)
{
- int x, xx, y, value;
- int mask;
- int e_downleft, e_down;
- int e_forward_r = 0;
- int e_forward_g = 0;
- int e_forward_b = 0;
- int pad_white;
- byte *inp;
- int width = ds->width;
- int awidth = ds->awidth;
- int factor = ds->factor;
- int span = ds->span;
- int *errors = ds->errors;
- byte *mfs_data = ds->mfs_data;
- int div = factor*factor;
+ int x, xx, y, value;
+ int pad_white;
+ byte *inp;
+ int width = ds->width;
+ int awidth = ds->awidth;
+ int factor = ds->factor;
+ int div = factor*factor;
pad_white = (awidth - width) * factor * 3;
if (pad_white < 0)
@@ -476,7 +378,7 @@ static void down_core24(gx_downscaler_t *ds,
if (pad_white)
{
- inp = ds->data + width*factor*3;
+ inp = in_buffer + width*factor*3;
for (y = factor; y > 0; y--)
{
memset(inp, 0xFF, pad_white);
@@ -484,18 +386,15 @@ static void down_core24(gx_downscaler_t *ds,
}
}
- inp = ds->data;
- if ((row & 1) == 0)
+ inp = in_buffer;
{
/* Left to Right pass (no min feature size) */
const int back = span * factor - 3;
const int back2 = factor * 3 - 1;
- errors += 6;
for (x = awidth; x > 0; x--)
{
- int res;
/* R */
- value = e_forward_r + *errors;
+ value = 0;
for (xx = factor; xx > 0; xx--)
{
for (y = factor; y > 0; y--)
@@ -506,18 +405,9 @@ static void down_core24(gx_downscaler_t *ds,
inp -= back;
}
inp -= back2;
- res = (value+(div>>1))/div;
- *outp++ = res;
- value -= res*div;
- e_forward_r = value * 7/16;
- e_downleft = value * 3/16;
- e_down = value * 5/16;
- value -= e_forward_r + e_downleft + e_down;
- errors[-2] += e_downleft;
- errors[-1] += e_down;
- *errors++ = value;
+ *outp++ = (value+(div>>1))/div;
/* G */
- value = e_forward_g + *errors;
+ value = 0;
for (xx = factor; xx > 0; xx--)
{
for (y = factor; y > 0; y--)
@@ -528,18 +418,9 @@ static void down_core24(gx_downscaler_t *ds,
inp -= back;
}
inp -= back2;
- res = (value+(div>>1))/div;
- *outp++ = res;
- value -= res*div;
- e_forward_g = value * 7/16;
- e_downleft = value * 3/16;
- e_down = value * 5/16;
- value -= e_forward_g + e_downleft + e_down;
- errors[-2] += e_downleft;
- errors[-1] += e_down;
- *errors++ = value;
+ *outp++ = (value+(div>>1))/div;
/* B */
- value = e_forward_b + *errors;
+ value = 0;
for (xx = factor; xx > 0; xx--)
{
for (y = factor; y > 0; y--)
@@ -550,176 +431,80 @@ static void down_core24(gx_downscaler_t *ds,
inp -= back;
}
inp -= 2;
- res = (value+(div>>1))/div;
- *outp++ = res;
- value -= res*div;
- e_forward_b = value * 7/16;
- e_downleft = value * 3/16;
- e_down = value * 5/16;
- value -= e_forward_b + e_downleft + e_down;
- errors[-2] += e_downleft;
- errors[-1] += e_down;
- *errors++ = value;
- }
- }
- else
- {
- /* Right to Left pass (no min feature size) */
- const int back = span * factor + 3;
- const int back2 = factor * 3 - 1;
- errors += 3*awidth;
- inp += 3*awidth*factor-1;
- outp += 3*awidth - 1;
- for (x = awidth; x > 0; x--)
- {
- int res;
- /* B */
- value = e_forward_b + *errors;
- for (xx = factor; xx > 0; xx--)
- {
- for (y = factor; y > 0; y--)
- {
- value += *inp;
- inp += span;
- }
- inp -= back;
- }
- inp += back2;
- res = (value + (div>>1))/div;
- *outp-- = res;
- value -= res*div;
- e_forward_b = value * 7/16;
- e_downleft = value * 3/16;
- e_down = value * 5/16;
- value -= e_forward_b + e_downleft + e_down;
- errors[2] += e_downleft;
- errors[1] += e_down;
- *errors-- = value;
- /* G */
- value = e_forward_g + *errors;
- for (xx = factor; xx > 0; xx--)
- {
- for (y = factor; y > 0; y--)
- {
- value += *inp;
- inp += span;
- }
- inp -= back;
- }
- inp += back2;
- res = (value + (div>>1))/div;
- *outp-- = res;
- value -= res*div;
- e_forward_g = value * 7/16;
- e_downleft = value * 3/16;
- e_down = value * 5/16;
- value -= e_forward_g + e_downleft + e_down;
- errors[2] += e_downleft;
- errors[1] += e_down;
- *errors-- = value;
- /* R */
- value = e_forward_r + *errors;
- for (xx = factor; xx > 0; xx--)
- {
- for (y = factor; y > 0; y--)
- {
- value += *inp;
- inp += span;
- }
- inp -= back;
- }
- inp += 2;
- res = (value + (div>>1))/div;
- *outp-- = res;
- value -= res*div;
- e_forward_r = value * 7/16;
- e_downleft = value * 3/16;
- e_down = value * 5/16;
- value -= e_forward_r + e_downleft + e_down;
- errors[2] += e_downleft;
- errors[1] += e_down;
- *errors-- = value;
+ *outp++ = (value+(div>>1))/div;
}
}
}
-#else
-static void down_core24(gx_downscaler_t *ds,
- byte *outp,
- int row)
-{
- int x, xx, y, value;
- int pad_white;
- byte *inp;
- int width = ds->width;
- int awidth = ds->awidth;
- int factor = ds->factor;
- int span = ds->span;
- int div = factor*factor;
- pad_white = (awidth - width) * factor * 3;
- if (pad_white < 0)
- pad_white = 0;
+int gx_downscaler_init_planar(gx_downscaler_t *ds,
+ gx_device *dev,
+ gs_get_bits_params_t *params,
+ int num_comps,
+ int factor,
+ int mfs,
+ int dst_bpc)
+{
+ int span = bitmap_raster(dev->width * 8);
+ int width = dev->width/factor;
+ int code;
+ gx_downscale_core *core;
+ int i;
- if (pad_white)
+ memset(ds, 0, sizeof(*ds));
+ ds->dev = dev;
+ ds->width = width;
+ ds->awidth = width;
+ ds->span = span;
+ ds->factor = factor;
+ ds->num_planes = num_comps;
+
+ memcpy(&ds->params, params, sizeof(*params));
+ ds->params.raster = span;
+ for (i = 0; i < num_comps; i++)
{
- inp = ds->data + width*factor*3;
- for (y = factor; y > 0; y--)
- {
- memset(inp, 0xFF, pad_white);
- inp += span;
- }
+ ds->params.data[i] = gs_alloc_bytes(dev->memory, span * factor,
+ "gx_downscaler(planar_data)");
+ if (ds->params.data[i] == NULL)
+ goto cleanup;
}
- inp = ds->data;
+ if (dst_bpc == 1)
+ core = &down_core;
+ else if (factor == 1)
+ core = NULL;
+ else
+ core = &down_core8;
+ ds->down_core = core;
+
+ if (mfs > 1) {
+ ds->mfs_data = (byte *)gs_alloc_bytes(dev->memory,
+ (width+1) * num_comps,
+ "gx_downscaler(mfs)");
+ if (ds->mfs_data == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto cleanup;
+ }
+ memset(ds->mfs_data, 0, (width+1) * num_comps);
+ }
+ if (dst_bpc == 1)
{
- /* Left to Right pass (no min feature size) */
- const int back = span * factor - 3;
- const int back2 = factor * 3 - 1;
- for (x = awidth; x > 0; x--)
+ ds->errors = (int *)gs_alloc_bytes(dev->memory,
+ num_comps*(width+3)*sizeof(int),
+ "gx_downscaler(errors)");
+ if (ds->errors == NULL)
{
- /* R */
- value = 0;
- for (xx = factor; xx > 0; xx--)
- {
- for (y = factor; y > 0; y--)
- {
- value += *inp;
- inp += span;
- }
- inp -= back;
- }
- inp -= back2;
- *outp++ = (value+(div>>1))/div;
- /* G */
- value = 0;
- for (xx = factor; xx > 0; xx--)
- {
- for (y = factor; y > 0; y--)
- {
- value += *inp;
- inp += span;
- }
- inp -= back;
- }
- inp -= back2;
- *outp++ = (value+(div>>1))/div;
- /* B */
- value = 0;
- for (xx = factor; xx > 0; xx--)
- {
- for (y = factor; y > 0; y--)
- {
- value += *inp;
- inp += span;
- }
- inp -= back;
- }
- inp -= 2;
- *outp++ = (value+(div>>1))/div;
+ code = gs_note_error(gs_error_VMerror);
+ goto cleanup;
}
+ memset(ds->errors, 0, num_comps * (width+3) * sizeof(int));
}
+
+ return 0;
+
+ cleanup:
+ gx_downscaler_fin(ds);
+ return code;
}
-#endif
int gx_downscaler_init(gx_downscaler_t *ds,
gx_device *dev,
@@ -729,7 +514,7 @@ int gx_downscaler_init(gx_downscaler_t *ds,
int factor,
int mfs,
int (*adjust_width_proc)(int, int),
- int adjust_width)
+ int adjust_width)
{
int size = gdev_mem_bytes_per_scan_line((gx_device *)dev);
int span;
@@ -747,11 +532,12 @@ int gx_downscaler_init(gx_downscaler_t *ds,
span = size + pad_white*factor*num_comps + factor-1;
memset(ds, 0, sizeof(*ds));
- ds->dev = dev;
- ds->width = width;
- ds->awidth = awidth;
- ds->span = span;
- ds->factor = factor;
+ ds->dev = dev;
+ ds->width = width;
+ ds->awidth = awidth;
+ ds->span = span;
+ ds->factor = factor;
+ ds->num_planes = 0;
/* Choose an appropriate core */
if ((src_bpc == 8) && (dst_bpc == 1) && (num_comps == 1))
@@ -785,9 +571,7 @@ int gx_downscaler_init(gx_downscaler_t *ds,
}
memset(ds->mfs_data, 0, awidth+1);
}
-#ifndef DO_STUPID_ERROR_DIFFUSION
if (dst_bpc == 1)
-#endif
{
ds->errors = (int *)gs_alloc_bytes(dev->memory,
num_comps*(awidth+3)*sizeof(int),
@@ -810,6 +594,14 @@ int gx_downscaler_init(gx_downscaler_t *ds,
void gx_downscaler_fin(gx_downscaler_t *ds)
{
+ int plane;
+ for (plane=0; plane < ds->num_planes; plane++)
+ {
+ gs_free_object(ds->dev->memory, ds->params.data[plane],
+ "gx_downscaler(planar_data)");
+ }
+ ds->num_planes = 0;
+
gs_free_object(ds->dev->memory, ds->mfs_data, "gx_downscaler(mfs)");
ds->mfs_data = NULL;
gs_free_object(ds->dev->memory, ds->errors, "gx_downscaler(errors)");
@@ -843,7 +635,78 @@ int gx_downscaler_getbits(gx_downscaler_t *ds,
y++;
} while (y < y_end);
- (ds->down_core)(ds, out_data, row);
+ (ds->down_core)(ds, out_data, ds->data, row, 0, ds->span);
+
+ return code;
+}
+
+int gx_downscaler_get_bits_rectangle(gx_downscaler_t *ds,
+ gs_get_bits_params_t *params,
+ int row)
+{
+ int code;
+ gs_int_rect rect;
+ int plane;
+ int factor = ds->factor;
+ gs_get_bits_params_t params2;
+
+
+ rect.p.x = 0;
+ rect.p.y = row * factor;
+ rect.q.x = ds->dev->width;
+ rect.q.y = (row + 1) * factor;
+
+ /* Check for the simple case */
+ if (ds->down_core == NULL) {
+ return (*dev_proc(ds->dev, get_bits_rectangle))(ds->dev, &rect, params, NULL);
+ }
+
+ /* Copy the params, because get_bits_rectangle can helpfully overwrite
+ * them. */
+ memcpy(&params2, &ds->params, sizeof(params2));
+ /* Get factor rows worth of data */
+ code = (*dev_proc(ds->dev, get_bits_rectangle))(ds->dev, &rect, &params2, NULL);
+ if (code == gs_error_rangecheck)
+ {
+ int i, j;
+ int copy = ds->dev->width; /* Assumes 8bpp */
+ /* At the bottom of a band, the get_bits_rectangle call can fail to be
+ * able to return us enough lines of data at the same time. We therefore
+ * drop back to reading them one at a time, and copying them into our
+ * own buffer. */
+ for (i = 0; i < factor; i++) {
+ rect.q.y = rect.p.y+1;
+ if (rect.q.y > ds->dev->height)
+ break;
+ memcpy(&params2, &ds->params, sizeof(params2));
+ code = (*dev_proc(ds->dev, get_bits_rectangle))(ds->dev, &rect, &params2, NULL);
+ if (code < 0)
+ break;
+ for (j = 0; j < ds->num_planes; j++) {
+ memcpy(ds->params.data[j] + i*ds->span, params2.data[j], copy);
+ }
+ rect.p.y++;
+ }
+ if (i == 0)
+ return code;
+ /* If we still haven't got enough, we've hit the end of the page; just
+ * duplicate the last line we did get. */
+ for (;i < factor; i++) {
+ for (j = 0; j < ds->num_planes; j++) {
+ memcpy(ds->params.data[j] + i*ds->span, ds->params.data[j] + (i-1)*ds->span, copy);
+ }
+ }
+ for (j = 0; j < ds->num_planes; j++) {
+ params2.data[j] = ds->params.data[j];
+ }
+ }
+ if (code < 0)
+ return code;
+
+ for (plane=0; plane < ds->num_planes; plane++)
+ {
+ (ds->down_core)(ds, params->data[plane], params2.data[plane], row, plane, params2.raster);
+ }
return code;
}
diff --git a/gs/base/gxdownscale.h b/gs/base/gxdownscale.h
index aa65bca34..70fe62e5f 100644
--- a/gs/base/gxdownscale.h
+++ b/gs/base/gxdownscale.h
@@ -18,6 +18,7 @@
#include "gsmemory.h"
#include "gstypes.h"
#include "gxdevcli.h"
+#include "gxgetbit.h"
/* The following structure definitions should really be considered
* private, and are exposed here only because it enables us to define
@@ -28,34 +29,41 @@ typedef struct gx_downscaler_s gx_downscaler_t;
typedef void (gx_downscale_core)(gx_downscaler_t *ds,
byte *out_buffer,
- int row);
+ byte *in_buffer,
+ int row,
+ int plane,
+ int span);
struct gx_downscaler_s {
- gx_device *dev; /* Device */
- int width; /* Width (pixels) */
- int awidth; /* Adjusted width (pixels) */
- int span; /* Num bytes in downscale buffer scanline */
- int factor; /* Factor to downscale */
- byte *mfs_data; /* MinFeatureSize data */
- int *errors; /* Error diffusion table */
- byte *data; /* Downscaling buffer */
- gx_downscale_core *down_core;
+ gx_device *dev; /* Device */
+ int width; /* Width (pixels) */
+ int awidth; /* Adjusted width (pixels) */
+ int span; /* Num bytes in downscale buffer scanline */
+ int factor; /* Factor to downscale */
+ byte *mfs_data; /* MinFeatureSize data */
+ int *errors; /* Error diffusion table */
+ byte *data; /* Downscaling buffer */
+ gx_downscale_core *down_core; /* Core downscaling function */
+ gs_get_bits_params_t params; /* Params if in planar mode */
+ int num_planes;/* Number of planes if planar, 0 otherwise */
};
/* To use the downscaler:
*
* + define a gx_downscaler_t on the stack.
- * + initialise it with gx_downscaler_init
+ * + initialise it with gx_downscaler_init or gx_downscaler_init_planar
* + repeatedly call gx_downscaler_get_lines (or
- * gx_downscaler_copy_scan_lines)
+ * gx_downscaler_copy_scan_lines) (for chunky mode) or
+ * gx_downscaler_get_bits_rectangle (for planar mode)
* + finalise with gx_downscaler_fin
*/
-/* Currently only:
+/* For chunky mode, currently only:
* src_bpc == 8 && dst_bpc == 1 && num_comps == 1
* src_bpc == 8 && dst_bpc == 8 && num_comps == 1
* src_bpc == 8 && dst_bpc == 8 && num_comps == 3
* are supported. mfs is ignored for all except the first of these.
+ * For planar mode, currently only src_bpp && dst_bpp == 8 are supported.
*/
int gx_downscaler_init(gx_downscaler_t *ds,
gx_device *dev,
@@ -65,12 +73,24 @@ int gx_downscaler_init(gx_downscaler_t *ds,
int factor,
int mfs,
int (*adjust_width_proc)(int, int),
- int adjust_width);
+ int adjust_width);
+
+int gx_downscaler_init_planar(gx_downscaler_t *ds,
+ gx_device *dev,
+ gs_get_bits_params_t *params,
+ int num_comps,
+ int factor,
+ int mfs,
+ int dst_bpc);
int gx_downscaler_getbits(gx_downscaler_t *ds,
byte *out_data,
int row);
+int gx_downscaler_get_bits_rectangle(gx_downscaler_t *ds,
+ gs_get_bits_params_t *params,
+ int row);
+
/* Must only fin a device that has been inited (though you can safely
* fin several times) */
void gx_downscaler_fin(gx_downscaler_t *ds);
diff --git a/gs/base/lib.mak b/gs/base/lib.mak
index b2fcd10e0..37240fdf0 100644
--- a/gs/base/lib.mak
+++ b/gs/base/lib.mak
@@ -1212,7 +1212,7 @@ $(GLOBJ)gdevemap.$(OBJ) : $(GLSRC)gdevemap.c $(AK) $(std_h) $(MAKEDIRS)
# ----------- Downsampling routines ------------ #
gxdownscale_h=$(GLSRC)gxdownscale.h $(gsmemory_h) $(gxdevcli_h) $(ctype__h) \
- $(gstypes_h)
+ $(gstypes_h) $(gxgetbit_h)
downscale_=$(GLOBJ)gxdownscale.$(OBJ)
$(GLOBJ)gxdownscale.$(OBJ) : $(GLSRC)gxdownscale.c $(AK) \
diff --git a/gs/doc/Devices.htm b/gs/doc/Devices.htm
index ebab696d2..a6a915373 100644
--- a/gs/doc/Devices.htm
+++ b/gs/doc/Devices.htm
@@ -458,6 +458,17 @@ It is possible to create an overall CMYK composite for more than 4 colorants
by then adding together (via an external application like imagemagick)
the composite CMYK output files from the individual Ghostscript passes.
+<p>The <code>tiffsep</code> device accepts a -dBitsPerComponent=
+option, which may be set to 8 (the default) or 1. In 1bpp mode, the
+device renders each component internally in 8 bits, but then converts
+down to 1bpp with error diffusion before output as described below in
+the <code>tiffscaled</code> device. No composite file is produced in
+1bpp mode, only individual separations.
+
+<p>The device also accepts the -dDownScaleFactor= and -dMinFeatureSize=
+parameters as described below in the tiffscaled device, but
+MinFeatureSize is only honoured in 1bpp mode.
+
<a name="tiffsep1"></a><dt><code>tiffsep1</code>
<dd>
The tiffsep1 device creates multiple output files, one for each component