Clean up.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14924 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
// BeUtils.cpp
|
// BeUtils.h
|
||||||
//
|
//
|
||||||
// Version: 1.0.0d1
|
// Version: 1.0.0d1
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user