diff --git a/headers/private/print/libprint/Halftone.h b/headers/private/print/libprint/Halftone.h index a3c71e3720..b52cace62b 100644 --- a/headers/private/print/libprint/Halftone.h +++ b/headers/private/print/libprint/Halftone.h @@ -51,16 +51,21 @@ public: kPlaneMonochrome1, // 1 bit depth (0 white, 1 black) kPlaneRGB1, // 3 planes, 1 bit depth (0 black, 7 white) }; + enum BlackValue { + kHighValueMeansBlack, + kLowValueMeansBlack, + }; Halftone(color_space cs, double gamma = 1.4, DitherType dither_type = kTypeFloydSteinberg); ~Halftone(); void setPlanes(Planes planes); + void setBlackValue(BlackValue blackValue); int dither(uchar *dst, const uchar *src, int x, int y, int width); int getPixelDepth() const; - const rgb_color *getPalette() const; const uchar *getPattern() const; void setPattern(const uchar *pattern); protected: + // PFN_gray: return value of 0 means low density (or black) and value of 255 means high density (or white) PFN_gray getGrayFunction() const; void setGrayFunction(PFN_gray gray); void setGrayFunction(GrayFunction grayFunction); @@ -68,6 +73,7 @@ protected: void createGammaTable(double gamma); void initElements(int x, int y, uchar *elements); uint getDensity(ColorRGB32 c) const; + uchar convertUsingBlackValue(uchar byte) const; int ditherRGB32(uchar *dst, const uchar *src, int x, int y, int width); void initFloydSteinberg(); @@ -88,6 +94,7 @@ private: PFN_gray fGray; int fPixelDepth; Planes fPlanes; + BlackValue fBlackValue; const uchar *fPattern; uint fGammaTable[kGammaTableSize]; int fNumberOfPlanes; @@ -128,4 +135,14 @@ inline uint Halftone::getDensity(ColorRGB32 c) const return fGammaTable[fGray(c)]; } +inline uchar Halftone::convertUsingBlackValue(uchar byte) const +{ + // bits with value = '1' in byte mean black + if (fBlackValue == kHighValueMeansBlack) { + return byte; + } else { + return ~byte; + } +} + #endif /* __HALFTONE_H */ diff --git a/src/add-ons/print/drivers/pcl5/PCL5.cpp b/src/add-ons/print/drivers/pcl5/PCL5.cpp index 75d57c6dba..f8d6dc617c 100644 --- a/src/add-ons/print/drivers/pcl5/PCL5.cpp +++ b/src/add-ons/print/drivers/pcl5/PCL5.cpp @@ -146,12 +146,10 @@ bool PCL5Driver::nextBand(BBitmap *bitmap, BPoint *offset) const bool color = getJobData()->getColor() == JobData::kColor; const int num_planes = color ? 3 : 1; - const int fill_bits = in_size * 8 - width; - const uchar fill_mask = 0xff >> (8 - fill_bits); - // ASSERT(0 <= fill_bits && fill_bits < 8); if (color) { fHalftone->setPlanes(Halftone::kPlaneRGB1); + fHalftone->setBlackValue(Halftone::kLowValueMeansBlack); } for (int i = rc.top; i <= rc.bottom; i++) { @@ -159,13 +157,7 @@ bool PCL5Driver::nextBand(BBitmap *bitmap, BPoint *offset) for (int plane = 0; plane < num_planes; plane ++) { fHalftone->dither(in_buffer, ptr, x, y, width); - - if (color) { - // in color mode a value of 1 in all three planes means white - // fill the remaining bits to the bytes boundary with 1s - in_buffer[in_size - 1] |= fill_mask; - } - + compressed_size = pack_bits(out_buffer, in_buffer, in_size); if (compressed_size + bytesToEnterCompressionMethod(2) < in_size + bytesToEnterCompressionMethod(0)) { diff --git a/src/add-ons/print/drivers/shared/libprint/Halftone.cpp b/src/add-ons/print/drivers/shared/libprint/Halftone.cpp index ce0568e3af..03bafa048f 100644 --- a/src/add-ons/print/drivers/shared/libprint/Halftone.cpp +++ b/src/add-ons/print/drivers/shared/libprint/Halftone.cpp @@ -22,9 +22,9 @@ using namespace std; static uint gray(ColorRGB32 c) { if (c.little.red == c.little.green && c.little.red == c.little.blue) { - return 255 - c.little.red; + return c.little.red; } else { - return 255 - (c.little.red * 3 + c.little.green * 6 + c.little.blue) / 10; + return (c.little.red * 3 + c.little.green * 6 + c.little.blue) / 10; } } @@ -48,6 +48,7 @@ Halftone::Halftone(color_space cs, double gamma, DitherType dither_type) fPixelDepth = color_space2pixel_depth(cs); fGray = gray; setPlanes(kPlaneMonochrome1); + setBlackValue(kHighValueMeansBlack); initFloydSteinberg(); @@ -99,6 +100,11 @@ void Halftone::setPlanes(Planes planes) fCurrentPlane = 0; } +void Halftone::setBlackValue(BlackValue blackValue) +{ + fBlackValue = blackValue; +} + void Halftone::createGammaTable(double gamma) { // gamma = 1.0f / gamma; @@ -196,7 +202,7 @@ int Halftone::ditherRGB32( remainder = 8; ColorRGB32 c; - uchar cur; + uchar cur; // cleared bit means white, set bit means black uint density; int i, j; uchar *e = elements; @@ -217,11 +223,11 @@ int Halftone::ditherRGB32( density = getDensity(c); } src++; - if (density > *e++) { + if (density <= *e++) { cur |= (0x80 >> j); } } - *dst++ = cur; + *dst++ = convertUsingBlackValue(cur); } } if (remainder > 0) { @@ -235,11 +241,11 @@ int Halftone::ditherRGB32( density = getDensity(c); } src++; - if (density > *e++) { + if (density <= *e++) { cur |= (0x80 >> j); } } - *dst++ = cur; + *dst++ = convertUsingBlackValue(cur); } return widthByte; @@ -291,22 +297,16 @@ int Halftone::ditherFloydSteinberg(uchar *dst, const uchar* a_src, int x, int y, int* error_table = &fErrorTables[fCurrentPlane][1]; int current_error = 0, error; const ColorRGB32 *src = (const ColorRGB32 *)a_src; + uchar cur = 0; // cleared bit means white, set bit means black for (int x = 0; x < width; x ++, src ++) { - const int bit = 7 - x % 8; - if (bit == 7) { - // clear byte if at first pixel in byte - *dst = 0; - } - - int density = getDensity(*src) + current_error / 16; + const int bit = 7 - x % 8; + const int density = getDensity(*src) + current_error / 16; if (density < 128) { - // white pixel error = density; + cur |= (1 << bit); } else { - // black pixel error = density - 255; - *dst |= (1 << bit); } // distribute error @@ -321,9 +321,16 @@ int Halftone::ditherFloydSteinberg(uchar *dst, const uchar* a_src, int x, int y, *left += 3 * error; if (bit == 0) { + *dst = convertUsingBlackValue(cur); // advance to next byte dst ++; + cur = 0; } } + + const bool hasRest = (width % 8) != 0; + if (hasRest) { + *dst = convertUsingBlackValue(cur); + } }