@@ -49,9 +49,51 @@ typedef enum cups_halftone_type_e
4949 HALFTONE_DEFAULT ,
5050 HALFTONE_STOCHASTIC ,
5151 HALFTONE_FOO2ZJS ,
52- HALFTONE_BI_LEVEL
52+ HALFTONE_BI_LEVEL ,
53+ HALFTONE_DITHERING ,
54+ HALFTONE_GENORDERED ,
55+ HALFTONE_SPOT
5356} cups_halftone_type_t ;
5457
58+ static const char * ht_spot_functions [] =
59+ {
60+ "{dup mul exch dup mul add 1 exch sub}" , /* 0 SimpleDot */
61+ "{dup mul exch dup mul add 1 sub}" , /* 1 InvertedSimpleDot */
62+ "{360 mul sin 2 div exch 360 mul sin 2 div add}" ,/* 2 DoubleDot */
63+ "{360 mul sin 2 div exch 360 mul sin 2 div add neg}" ,/* 3 InvertedDoubleDot */
64+ "{180 mul cos exch 180 mul cos add 2 div}" , /* 4 CosineDot */
65+ "{360 mul sin 2 div exch 2 div 360 mul sin 2 div add}" , /* 5 Double */
66+ "{360 mul sin 2 div exch 2 div 360 mul sin 2 div add neg}" ,/* 6 InvertedDouble */
67+ "{exch pop abs neg}" , /* 7 Line */
68+ "{pop}" , /* 8 LineX */
69+ "{exch pop}" , /* 9 LineY */
70+ "{abs exch abs 2 copy add 1.0 le"
71+ " {dup mul exch dup mul add 1 exch sub}"
72+ " {1 sub dup mul exch 1 sub dup mul add 1 sub}"
73+ " ifelse}" , /* 10 Round */
74+ "{abs exch abs 2 copy 3 mul exch 4 mul add 3 sub dup 0 lt"
75+ " {pop dup mul exch 0.75 div dup mul add 4 div 1 exch sub}"
76+ " {dup 1 gt"
77+ " {pop 1 exch sub dup mul exch 1 exch sub 0.75 div dup mul add 4 div 1 sub}"
78+ " {0.5 exch sub exch pop exch pop}}"
79+ " ifelse}ifelse}" , /* 11 Ellipse */
80+ "{dup mul 0.9 mul exch dup mul add 1 exch sub}" , /* 12 EllipseA */
81+ "{dup mul 0.9 mul exch dup mul add 1 sub}" , /* 13 InvertedEllipseA */
82+ "{dup 5 mul 8 div mul exch dup mul exch add sqrt 1 exch sub}" , /* 14 EllipseB */
83+ "{dup mul exch dup mul 0.9 mul add 1 exch sub}" , /* 15 EllipseC */
84+ "{dup mul exch dup mul 0.9 mul add 1 sub}" , /* 16 InvertedEllipseC */
85+ "{abs exch abs 2 copy lt {exch} if pop neg}" , /* 17 Square */
86+ "{abs exch abs 2 copy gt {exch} if pop neg}" , /* 18 Cross */
87+ "{abs exch abs 0.9 mul add 2 div}" , /* 19 Rhomboid */
88+ "{abs exch abs 2 copy add 0.75 le"
89+ " {dup mul exch dup mul add 1 exch sub}"
90+ " {2 copy add 1.23 le"
91+ " {0.85 mul add 1 exch sub}"
92+ " {1 sub dup mul exch 1 sub dup mul add 1 sub}"
93+ " ifelse} ifelse}" /* 20 Diamond */
94+ };
95+ #define HT_SPOT_FUNCTIONS_COUNT ((int)(sizeof(ht_spot_functions)/sizeof(ht_spot_functions[0])))
96+
5597static gs_doc_t
5698parse_doc_type (FILE * fp )
5799{
@@ -825,6 +867,7 @@ cfFilterGhostscript(int inputfd, // I - File descriptor input
825867 cf_cm_calibration_t cm_calibrate ;
826868 int pxlcolor = 0 ; // 1 if printer is color printer otherwise 0.
827869 cups_halftone_type_t halftonetype = HALFTONE_DEFAULT ;
870+ int ht_frequency = 133 , ht_angle = 45 , ht_dotshape = 0 ;
828871 ipp_attribute_t * ipp_attr ;
829872 cf_logfunc_t log = data -> logfunc ;
830873 void * ld = data -> logdata ;
@@ -1636,6 +1679,58 @@ cfFilterGhostscript(int inputfd, // I - File descriptor input
16361679 halftonetype = HALFTONE_FOO2ZJS ;
16371680 else if (!strcasecmp (t , "bi-level" ))
16381681 halftonetype = HALFTONE_BI_LEVEL ;
1682+ else if (!strcasecmp (t , "dithering" ))
1683+ halftonetype = HALFTONE_DITHERING ;
1684+ else if (!strncasecmp (t , "genordered" , 10 ) &&
1685+ (t [10 ] == '-' || t [10 ] == '\0' ))
1686+ {
1687+ halftonetype = HALFTONE_GENORDERED ;
1688+ if (t [10 ] == '-' )
1689+ {
1690+ const char * p = t + 11 ;
1691+ char * endp ;
1692+ long v ;
1693+ v = strtol (p , & endp , 10 );
1694+ if (endp != p ) { ht_frequency = (int )v ; p = endp ; }
1695+ if (* p == '-' )
1696+ {
1697+ p ++ ;
1698+ v = strtol (p , & endp , 10 );
1699+ if (endp != p ) { ht_angle = (int )v ; p = endp ; }
1700+ if (* p == '-' )
1701+ {
1702+ p ++ ;
1703+ v = strtol (p , & endp , 10 );
1704+ if (endp != p ) ht_dotshape = (int )v ;
1705+ }
1706+ }
1707+ }
1708+ }
1709+ else if (!strncasecmp (t , "spot" , 4 ) &&
1710+ (t [4 ] == '-' || t [4 ] == '\0' ))
1711+ {
1712+ halftonetype = HALFTONE_SPOT ;
1713+ if (t [4 ] == '-' )
1714+ {
1715+ const char * p = t + 5 ;
1716+ char * endp ;
1717+ long v ;
1718+ v = strtol (p , & endp , 10 );
1719+ if (endp != p ) { ht_frequency = (int )v ; p = endp ; }
1720+ if (* p == '-' )
1721+ {
1722+ p ++ ;
1723+ v = strtol (p , & endp , 10 );
1724+ if (endp != p ) { ht_angle = (int )v ; p = endp ; }
1725+ if (* p == '-' )
1726+ {
1727+ p ++ ;
1728+ v = strtol (p , & endp , 10 );
1729+ if (endp != p ) ht_dotshape = (int )v ;
1730+ }
1731+ }
1732+ }
1733+ }
16391734 }
16401735
16411736 //
@@ -1771,6 +1866,65 @@ cfFilterGhostscript(int inputfd, // I - File descriptor input
17711866 cupsArrayAdd (gs_args , strdup ("{ .5 gt { 1 } { 0 } ifelse} settransfer" ));
17721867 }
17731868
1869+ //
1870+ // Use 8x8 ordered dithering.
1871+ //
1872+ // This uses .setloresscreen Ghostscript setup function which is a part
1873+ // of dithering vs halftoning automatic selection code and is used only
1874+ // if DPI of the output device is low (< 150).
1875+ // To correctly force it, we need to call it in Install function of
1876+ // Page Device.
1877+ // DPI is auto-detected and passed for screen frequency calculation.
1878+ //
1879+ // Particularly useful for printing images on label printers (203 DPI).
1880+ //
1881+ if (halftonetype == HALFTONE_DITHERING )
1882+ {
1883+ if (log ) log (ld , CF_LOGLEVEL_DEBUG ,
1884+ "cfFilterGhostscript: Ghostscript using 8x8 ordered dithering." );
1885+ cupsArrayAdd (gs_args , strdup ("<< /Install { 72 72 matrix defaultmatrix dtransform abs exch abs .min .setloresscreen } >> setpagedevice" ));
1886+ }
1887+
1888+ //
1889+ // Ghostscript .genordered advanced ordered dithering
1890+ // PostScript HalftoneType 3 (threshold array based).
1891+ //
1892+ // This uses the .genordered operator to generate an ordered dither
1893+ // halftone screen with configurable frequency, angle and dot shape.
1894+ //
1895+ // Dot shapes:
1896+ // 0=CIRCLE, 1=REDBOOK, 2=INVERTED, 3=RHOMBOID, 4=LINE_X, 5=LINE_Y,
1897+ // 6=DIAMOND1, 7=DIAMOND2, 8=ROUNDSPOT */
1898+ //
1899+ if (halftonetype == HALFTONE_GENORDERED ) {
1900+ if (log ) log (ld , CF_LOGLEVEL_DEBUG ,
1901+ "cfFilterGhostscript: Ghostscript using .genordered halftone (frequency=%d angle=%d dotshape=%d)." ,
1902+ ht_frequency , ht_angle , ht_dotshape );
1903+ snprintf (tmpstr , sizeof (tmpstr ),
1904+ "<< /Frequency %d /Angle %d /DotShape %d >> .genordered /Default exch /Halftone defineresource sethalftone { } settransfer 0.003 setsmoothness" ,
1905+ ht_frequency , ht_angle , ht_dotshape );
1906+ cupsArrayAdd (gs_args , strdup (tmpstr ));
1907+ }
1908+
1909+ //
1910+ // PostScript HalftoneType 1 spot-function halftone algorithm.
1911+ //
1912+ // Spot functions are from PDF specification, see ht_spot_functions array.
1913+ //
1914+ if (halftonetype == HALFTONE_SPOT )
1915+ {
1916+ int shape = ht_dotshape ;
1917+ if (shape < 0 ) shape = 0 ;
1918+ if (shape >= HT_SPOT_FUNCTIONS_COUNT ) shape = HT_SPOT_FUNCTIONS_COUNT - 1 ;
1919+ if (log ) log (ld , CF_LOGLEVEL_DEBUG ,
1920+ "cfFilterGhostscript: Ghostscript using Spot halftone (frequency=%d angle=%d dotshape=%d).\n" ,
1921+ ht_frequency , ht_angle , shape );
1922+ snprintf (tmpstr , sizeof (tmpstr ),
1923+ "<< /HalftoneType 1 /Frequency %d /Angle %d /SpotFunction %s >> /Default exch /Halftone defineresource sethalftone" ,
1924+ ht_frequency , ht_angle , ht_spot_functions [shape ]);
1925+ cupsArrayAdd (gs_args , strdup (tmpstr ));
1926+ }
1927+
17741928 // Mark the end of PostScript commands supplied on the Ghostscript command
17751929 // line (with the "-c" option), so that we can supply the input file name
17761930 cupsArrayAdd (gs_args , strdup ("-f" ));
0 commit comments