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
15static void dump(uchar* buffer, int size);
16static 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
32MonochromeRasterizer::MonochromeRasterizer(Halftone* halftone)
33	:
34	PCL6Rasterizer(halftone),
35	fOutBuffer(NULL)
36{}
37
38
39void
40MonochromeRasterizer::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
53const void*
54MonochromeRasterizer::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
78ColorRGBRasterizer::ColorRGBRasterizer(Halftone* halftone)
79	:
80	PCL6Rasterizer(halftone)
81{}
82
83
84void
85ColorRGBRasterizer::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
97const void*
98ColorRGBRasterizer::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
123ColorRasterizer::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
135ColorRasterizer::~ColorRasterizer() {
136	for (int plane = 0; plane < 3; plane ++) {
137		delete fPlaneBuffers[plane];
138		fPlaneBuffers[plane] = NULL;
139	}
140}
141
142
143void
144ColorRasterizer::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
161enum {
162	kRed = 1,
163	kGreen = 2,
164	kBlue = 4,
165};
166
167
168const void*
169ColorRasterizer::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
194void
195ColorRasterizer::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
328static void
329dump(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
349static void
350dump_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
377static void
378fill(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
388static void
389initializeBitmap(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
431int
432main()
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