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