3 * Copyright 1999-2000 Y.Takagi. All Rights Reserved.
7 #include <InterfaceDefs.h>
12 #include "ValidRect.h"
25 if (c
.little
.red
== c
.little
.green
&& c
.little
.red
== c
.little
.blue
)
27 return (c
.little
.red
* 3 + c
.little
.green
* 6 + c
.little
.blue
) / 10;
32 GetRedValue(ColorRGB32 c
)
39 GetGreenValue(ColorRGB32 c
)
41 return c
.little
.green
;
46 GetBlueValue(ColorRGB32 c
)
52 Halftone::Halftone(color_space colorSpace
, double gamma
, double min
,
53 DitherType ditherType
)
55 fPixelDepth
= color_space2pixel_depth(colorSpace
);
57 SetPlanes(kPlaneMonochrome1
);
58 SetBlackValue(kHighValueMeansBlack
);
62 CreateGammaTable(gamma
, min
);
64 if (ditherType
== kTypeFloydSteinberg
) {
65 fDither
= &Halftone::DitherFloydSteinberg
;
71 fPattern
= pattern16x16_type2
;
74 fPattern
= pattern16x16_type3
;
77 fPattern
= pattern16x16_type1
;
84 fDither
= &Halftone::DitherRGB32
;
95 UninitFloydSteinberg();
100 Halftone::SetPlanes(Planes planes
)
103 if (planes
== kPlaneMonochrome1
) {
107 ASSERT(planes
== kPlaneRGB1
);
115 Halftone::SetBlackValue(BlackValue blackValue
)
117 fBlackValue
= blackValue
;
122 Halftone::CreateGammaTable(double gamma
, double min
)
124 const double kScalingFactor
= 255.0 - min
;
125 for (int i
= 0; i
< kGammaTableSize
; i
++) {
126 const double kGammaCorrectedValue
= pow((double)i
/ 255.0, gamma
);
127 const double kTranslatedValue
= min
+ kGammaCorrectedValue
* kScalingFactor
;
128 fGammaTable
[i
] = (uint
)(kTranslatedValue
);
134 Halftone::InitElements(int x
, int y
, uchar
* elements
)
139 const uchar
*left
= &fPattern
[y
* 16];
140 const uchar
*pos
= left
+ x
;
141 const uchar
*right
= left
+ 0x0F;
143 for (int i
= 0; i
< 16; i
++) {
154 Halftone::Dither(uchar
* destination
, const uchar
* source
, int x
, int y
,
157 if (fPlanes
== kPlaneRGB1
) {
158 switch (fCurrentPlane
) {
160 SetGrayFunction(kRedChannel
);
163 SetGrayFunction(kGreenChannel
);
166 SetGrayFunction(kBlueChannel
);
170 ASSERT(fGray
== &ToGray
);
173 (this->*fDither
)(destination
, source
, x
, y
, width
);
177 if (fCurrentPlane
>= fNumberOfPlanes
)
183 Halftone::SetGrayFunction(GrayFunction grayFunction
)
185 PFN_gray function
= NULL
;
186 switch (grayFunction
) {
187 case kMixToGray
: function
= ToGray
;
189 case kRedChannel
: function
= GetRedValue
;
191 case kGreenChannel
: function
= GetGreenValue
;
193 case kBlueChannel
: function
= GetBlueValue
;
196 SetGrayFunction(function
);
201 Halftone::DitherRGB32(uchar
*destination
, const uchar
*source0
, int x
, int y
,
205 InitElements(x
, y
, elements
);
207 const ColorRGB32
* source
= reinterpret_cast<const ColorRGB32
*>(source0
);
209 int widthByte
= (width
+ 7) / 8;
210 int remainder
= width
% 8;
215 uchar cur
; // cleared bit means white, set bit means black
219 uchar
*last_e
= elements
+ 16;
222 density
= GetDensity(c
);
225 for (i
= 0; i
< widthByte
- 1; i
++) {
230 for (j
= 0; j
< 8; j
++) {
231 if (c
.little
.red
!= source
->little
.red
232 || c
.little
.green
!= source
->little
.green
233 || c
.little
.blue
!= source
->little
.blue
) {
235 density
= GetDensity(c
);
238 if (density
<= *e
++) {
242 *destination
++ = ConvertUsingBlackValue(cur
);
251 for (j
= 0; j
< remainder
; j
++) {
252 if (c
.little
.red
!= source
->little
.red
253 || c
.little
.green
!= source
->little
.green
254 || c
.little
.blue
!= source
->little
.blue
) {
256 density
= GetDensity(c
);
259 if (density
<= *e
++) {
263 *destination
++ = ConvertUsingBlackValue(cur
);
268 // Floyd-Steinberg dithering
270 Halftone::InitFloydSteinberg()
272 for (int i
= 0; i
< kMaxNumberOfPlanes
; i
++)
273 fErrorTables
[i
] = NULL
;
278 Halftone::DeleteErrorTables()
280 for (int i
= 0; i
< kMaxNumberOfPlanes
; i
++) {
281 delete fErrorTables
[i
];
282 fErrorTables
[i
] = NULL
;
288 Halftone::UninitFloydSteinberg()
295 Halftone::SetupErrorBuffer(int x
, int y
, int width
)
301 for (int i
= 0; i
< fNumberOfPlanes
; i
++) {
302 // reserve also space for sentinals at both ends of error table
303 const int size
= width
+ 2;
304 fErrorTables
[i
] = new int[size
];
305 memset(fErrorTables
[i
], 0, sizeof(int) * size
);
311 Halftone::DitherFloydSteinberg(uchar
*destination
, const uchar
* source0
,
312 int x
, int y
, int width
)
314 if (fErrorTables
[fCurrentPlane
] == NULL
|| fX
!= x
315 || (fCurrentPlane
== 0 && fY
!= y
- 1)
316 || (fCurrentPlane
> 0 && fY
!= y
)
318 SetupErrorBuffer(x
, y
, width
);
322 int* errorTable
= &fErrorTables
[fCurrentPlane
][1];
323 int current_error
= errorTable
[0];
327 const ColorRGB32
*source
= reinterpret_cast<const ColorRGB32
*>(source0
);
328 uchar cur
= 0; // cleared bit means white, set bit means black
329 for (int x
= 0; x
< width
; x
++, source
++) {
330 const int bit
= 7 - x
% 8;
331 const int density
= GetDensity(*source
) + current_error
/ 16;
337 error
= density
- 255;
340 // distribute error using this pattern:
341 // 0 X 7 (current_error)
342 // (left) 3 5 1 (right)
344 int* right
= &errorTable
[x
+1];
345 current_error
= (*right
) + 7 * error
;
348 int* middle
= right
- 1;
349 *middle
+= 5 * error
;
351 int* left
= middle
- 1;
355 *destination
= ConvertUsingBlackValue(cur
);
356 // advance to next byte
362 const bool hasRest
= (width
% 8) != 0;
364 *destination
= ConvertUsingBlackValue(cur
);