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 register const uchar 213 red = fPlaneBuffers[0][i], 214 green = fPlaneBuffers[1][i], 215 blue = fPlaneBuffers[2][i]; 216 217 register 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 register 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