xref: /haiku/src/add-ons/print/drivers/pcl6/PCL6Rasterizer.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
1 /*
2 ** PCL6Rasterizer.cpp
3 ** Copyright 2005, Michael Pfeiffer, laplace@users.sourceforge.net.
4 ** All rights reserved.
5 ** Distributed under the terms of the MIT License.
6 */
7 
8 
9 #include "PCL6Rasterizer.h"
10 
11 #include <stdio.h>
12 
13 #ifdef _PCL6_RASTERIZER_TEST_
14 
15 static void dump(uchar* buffer, int size);
16 static void dump_bits(uchar* buffer, int size);
17 
18 #define DUMP(text, buffer, size) { fprintf text; dump(buffer, size); }
19 #define DUMP_BITS(text, buffer, size) { fprintf text; dump_bits(buffer, size); }
20 
21 #else
22 
23 #define DUMP(text, buffer, size) {}
24 #define DUMP_BITS(text, buffer, size) {}
25 
26 #endif
27 
28 
29 // #pragma - MonochromeRasterizer
30 
31 
32 MonochromeRasterizer::MonochromeRasterizer(Halftone* halftone)
33 	:
34 	PCL6Rasterizer(halftone),
35 	fOutBuffer(NULL)
36 {}
37 
38 
39 void
40 MonochromeRasterizer::InitializeBuffer()
41 {
42 	fWidthByte = RowBufferSize(GetWidth(), 1, 1);
43 	// line length is a multiple of 4 bytes
44 	fOutRowSize = RowBufferSize(GetWidth(), 1, 4);
45 	fPadBytes = fOutRowSize - fWidthByte;
46 	// Total size
47 	SetOutBufferSize(fOutRowSize * GetHeight());
48 	PCL6Rasterizer::InitializeBuffer();
49 	fCurrentLine = GetOutBuffer();
50 }
51 
52 
53 const void*
54 MonochromeRasterizer::RasterizeLine(int x, int y,
55 	const ColorRGB32Little* source)
56 {
57 	GetHalftone()->Dither(fCurrentLine, (const uchar*)source, x, y, GetWidth());
58 
59 	uchar* out = fCurrentLine;
60 
61 	// invert pixels
62 	for (int w = fWidthByte; w > 0; w --, out ++)
63 		*out = ~*out;
64 
65 	// pad with zeros
66 	for (int w = fPadBytes; w > 0; w --, out ++)
67 		*out = 0;
68 
69 	void* result = fCurrentLine;
70 	fCurrentLine += fOutRowSize;
71 	return result;
72 }
73 
74 
75 // #pragma - ColorRGBRasterizer
76 
77 
78 ColorRGBRasterizer::ColorRGBRasterizer(Halftone* halftone)
79 	:
80 	PCL6Rasterizer(halftone)
81 {}
82 
83 
84 void
85 ColorRGBRasterizer::InitializeBuffer() {
86 	fWidthByte = RowBufferSize(GetWidth(), 24, 1);
87 	// line length is a multiple of 4 bytes
88 	fOutRowSize = RowBufferSize(GetWidth(), 24, 4);
89 	fPadBytes = fOutRowSize - fWidthByte;
90 	// Total size
91 	SetOutBufferSize(fOutRowSize * GetHeight());
92 	PCL6Rasterizer::InitializeBuffer();
93 	fCurrentLine = GetOutBuffer();
94 }
95 
96 
97 const void*
98 ColorRGBRasterizer::RasterizeLine(int x, int y,
99 	const ColorRGB32Little* source)
100 {
101 	uchar* out = fCurrentLine;
102 	int width = GetWidth();
103 	for (int w = width; w > 0; w --) {
104 		*out++ = source->red;
105 		*out++ = source->green;
106 		*out++ = source->blue;
107 		source ++;
108 	}
109 
110 	// pad with 0s
111 	for (int w = fPadBytes; w > 0; w --, out ++)
112 		*out = 0;
113 
114 	void* result = fCurrentLine;
115 	fCurrentLine += fOutRowSize;
116 	return result;
117 }
118 
119 
120 // #pragma - ColorRasterizer
121 
122 
123 ColorRasterizer::ColorRasterizer::ColorRasterizer(Halftone* halftone)
124 	:
125 	PCL6Rasterizer(halftone)
126 {
127 	for (int plane = 0; plane < 3; plane ++)
128 		fPlaneBuffers[plane] = NULL;
129 
130 	halftone->SetPlanes(Halftone::kPlaneRGB1);
131 	halftone->SetBlackValue(Halftone::kLowValueMeansBlack);
132 }
133 
134 
135 ColorRasterizer::~ColorRasterizer() {
136 	for (int plane = 0; plane < 3; plane ++) {
137 		delete fPlaneBuffers[plane];
138 		fPlaneBuffers[plane] = NULL;
139 	}
140 }
141 
142 
143 void
144 ColorRasterizer::InitializeBuffer() {
145 	fWidthByte = RowBufferSize(GetWidth(), 3, 1);
146 	// line length is a multiple of 4 bytes
147 	fOutRowSize = RowBufferSize(GetWidth(), 3, 4);
148 	fPadBytes = fOutRowSize - fWidthByte;
149 	// Total size
150 	SetOutBufferSize(fOutRowSize * GetHeight());
151 	PCL6Rasterizer::InitializeBuffer();
152 	fCurrentLine = GetOutBuffer();
153 
154 	fPlaneBufferSize = RowBufferSize(GetWidth(), 1, 1);
155 	for (int plane = 0; plane < 3; plane ++) {
156 		fPlaneBuffers[plane] = new uchar[fPlaneBufferSize];
157 	}
158 }
159 
160 
161 enum {
162 	kRed = 1,
163 	kGreen = 2,
164 	kBlue = 4,
165 };
166 
167 
168 const void*
169 ColorRasterizer::RasterizeLine(int x, int y, const ColorRGB32Little* source)
170 {
171 	DUMP((stderr, "\nRGB32 row at x %d y %d:\n", x, y), (uchar*)source,
172 		GetWidth() * 4);
173 
174 	// dither each color component
175 	for (int plane = 0; plane < 3; plane ++)
176 		GetHalftone()->Dither(fPlaneBuffers[plane], (const uchar*)source, x, y,
177 			GetWidth());
178 
179 	DUMP_BITS((stderr, "red   "), fPlaneBuffers[0], fPlaneBufferSize);
180 	DUMP_BITS((stderr, "green "), fPlaneBuffers[1], fPlaneBufferSize);
181 	DUMP_BITS((stderr, "blue  "), fPlaneBuffers[2], fPlaneBufferSize);
182 
183 	MergePlaneBuffersToCurrentLine();
184 
185 	DUMP_BITS((stderr, "merged\n"), fCurrentLine, fOutRowSize);
186 	DUMP((stderr, "\n"), fCurrentLine, fOutRowSize);
187 
188 	void* result = fCurrentLine;
189 	fCurrentLine += fOutRowSize;
190 	return result;
191 }
192 
193 
194 void
195 ColorRasterizer::MergePlaneBuffersToCurrentLine()
196 {
197 	// merge the three planes into output buffer
198 	int remainingPixels = GetWidth();
199 	uchar* out = fCurrentLine;
200 	uchar value = 0;
201 	uchar outMask = 0x80; // current bit mask (1 << (8 - bit)) in output buffer
202 
203 	// iterate over the three plane buffers
204 	for (int i = 0; i < fPlaneBufferSize; i ++) {
205 		int pixels = 8;
206 		if (remainingPixels < 8)
207 			pixels = remainingPixels;
208 
209 		remainingPixels -= pixels;
210 
211 		if (remainingPixels >= 8) {
212 			const uchar
213 				red = fPlaneBuffers[0][i],
214 				green = fPlaneBuffers[1][i],
215 				blue = fPlaneBuffers[2][i];
216 
217 			uchar value = 0;
218 			if (red & 0x80) value =  0x80;
219 			if (red & 0x40) value |=  0x10;
220 			if (red & 0x20) value |=  0x02;
221 
222 			if (green & 0x80) value |= 0x40;
223 			if (green & 0x40) value |= 0x08;
224 			if (green & 0x20) value |= 0x01;
225 
226 			if (blue & 0x80) value |= 0x20;
227 			if (blue & 0x40) value |= 0x04;
228 
229 			*out++ = value;
230 
231 			value = 0;
232 			if (blue & 0x20) value =  0x80;
233 			if (blue & 0x10) value |=  0x10;
234 			if (blue & 0x08) value |=  0x02;
235 
236 			if (red & 0x10) value |= 0x40;
237 			if (red & 0x08) value |= 0x08;
238 			if (red & 0x04) value |= 0x01;
239 
240 			if (green & 0x10) value |= 0x20;
241 			if (green & 0x08) value |= 0x04;
242 			*out++ = value;
243 
244 			value = 0;
245 			if (green & 0x04) value =  0x80;
246 			if (green & 0x02) value |=  0x10;
247 			if (green & 0x01) value |=  0x02;
248 
249 			if (blue & 0x04) value |= 0x40;
250 			if (blue & 0x02) value |= 0x08;
251 			if (blue & 0x01) value |= 0x01;
252 
253 			if (red & 0x02) value |= 0x20;
254 			if (red & 0x01) value |= 0x04;
255 			*out++ = value;
256 
257 		} else {
258 			const uchar
259 				red = fPlaneBuffers[0][i],
260 				green = fPlaneBuffers[1][i],
261 				blue = fPlaneBuffers[2][i];
262 			// for each bit in the current byte of each plane
263 			uchar mask = 0x80;
264 			for (; pixels > 0; pixels --) {
265 				int rgb = 0;
266 
267 				if (red & mask)
268 					rgb |= kRed;
269 				if (green & mask)
270 					rgb |= kGreen;
271 				if (blue & mask)
272 					rgb |= kBlue;
273 
274 				for (int plane = 0; plane < 3; plane ++) {
275 					// copy pixel value to output value
276 					if (rgb & (1 << plane))
277 						value |= outMask;
278 
279 					// increment output mask
280 					if (outMask == 0x01) {
281 						outMask = 0x80;
282 						// write output value to output buffer
283 						*out = value;
284 						out ++;
285 						value = 0;
286 					} else
287 						outMask >>= 1;
288 				}
289 				mask >>= 1;
290 			}
291 		}
292 	}
293 
294 	// write last output value
295 	if (outMask != 0x80) {
296 		do {
297 			value |= outMask;
298 			outMask >>= 1;
299 		} while (outMask > 0);
300 
301 		*out = value;
302 		out ++;
303 	}
304 
305 	if (out - fCurrentLine != fWidthByte)
306 		fprintf(stderr, "Error buffer overflow: %d != %d\n", fWidthByte,
307 			static_cast<int>(out - fCurrentLine));
308 
309 	// pad with zeros
310 	for (int w = fPadBytes; w > 0; w --, out ++)
311 		*out = 0xff;
312 
313 	if (out - fCurrentLine != fOutRowSize)
314 		fprintf(stderr, "Error buffer overflow: %d != %d\n", fOutRowSize,
315 			static_cast<int>(out - fCurrentLine));
316 }
317 
318 
319 #ifdef _PCL6_RASTERIZER_TEST_
320 #include <Application.h>
321 #include <Bitmap.h>
322 #include <stdio.h>
323 
324 #define COLUMNS 40
325 #define BIT_COLUMNS 6
326 
327 
328 static void
329 dump(uchar* buffer, int size)
330 {
331 	int x = 0;
332 	for (int i = 0; i < size; i ++) {
333 		if ((x % COLUMNS) == COLUMNS - 1) {
334 			fprintf(stderr, "\n");
335 		} else if (i > 0) {
336 			fprintf(stderr, " ");
337 		}
338 
339 		fprintf(stderr, "%2.2x", (int)*buffer);
340 		buffer ++;
341 
342 		x ++;
343 	}
344 
345 	fprintf(stderr, "\n");
346 }
347 
348 
349 static void
350 dump_bits(uchar* buffer, int size)
351 {
352 	int x = 0;
353 	for (int i = 0; i < size; i ++) {
354 		if ((x % COLUMNS) == COLUMNS - 1) {
355 			fprintf(stderr, "\n");
356 		} else if (i > 0) {
357 			fprintf(stderr, " ");
358 		}
359 
360 		uchar value = *buffer;
361 		for (int bit = 0; bit < 8; bit ++) {
362 			if (value & (1 << bit)) {
363 				fprintf(stderr, "*");
364 			} else {
365 				fprintf(stderr, ".");
366 			}
367 		}
368 		buffer ++;
369 
370 		x ++;
371 	}
372 
373 	fprintf(stderr, "\n");
374 }
375 
376 
377 static void
378 fill(uchar* _row, int width, ColorRGB32Little color)
379 {
380 	ColorRGB32Little* row = static_cast<ColorRGB32Little*>(_row);
381 	for (int i = 0; i < width; i ++) {
382 		*row = color;
383 		row ++;
384 	}
385 }
386 
387 
388 static void
389 initializeBitmap(BBitmap* bitmap, int width, int height)
390 {
391 	int bpr = bitmap->BytesPerRow();
392 	uchar* row = (uchar*)bitmap->Bits();
393 	// BGRA
394 	ColorRGB32Little black = {0, 0, 0, 0};
395 	ColorRGB32Little white = {255, 255, 255, 0};
396 	ColorRGB32Little red = {0, 0, 255, 0};
397 	ColorRGB32Little green = {0, 255, 0, 0};
398 	ColorRGB32Little blue = {255, 0, 0, 0};
399 
400 	fprintf(stderr, "black row\n");
401 	fill(row, width, black);
402 	row += bpr;
403 
404 	fprintf(stderr, "white row\n");
405 	fill(row, width, white);
406 	row += bpr;
407 
408 	fprintf(stderr, "red row\n");
409 	fill(row, width, red);
410 	row += bpr;
411 
412 	fprintf(stderr, "red green blue pattern");
413 	ColorRGB32Little* color = (ColorRGB32Little*)row;
414 	for (int i = 0; i < width; i++) {
415 		switch (i % 3) {
416 			case 0:
417 				*color = red;
418 				break;
419 			case 1:
420 				*color = green;
421 				break;
422 			case 2:
423 				*color = blue;
424 				break;
425 		}
426 		color ++;
427 	}
428 }
429 
430 
431 int
432 main()
433 {
434 	const int width = 10;
435 	const int height = 4;
436 
437 	fprintf(stderr, "width:  %d\nheight: %d\n", width, height);
438 	BApplication app("application/pcl6-rasterizer-test");
439 #if 1
440 	Halftone halftone(B_RGB32, 0.25f, 0.0f, Halftone::kType1);
441 #else
442 	Halftone halftone(B_RGB32, 0.25f, 0.0f, Halftone::kTypeFloydSteinberg);
443 #endif
444 	ColorRasterizer rasterizer(&halftone);
445 	BBitmap bitmap(BRect(0, 0, width - 1, height - 1), B_RGB32);
446 
447 	initializeBitmap(&bitmap, width, height);
448 
449 	rasterizer.SetBitmap(0, 0, &bitmap, height);
450 	rasterizer.InitializeBuffer();
451 	while (rasterizer.HasNextLine()) {
452 		rasterizer.RasterizeNextLine();
453 	}
454 }
455 
456 #endif // _PCL6_RASTERIZER_TEST_
457