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

View File

@ -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 */

View File

@ -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)) {

View File

@ -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);
}
}