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