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