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:
@@ -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 */
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user