Unified handling of color and monochrome dithering.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6441 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Pfeiffer
2004-01-31 08:54:26 +00:00
parent 42b671e397
commit 730329f797
3 changed files with 44 additions and 28 deletions
+18 -1
View File
@@ -51,16 +51,21 @@ public:
kPlaneMonochrome1, // 1 bit depth (0 white, 1 black) kPlaneMonochrome1, // 1 bit depth (0 white, 1 black)
kPlaneRGB1, // 3 planes, 1 bit depth (0 black, 7 white) 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(color_space cs, double gamma = 1.4, DitherType dither_type = kTypeFloydSteinberg);
~Halftone(); ~Halftone();
void setPlanes(Planes planes); void setPlanes(Planes planes);
void setBlackValue(BlackValue blackValue);
int dither(uchar *dst, const uchar *src, int x, int y, int width); int dither(uchar *dst, const uchar *src, int x, int y, int width);
int getPixelDepth() const; int getPixelDepth() const;
const rgb_color *getPalette() const;
const uchar *getPattern() const; const uchar *getPattern() const;
void setPattern(const uchar *pattern); void setPattern(const uchar *pattern);
protected: 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; PFN_gray getGrayFunction() const;
void setGrayFunction(PFN_gray gray); void setGrayFunction(PFN_gray gray);
void setGrayFunction(GrayFunction grayFunction); void setGrayFunction(GrayFunction grayFunction);
@@ -68,6 +73,7 @@ protected:
void createGammaTable(double gamma); void createGammaTable(double gamma);
void initElements(int x, int y, uchar *elements); void initElements(int x, int y, uchar *elements);
uint getDensity(ColorRGB32 c) const; uint getDensity(ColorRGB32 c) const;
uchar convertUsingBlackValue(uchar byte) const;
int ditherRGB32(uchar *dst, const uchar *src, int x, int y, int width); int ditherRGB32(uchar *dst, const uchar *src, int x, int y, int width);
void initFloydSteinberg(); void initFloydSteinberg();
@@ -88,6 +94,7 @@ private:
PFN_gray fGray; PFN_gray fGray;
int fPixelDepth; int fPixelDepth;
Planes fPlanes; Planes fPlanes;
BlackValue fBlackValue;
const uchar *fPattern; const uchar *fPattern;
uint fGammaTable[kGammaTableSize]; uint fGammaTable[kGammaTableSize];
int fNumberOfPlanes; int fNumberOfPlanes;
@@ -128,4 +135,14 @@ inline uint Halftone::getDensity(ColorRGB32 c) const
return fGammaTable[fGray(c)]; 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 */ #endif /* __HALFTONE_H */
+2 -10
View File
@@ -146,12 +146,10 @@ bool PCL5Driver::nextBand(BBitmap *bitmap, BPoint *offset)
const bool color = getJobData()->getColor() == JobData::kColor; const bool color = getJobData()->getColor() == JobData::kColor;
const int num_planes = color ? 3 : 1; 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) { if (color) {
fHalftone->setPlanes(Halftone::kPlaneRGB1); fHalftone->setPlanes(Halftone::kPlaneRGB1);
fHalftone->setBlackValue(Halftone::kLowValueMeansBlack);
} }
for (int i = rc.top; i <= rc.bottom; i++) { 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 ++) { for (int plane = 0; plane < num_planes; plane ++) {
fHalftone->dither(in_buffer, ptr, x, y, width); 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); compressed_size = pack_bits(out_buffer, in_buffer, in_size);
if (compressed_size + bytesToEnterCompressionMethod(2) < in_size + bytesToEnterCompressionMethod(0)) { if (compressed_size + bytesToEnterCompressionMethod(2) < in_size + bytesToEnterCompressionMethod(0)) {
@@ -22,9 +22,9 @@ using namespace std;
static uint gray(ColorRGB32 c) static uint gray(ColorRGB32 c)
{ {
if (c.little.red == c.little.green && c.little.red == c.little.blue) { if (c.little.red == c.little.green && c.little.red == c.little.blue) {
return 255 - c.little.red; return c.little.red;
} else { } 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); fPixelDepth = color_space2pixel_depth(cs);
fGray = gray; fGray = gray;
setPlanes(kPlaneMonochrome1); setPlanes(kPlaneMonochrome1);
setBlackValue(kHighValueMeansBlack);
initFloydSteinberg(); initFloydSteinberg();
@@ -99,6 +100,11 @@ void Halftone::setPlanes(Planes planes)
fCurrentPlane = 0; fCurrentPlane = 0;
} }
void Halftone::setBlackValue(BlackValue blackValue)
{
fBlackValue = blackValue;
}
void Halftone::createGammaTable(double gamma) void Halftone::createGammaTable(double gamma)
{ {
// gamma = 1.0f / gamma; // gamma = 1.0f / gamma;
@@ -196,7 +202,7 @@ int Halftone::ditherRGB32(
remainder = 8; remainder = 8;
ColorRGB32 c; ColorRGB32 c;
uchar cur; uchar cur; // cleared bit means white, set bit means black
uint density; uint density;
int i, j; int i, j;
uchar *e = elements; uchar *e = elements;
@@ -217,11 +223,11 @@ int Halftone::ditherRGB32(
density = getDensity(c); density = getDensity(c);
} }
src++; src++;
if (density > *e++) { if (density <= *e++) {
cur |= (0x80 >> j); cur |= (0x80 >> j);
} }
} }
*dst++ = cur; *dst++ = convertUsingBlackValue(cur);
} }
} }
if (remainder > 0) { if (remainder > 0) {
@@ -235,11 +241,11 @@ int Halftone::ditherRGB32(
density = getDensity(c); density = getDensity(c);
} }
src++; src++;
if (density > *e++) { if (density <= *e++) {
cur |= (0x80 >> j); cur |= (0x80 >> j);
} }
} }
*dst++ = cur; *dst++ = convertUsingBlackValue(cur);
} }
return widthByte; 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* error_table = &fErrorTables[fCurrentPlane][1];
int current_error = 0, error; int current_error = 0, error;
const ColorRGB32 *src = (const ColorRGB32 *)a_src; 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 ++) { for (int x = 0; x < width; x ++, src ++) {
const int bit = 7 - x % 8; const int bit = 7 - x % 8;
if (bit == 7) { const int density = getDensity(*src) + current_error / 16;
// clear byte if at first pixel in byte
*dst = 0;
}
int density = getDensity(*src) + current_error / 16;
if (density < 128) { if (density < 128) {
// white pixel
error = density; error = density;
cur |= (1 << bit);
} else { } else {
// black pixel
error = density - 255; error = density - 255;
*dst |= (1 << bit);
} }
// distribute error // distribute error
@@ -321,9 +321,16 @@ int Halftone::ditherFloydSteinberg(uchar *dst, const uchar* a_src, int x, int y,
*left += 3 * error; *left += 3 * error;
if (bit == 0) { if (bit == 0) {
*dst = convertUsingBlackValue(cur);
// advance to next byte // advance to next byte
dst ++; dst ++;
cur = 0;
} }
} }
const bool hasRest = (width % 8) != 0;
if (hasRest) {
*dst = convertUsingBlackValue(cur);
}
} }