Clean up.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14924 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Pfeiffer
2005-11-14 19:08:35 +00:00
parent 614de12d9c
commit 4a6c604ad4
3 changed files with 486 additions and 486 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
/*****************************************************************************/ /*****************************************************************************/
// BeUtils.cpp // BeUtils.h
// //
// Version: 1.0.0d1 // Version: 1.0.0d1
// //
+148 -148
View File
@@ -1,148 +1,148 @@
/* /*
* HalftoneEngine.h * Halftone.h
* Copyright 1999-2000 Y.Takagi. All Rights Reserved. * Copyright 1999-2000 Y.Takagi. All Rights Reserved.
*/ */
#ifndef __HALFTONE_H #ifndef __HALFTONE_H
#define __HALFTONE_H #define __HALFTONE_H
#include <GraphicsDefs.h> #include <GraphicsDefs.h>
// definition for B_RGB32 (=B_RGB32_LITTLE) and B_RGBA32 // definition for B_RGB32 (=B_RGB32_LITTLE) and B_RGBA32
typedef struct { typedef struct {
uchar blue; uchar blue;
uchar green; uchar green;
uchar red; uchar red;
uchar alpha; // unused in B_RGB32 uchar alpha; // unused in B_RGB32
} ColorRGB32Little; } ColorRGB32Little;
// definition for B_RGB32_BIG and B_RGBA32_BIG // definition for B_RGB32_BIG and B_RGBA32_BIG
typedef struct { typedef struct {
uchar alpha; // unused in B_RGB32_BIG uchar alpha; // unused in B_RGB32_BIG
uchar red; uchar red;
uchar green; uchar green;
uchar blue; uchar blue;
} ColorRGB32Big; } ColorRGB32Big;
typedef union { typedef union {
ColorRGB32Little little; ColorRGB32Little little;
ColorRGB32Big big; ColorRGB32Big big;
} ColorRGB32; } ColorRGB32;
class Halftone; class Halftone;
typedef void (Halftone::*PFN_dither)(uchar *dst, const uchar *src, int x, int y, int width); typedef void (Halftone::*PFN_dither)(uchar *dst, const uchar *src, int x, int y, int width);
typedef uint (*PFN_gray)(ColorRGB32 c); typedef uint (*PFN_gray)(ColorRGB32 c);
class Halftone { class Halftone {
public: public:
enum DitherType { enum DitherType {
kType1, kType1,
kType2, kType2,
kType3, kType3,
kTypeFloydSteinberg, kTypeFloydSteinberg,
}; };
enum GrayFunction { enum GrayFunction {
kMixToGray, kMixToGray,
kRedChannel, kRedChannel,
kGreenChannel, kGreenChannel,
kBlueChannel kBlueChannel
}; };
enum Planes { enum Planes {
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 { enum BlackValue {
kHighValueMeansBlack, kHighValueMeansBlack,
kLowValueMeansBlack, kLowValueMeansBlack,
}; };
Halftone(color_space cs, double gamma = 1.4, double min = 0.0, DitherType dither_type = kTypeFloydSteinberg); Halftone(color_space cs, double gamma = 1.4, double min = 0.0, DitherType dither_type = kTypeFloydSteinberg);
~Halftone(); ~Halftone();
void setPlanes(Planes planes); void setPlanes(Planes planes);
void setBlackValue(BlackValue blackValue); void setBlackValue(BlackValue blackValue);
void dither(uchar *dst, const uchar *src, int x, int y, int width); void dither(uchar *dst, const uchar *src, int x, int y, int width);
int getPixelDepth() const; int getPixelDepth() 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: 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);
void createGammaTable(double gamma, double min); void createGammaTable(double gamma, double min);
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; uchar convertUsingBlackValue(uchar byte) const;
void ditherRGB32(uchar *dst, const uchar *src, int x, int y, int width); void ditherRGB32(uchar *dst, const uchar *src, int x, int y, int width);
void initFloydSteinberg(); void initFloydSteinberg();
void deleteErrorTables(); void deleteErrorTables();
void uninitFloydSteinberg(); void uninitFloydSteinberg();
void setupErrorBuffer(int x, int y, int width); void setupErrorBuffer(int x, int y, int width);
void ditherFloydSteinberg(uchar *dst, const uchar* src, int x, int y, int width); void ditherFloydSteinberg(uchar *dst, const uchar* src, int x, int y, int width);
Halftone(const Halftone &); Halftone(const Halftone &);
Halftone &operator = (const Halftone &); Halftone &operator = (const Halftone &);
private: private:
enum { enum {
kGammaTableSize = 256, kGammaTableSize = 256,
kMaxNumberOfPlanes = 3 kMaxNumberOfPlanes = 3
}; };
PFN_dither fDither; PFN_dither fDither;
PFN_gray fGray; PFN_gray fGray;
int fPixelDepth; int fPixelDepth;
Planes fPlanes; Planes fPlanes;
BlackValue fBlackValue; BlackValue fBlackValue;
const uchar *fPattern; const uchar *fPattern;
uint fGammaTable[kGammaTableSize]; uint fGammaTable[kGammaTableSize];
int fNumberOfPlanes; int fNumberOfPlanes;
int fCurrentPlane; int fCurrentPlane;
// fields used for floyd-steinberg dithering // fields used for floyd-steinberg dithering
int fX; int fX;
int fY; int fY;
int fWidth; int fWidth;
int *fErrorTables[kMaxNumberOfPlanes]; int *fErrorTables[kMaxNumberOfPlanes];
}; };
inline int Halftone::getPixelDepth() const inline int Halftone::getPixelDepth() const
{ {
return fPixelDepth; return fPixelDepth;
} }
inline const uchar * Halftone::getPattern() const inline const uchar * Halftone::getPattern() const
{ {
return fPattern; return fPattern;
} }
inline void Halftone::setPattern(const uchar *pattern) inline void Halftone::setPattern(const uchar *pattern)
{ {
fPattern = pattern; fPattern = pattern;
} }
inline PFN_gray Halftone::getGrayFunction() const inline PFN_gray Halftone::getGrayFunction() const
{ {
return fGray; return fGray;
} }
inline void Halftone::setGrayFunction(PFN_gray gray) inline void Halftone::setGrayFunction(PFN_gray gray)
{ {
fGray = gray; fGray = gray;
} }
inline uint Halftone::getDensity(ColorRGB32 c) const inline uint Halftone::getDensity(ColorRGB32 c) const
{ {
return fGammaTable[fGray(c)]; return fGammaTable[fGray(c)];
} }
inline uchar Halftone::convertUsingBlackValue(uchar byte) const inline uchar Halftone::convertUsingBlackValue(uchar byte) const
{ {
// bits with value = '1' in byte mean black // bits with value = '1' in byte mean black
if (fBlackValue == kHighValueMeansBlack) { if (fBlackValue == kHighValueMeansBlack) {
return byte; return byte;
} else { } else {
return ~byte; return ~byte;
} }
} }
#endif /* __HALFTONE_H */ #endif /* __HALFTONE_H */
@@ -1,337 +1,337 @@
/* /*
* HalftoneEngine.cpp * Halftone.cpp
* Copyright 1999-2000 Y.Takagi. All Rights Reserved. * Copyright 1999-2000 Y.Takagi. All Rights Reserved.
*/ */
#include <Debug.h> #include <Debug.h>
#include <InterfaceDefs.h> #include <InterfaceDefs.h>
#include <math.h> #include <math.h>
#include <memory> #include <memory>
#include "Halftone.h" #include "Halftone.h"
#include "ValidRect.h" #include "ValidRect.h"
#include "DbgMsg.h" #include "DbgMsg.h"
#if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) #if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE))
using namespace std; using namespace std;
#else #else
#define std #define std
#endif #endif
#include "Pattern.h" #include "Pattern.h"
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 c.little.red; return c.little.red;
} else { } else {
return (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;
} }
} }
static uint channel_red(ColorRGB32 c) static uint channel_red(ColorRGB32 c)
{ {
return c.little.red; return c.little.red;
} }
static uint channel_green(ColorRGB32 c) static uint channel_green(ColorRGB32 c)
{ {
return c.little.green; return c.little.green;
} }
static uint channel_blue(ColorRGB32 c) static uint channel_blue(ColorRGB32 c)
{ {
return c.little.blue; return c.little.blue;
} }
Halftone::Halftone(color_space cs, double gamma, double min, DitherType dither_type) Halftone::Halftone(color_space cs, double gamma, double min, DitherType dither_type)
{ {
fPixelDepth = color_space2pixel_depth(cs); fPixelDepth = color_space2pixel_depth(cs);
fGray = gray; fGray = gray;
setPlanes(kPlaneMonochrome1); setPlanes(kPlaneMonochrome1);
setBlackValue(kHighValueMeansBlack); setBlackValue(kHighValueMeansBlack);
initFloydSteinberg(); initFloydSteinberg();
createGammaTable(gamma, min); createGammaTable(gamma, min);
if (dither_type == kTypeFloydSteinberg) { if (dither_type == kTypeFloydSteinberg) {
fDither = &Halftone::ditherFloydSteinberg; fDither = &Halftone::ditherFloydSteinberg;
return; return;
} }
switch (dither_type) { switch (dither_type) {
case kType2: case kType2:
fPattern = pattern16x16_type2; fPattern = pattern16x16_type2;
break; break;
case kType3: case kType3:
fPattern = pattern16x16_type3; fPattern = pattern16x16_type3;
break; break;
default: default:
fPattern = pattern16x16_type1; fPattern = pattern16x16_type1;
break; break;
} }
switch (cs) { switch (cs) {
case B_RGB32: case B_RGB32:
case B_RGB32_BIG: case B_RGB32_BIG:
fDither = &Halftone::ditherRGB32; fDither = &Halftone::ditherRGB32;
break; break;
default: default:
fDither = NULL; fDither = NULL;
break; break;
} }
} }
Halftone::~Halftone() Halftone::~Halftone()
{ {
uninitFloydSteinberg(); uninitFloydSteinberg();
} }
void Halftone::setPlanes(Planes planes) void Halftone::setPlanes(Planes planes)
{ {
fPlanes = planes; fPlanes = planes;
if (planes == kPlaneMonochrome1) { if (planes == kPlaneMonochrome1) {
fNumberOfPlanes = 1; fNumberOfPlanes = 1;
fGray = gray; fGray = gray;
} else { } else {
ASSERT(planes == kPlaneRGB1); ASSERT(planes == kPlaneRGB1);
fNumberOfPlanes = 3; fNumberOfPlanes = 3;
} }
fCurrentPlane = 0; fCurrentPlane = 0;
} }
void Halftone::setBlackValue(BlackValue blackValue) void Halftone::setBlackValue(BlackValue blackValue)
{ {
fBlackValue = blackValue; fBlackValue = blackValue;
} }
void Halftone::createGammaTable(double gamma, double min) void Halftone::createGammaTable(double gamma, double min)
{ {
uint *g = fGammaTable; uint *g = fGammaTable;
const double kScalingFactor = 255.0 - min; const double kScalingFactor = 255.0 - min;
for (int i = 0; i < kGammaTableSize; i++) { for (int i = 0; i < kGammaTableSize; i++) {
const double kGammaCorrectedValue = pow((double)i / 255.0, gamma); const double kGammaCorrectedValue = pow((double)i / 255.0, gamma);
const double kTranslatedValue = min + kGammaCorrectedValue * kScalingFactor; const double kTranslatedValue = min + kGammaCorrectedValue * kScalingFactor;
*g++ = (uint)(kTranslatedValue); *g++ = (uint)(kTranslatedValue);
} }
} }
void Halftone::initElements(int x, int y, uchar *elements) void Halftone::initElements(int x, int y, uchar *elements)
{ {
x &= 0x0F; x &= 0x0F;
y &= 0x0F; y &= 0x0F;
const uchar *left = &fPattern[y * 16]; const uchar *left = &fPattern[y * 16];
const uchar *pos = left + x; const uchar *pos = left + x;
const uchar *right = left + 0x0F; const uchar *right = left + 0x0F;
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
*elements++ = *pos; *elements++ = *pos;
if (pos >= right) { if (pos >= right) {
pos = left; pos = left;
} else { } else {
pos++; pos++;
} }
} }
} }
void Halftone::dither( void Halftone::dither(
uchar *dst, uchar *dst,
const uchar *src, const uchar *src,
int x, int x,
int y, int y,
int width) int width)
{ {
if (fPlanes == kPlaneRGB1) { if (fPlanes == kPlaneRGB1) {
switch (fCurrentPlane) { switch (fCurrentPlane) {
case 0: case 0:
setGrayFunction(kRedChannel); setGrayFunction(kRedChannel);
break; break;
case 1: case 1:
setGrayFunction(kGreenChannel); setGrayFunction(kGreenChannel);
break; break;
case 2: case 2:
setGrayFunction(kBlueChannel); setGrayFunction(kBlueChannel);
break; break;
} }
} else { } else {
ASSERT(fGray == &gray); ASSERT(fGray == &gray);
} }
(this->*fDither)(dst, src, x, y, width); (this->*fDither)(dst, src, x, y, width);
// next plane // next plane
fCurrentPlane ++; fCurrentPlane ++;
if (fCurrentPlane >= fNumberOfPlanes) { if (fCurrentPlane >= fNumberOfPlanes) {
fCurrentPlane = 0; fCurrentPlane = 0;
} }
} }
void Halftone::setGrayFunction(GrayFunction grayFunction) void Halftone::setGrayFunction(GrayFunction grayFunction)
{ {
PFN_gray function = NULL; PFN_gray function = NULL;
switch (grayFunction) { switch (grayFunction) {
case kMixToGray: function = gray; case kMixToGray: function = gray;
break; break;
case kRedChannel: function = channel_red; case kRedChannel: function = channel_red;
break; break;
case kGreenChannel: function = channel_green; case kGreenChannel: function = channel_green;
break; break;
case kBlueChannel: function = channel_blue; case kBlueChannel: function = channel_blue;
break; break;
}; };
setGrayFunction(function); setGrayFunction(function);
} }
void Halftone::ditherRGB32( void Halftone::ditherRGB32(
uchar *dst, uchar *dst,
const uchar *a_src, const uchar *a_src,
int x, int x,
int y, int y,
int width) int width)
{ {
uchar elements[16]; uchar elements[16];
initElements(x, y, elements); initElements(x, y, elements);
const ColorRGB32 *src = (const ColorRGB32 *)a_src; const ColorRGB32 *src = (const ColorRGB32 *)a_src;
int widthByte = (width + 7) / 8; int widthByte = (width + 7) / 8;
int remainder = width % 8; int remainder = width % 8;
if (remainder == 0) if (remainder == 0)
remainder = 8; remainder = 8;
ColorRGB32 c; ColorRGB32 c;
uchar cur; // cleared bit means white, set bit means black 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;
uchar *last_e = elements + 16; uchar *last_e = elements + 16;
c = *src; c = *src;
density = getDensity(c); density = getDensity(c);
if (width >= 8) { if (width >= 8) {
for (i = 0; i < widthByte - 1; i++) { for (i = 0; i < widthByte - 1; i++) {
cur = 0; cur = 0;
if (e == last_e) { if (e == last_e) {
e = elements; e = elements;
} }
for (j = 0; j < 8; j++) { for (j = 0; j < 8; j++) {
if (c.little.red != src->little.red || c.little.green != src->little.green || c.little.blue != src->little.blue) { if (c.little.red != src->little.red || c.little.green != src->little.green || c.little.blue != src->little.blue) {
c = *src; c = *src;
density = getDensity(c); density = getDensity(c);
} }
src++; src++;
if (density <= *e++) { if (density <= *e++) {
cur |= (0x80 >> j); cur |= (0x80 >> j);
} }
} }
*dst++ = convertUsingBlackValue(cur); *dst++ = convertUsingBlackValue(cur);
} }
} }
if (remainder > 0) { if (remainder > 0) {
cur = 0; cur = 0;
if (e == last_e) { if (e == last_e) {
e = elements; e = elements;
} }
for (j = 0; j < remainder; j++) { for (j = 0; j < remainder; j++) {
if (c.little.red != src->little.red || c.little.green != src->little.green || c.little.blue != src->little.blue) { if (c.little.red != src->little.red || c.little.green != src->little.green || c.little.blue != src->little.blue) {
c = *src; c = *src;
density = getDensity(c); density = getDensity(c);
} }
src++; src++;
if (density <= *e++) { if (density <= *e++) {
cur |= (0x80 >> j); cur |= (0x80 >> j);
} }
} }
*dst++ = convertUsingBlackValue(cur); *dst++ = convertUsingBlackValue(cur);
} }
} }
// Floyd-Steinberg dithering // Floyd-Steinberg dithering
void Halftone::initFloydSteinberg() void Halftone::initFloydSteinberg()
{ {
for (int i = 0; i < kMaxNumberOfPlanes; i ++) { for (int i = 0; i < kMaxNumberOfPlanes; i ++) {
fErrorTables[i] = NULL; fErrorTables[i] = NULL;
} }
} }
void Halftone::deleteErrorTables() void Halftone::deleteErrorTables()
{ {
for (int i = 0; i < kMaxNumberOfPlanes; i ++) { for (int i = 0; i < kMaxNumberOfPlanes; i ++) {
delete fErrorTables[i]; delete fErrorTables[i];
fErrorTables[i] = NULL; fErrorTables[i] = NULL;
} }
} }
void Halftone::uninitFloydSteinberg() void Halftone::uninitFloydSteinberg()
{ {
deleteErrorTables(); deleteErrorTables();
} }
void Halftone::setupErrorBuffer(int x, int y, int width) void Halftone::setupErrorBuffer(int x, int y, int width)
{ {
deleteErrorTables(); deleteErrorTables();
fX = x; fX = x;
fY = y; fY = y;
fWidth = width; fWidth = width;
for (int i = 0; i < fNumberOfPlanes; i ++) { for (int i = 0; i < fNumberOfPlanes; i ++) {
// reserve also space for sentinals at both ends of error table // reserve also space for sentinals at both ends of error table
const int size = width + 2; const int size = width + 2;
fErrorTables[i] = new int[size]; fErrorTables[i] = new int[size];
memset(fErrorTables[i], 0, sizeof(int) * size); memset(fErrorTables[i], 0, sizeof(int) * size);
} }
} }
void Halftone::ditherFloydSteinberg(uchar *dst, const uchar* a_src, int x, int y, int width) void Halftone::ditherFloydSteinberg(uchar *dst, const uchar* a_src, int x, int y, int width)
{ {
if (fErrorTables[fCurrentPlane] == NULL || fX != x || fCurrentPlane == 0 && fY != y - 1 || fCurrentPlane > 0 && fY != y || fWidth != width) { if (fErrorTables[fCurrentPlane] == NULL || fX != x || fCurrentPlane == 0 && fY != y - 1 || fCurrentPlane > 0 && fY != y || fWidth != width) {
setupErrorBuffer(x, y, width); setupErrorBuffer(x, y, width);
} else { } else {
fY = y; fY = y;
} }
int* error_table = &fErrorTables[fCurrentPlane][1]; int* error_table = &fErrorTables[fCurrentPlane][1];
int current_error = error_table[0], error; int current_error = error_table[0], error;
error_table[0] = 0; error_table[0] = 0;
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 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;
const int density = getDensity(*src) + current_error / 16; const int density = getDensity(*src) + current_error / 16;
if (density < 128) { if (density < 128) {
error = density; error = density;
cur |= (1 << bit); cur |= (1 << bit);
} else { } else {
error = density - 255; error = density - 255;
} }
// distribute error using this pattern: // distribute error using this pattern:
// 0 X 7 (current_error) // 0 X 7 (current_error)
// (left) 3 5 1 (right) // (left) 3 5 1 (right)
// (middle) // (middle)
int* right = &error_table[x+1]; int* right = &error_table[x+1];
current_error = (*right) + 7 * error; current_error = (*right) + 7 * error;
*right = 1 * error; *right = 1 * error;
int* middle = right - 1; int* middle = right - 1;
*middle += 5 * error; *middle += 5 * error;
int* left = middle - 1; int* left = middle - 1;
*left += 3 * error; *left += 3 * error;
if (bit == 0) { if (bit == 0) {
*dst = convertUsingBlackValue(cur); *dst = convertUsingBlackValue(cur);
// advance to next byte // advance to next byte
dst ++; dst ++;
cur = 0; cur = 0;
} }
} }
const bool hasRest = (width % 8) != 0; const bool hasRest = (width % 8) != 0;
if (hasRest) { if (hasRest) {
*dst = convertUsingBlackValue(cur); *dst = convertUsingBlackValue(cur);
} }
} }