Skip to content

Commit 2a84dee

Browse files
authored
cfFilterGhostscript(): Introduce cupsHalftoneType dithering algorithms (#92)
- Added new dithering (halftone) algorithms in addition to the default Ghostscript one - Controlled either with `halftone-type` job option or `cupsHalftoneType` PPD option - Stochastic algorithm is implemented in `stocht.ps` Ghostscript library, just include it if cupsHalftoneType is set to yes/true/on/stochastic - foo2zjs algorithm is PostScript code taken from foo2zjs-pstops (don't know the name of the algorithm) - Added bi-level threshold support, similar to pdftoraster implementation
1 parent 5d1b247 commit 2a84dee

File tree

1 file changed

+98
-0
lines changed

1 file changed

+98
-0
lines changed

cupsfilters/ghostscript.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ typedef enum gs_doc_e
4444

4545
typedef cups_page_header_t gs_page_header;
4646

47+
typedef enum cups_halftone_type_e
48+
{
49+
HALFTONE_DEFAULT,
50+
HALFTONE_STOCHASTIC,
51+
HALFTONE_FOO2ZJS,
52+
HALFTONE_BI_LEVEL
53+
} cups_halftone_type_t;
54+
4755
static gs_doc_t
4856
parse_doc_type(FILE *fp)
4957
{
@@ -816,6 +824,7 @@ cfFilterGhostscript(int inputfd, // I - File descriptor input
816824
struct sigaction sa;
817825
cf_cm_calibration_t cm_calibrate;
818826
int pxlcolor = 0; // 1 if printer is color printer otherwise 0.
827+
cups_halftone_type_t halftonetype = HALFTONE_DEFAULT;
819828
ipp_attribute_t *ipp_attr;
820829
cf_logfunc_t log = data->logfunc;
821830
void *ld = data->logdata;
@@ -1617,6 +1626,37 @@ cfFilterGhostscript(int inputfd, // I - File descriptor input
16171626
else if (!cm_disabled)
16181627
cupsArrayAdd(gs_args, strdup("-sOutputICCProfile=srgb.icc"));
16191628

1629+
if ((t = cupsGetOption("cupsHalftoneType", num_options, options)) != NULL ||
1630+
(t = cupsGetOption("halftone-type", num_options, options)) != NULL)
1631+
{
1632+
if (!strcasecmp(t, "true") || !strcasecmp(t, "on") ||
1633+
!strcasecmp(t, "yes") || !strcasecmp(t, "stochastic"))
1634+
halftonetype = HALFTONE_STOCHASTIC;
1635+
else if (!strcasecmp(t, "foo2zjs"))
1636+
halftonetype = HALFTONE_FOO2ZJS;
1637+
else if (!strcasecmp(t, "bi-level"))
1638+
halftonetype = HALFTONE_BI_LEVEL;
1639+
}
1640+
1641+
//
1642+
// For bi-level type, also check print-color-mode, the way it is
1643+
// handled by Poppler pwgtoraster/pdftoraster/pclmtoraster utilities.
1644+
//
1645+
if ((t = cupsGetOption("print-color-mode", num_options, options)) != NULL &&
1646+
!strcasecmp(t, "bi-level"))
1647+
halftonetype = HALFTONE_BI_LEVEL;
1648+
1649+
//
1650+
// Use Stochastic Halftone dithering found in GhostScript stocht.ps library file.
1651+
// It is activated automatically.
1652+
//
1653+
if (halftonetype == HALFTONE_STOCHASTIC)
1654+
{
1655+
if (log) log(ld, CF_LOGLEVEL_DEBUG,
1656+
"cfFilterGhostscript: Ghostscript using Stochastic Halftone dithering.");
1657+
cupsArrayAdd(gs_args, strdup("stocht.ps"));
1658+
}
1659+
16201660
// Switch to taking PostScript commands on the Ghostscript command line
16211661
cupsArrayAdd(gs_args, strdup("-c"));
16221662

@@ -1673,6 +1713,64 @@ cfFilterGhostscript(int inputfd, // I - File descriptor input
16731713
"cfFilterGhostscript: Ghostscript using Any-Part-of-Pixel method to "
16741714
"fill paths.");
16751715

1716+
//
1717+
// Use halftone dithering algorithm found in foo2zjs-pstops file
1718+
//
1719+
if (halftonetype == HALFTONE_FOO2ZJS)
1720+
{
1721+
if (log) log(ld, CF_LOGLEVEL_DEBUG,
1722+
"cfFilterGhostscript: Ghostscript using foo2zjs Halftone dithering.");
1723+
cupsArrayAdd(gs_args, strdup("/SpotDot { 180 mul cos exch 180 mul cos add 2 div } def\
1724+
<<\
1725+
/HalftoneType 5\
1726+
/Cyan <<\
1727+
/HalftoneType 1\
1728+
/AccurateScreens true\
1729+
/Frequency 150\
1730+
/Angle 105\
1731+
/SpotFunction /SpotDot load\
1732+
>>\
1733+
/Magenta <<\
1734+
/HalftoneType 1\
1735+
/AccurateScreens true\
1736+
/Frequency 150\
1737+
/Angle 165\
1738+
/SpotFunction /SpotDot load\
1739+
>>\
1740+
/Yellow <<\
1741+
/HalftoneType 1\
1742+
/AccurateScreens true\
1743+
/Frequency 150\
1744+
/Angle 30\
1745+
/SpotFunction /SpotDot load\
1746+
>>\
1747+
/Black <<\
1748+
/HalftoneType 1\
1749+
/AccurateScreens true\
1750+
/Frequency 150\
1751+
/Angle 45\
1752+
/SpotFunction /SpotDot load\
1753+
>>\
1754+
/Default <<\
1755+
/HalftoneType 1\
1756+
/AccurateScreens true\
1757+
/Frequency 150\
1758+
/Angle 37\
1759+
/SpotFunction /SpotDot load\
1760+
>>\
1761+
>> /Default exch /Halftone defineresource sethalftone"));
1762+
}
1763+
1764+
//
1765+
// Use simple threshold (bi-level) halftone algorithm
1766+
//
1767+
if (halftonetype == HALFTONE_BI_LEVEL)
1768+
{
1769+
if (log) log(ld, CF_LOGLEVEL_DEBUG,
1770+
"cfFilterGhostscript: Ghostscript using Bi-Level Halftone dithering.");
1771+
cupsArrayAdd(gs_args, strdup("{ .5 gt { 1 } { 0 } ifelse} settransfer"));
1772+
}
1773+
16761774
// Mark the end of PostScript commands supplied on the Ghostscript command
16771775
// line (with the "-c" option), so that we can supply the input file name
16781776
cupsArrayAdd(gs_args, strdup("-f"));

0 commit comments

Comments
 (0)