📄 ximatran.cpp
字号:
//copy new image to the destination
if (iDst)
iDst->Transfer(newImage);
else
Transfer(newImage);
return true;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Reduces the number of bits per pixel to nbit (1, 4 or 8).
* ppal points to a valid palette for the final image; if not supplied the function will use a standard palette.
* ppal is not necessary for reduction to 1 bpp.
*/
bool CxImage::DecreaseBpp(DWORD nbit, bool errordiffusion, RGBQUAD* ppal, DWORD clrimportant)
{
if (!pDib) return false;
if (head.biBitCount < nbit){
strcpy(info.szLastError,"DecreaseBpp: target BPP greater than source BPP");
return false;
}
if (head.biBitCount == nbit){
if (clrimportant==0) return true;
if (head.biClrImportant && (head.biClrImportant<clrimportant)) return true;
}
long er,eg,eb;
RGBQUAD c,ce;
CxImage tmp;
tmp.CopyInfo(*this);
tmp.Create(head.biWidth,head.biHeight,(WORD)nbit,info.dwType);
if (clrimportant) tmp.SetClrImportant(clrimportant);
if (!tmp.IsValid()){
strcpy(info.szLastError,tmp.GetLastError());
return false;
}
#if CXIMAGE_SUPPORT_SELECTION
tmp.SelectionCopy(*this);
#endif //CXIMAGE_SUPPORT_SELECTION
#if CXIMAGE_SUPPORT_ALPHA
tmp.AlphaCopy(*this);
#endif //CXIMAGE_SUPPORT_ALPHA
if (ppal) {
if (clrimportant) {
tmp.SetPalette(ppal,clrimportant);
} else {
tmp.SetPalette(ppal,1<<tmp.head.biBitCount);
}
} else {
tmp.SetStdPalette();
}
for (long y=0;y<head.biHeight;y++){
if (info.nEscape) break;
info.nProgress = (long)(100*y/head.biHeight);
for (long x=0;x<head.biWidth;x++){
if (!errordiffusion){
tmp.BlindSetPixelColor(x,y,BlindGetPixelColor(x,y));
} else {
c = BlindGetPixelColor(x,y);
tmp.BlindSetPixelColor(x,y,c);
ce = tmp.BlindGetPixelColor(x,y);
er=(long)c.rgbRed - (long)ce.rgbRed;
eg=(long)c.rgbGreen - (long)ce.rgbGreen;
eb=(long)c.rgbBlue - (long)ce.rgbBlue;
c = GetPixelColor(x+1,y);
c.rgbRed = (BYTE)min(255L,max(0L,(long)c.rgbRed + ((er*7)/16)));
c.rgbGreen = (BYTE)min(255L,max(0L,(long)c.rgbGreen + ((eg*7)/16)));
c.rgbBlue = (BYTE)min(255L,max(0L,(long)c.rgbBlue + ((eb*7)/16)));
SetPixelColor(x+1,y,c);
int coeff=1;
for(int i=-1; i<2; i++){
switch(i){
case -1:
coeff=2; break;
case 0:
coeff=4; break;
case 1:
coeff=1; break;
}
c = GetPixelColor(x+i,y+1);
c.rgbRed = (BYTE)min(255L,max(0L,(long)c.rgbRed + ((er * coeff)/16)));
c.rgbGreen = (BYTE)min(255L,max(0L,(long)c.rgbGreen + ((eg * coeff)/16)));
c.rgbBlue = (BYTE)min(255L,max(0L,(long)c.rgbBlue + ((eb * coeff)/16)));
SetPixelColor(x+i,y+1,c);
}
}
}
}
Transfer(tmp);
return true;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Increases the number of bits per pixel of the image.
* \param nbit: 4, 8, 24
*/
bool CxImage::IncreaseBpp(DWORD nbit)
{
if (!pDib) return false;
switch (nbit){
case 4:
{
if (head.biBitCount==4) return true;
if (head.biBitCount>4) return false;
CxImage tmp;
tmp.CopyInfo(*this);
tmp.Create(head.biWidth,head.biHeight,4,info.dwType);
tmp.SetPalette(GetPalette(),GetNumColors());
if (!tmp.IsValid()){
strcpy(info.szLastError,tmp.GetLastError());
return false;
}
#if CXIMAGE_SUPPORT_SELECTION
tmp.SelectionCopy(*this);
#endif //CXIMAGE_SUPPORT_SELECTION
#if CXIMAGE_SUPPORT_ALPHA
tmp.AlphaCopy(*this);
#endif //CXIMAGE_SUPPORT_ALPHA
for (long y=0;y<head.biHeight;y++){
if (info.nEscape) break;
for (long x=0;x<head.biWidth;x++){
tmp.BlindSetPixelIndex(x,y,BlindGetPixelIndex(x,y));
}
}
Transfer(tmp);
return true;
}
case 8:
{
if (head.biBitCount==8) return true;
if (head.biBitCount>8) return false;
CxImage tmp;
tmp.CopyInfo(*this);
tmp.Create(head.biWidth,head.biHeight,8,info.dwType);
tmp.SetPalette(GetPalette(),GetNumColors());
if (!tmp.IsValid()){
strcpy(info.szLastError,tmp.GetLastError());
return false;
}
#if CXIMAGE_SUPPORT_SELECTION
tmp.SelectionCopy(*this);
#endif //CXIMAGE_SUPPORT_SELECTION
#if CXIMAGE_SUPPORT_ALPHA
tmp.AlphaCopy(*this);
#endif //CXIMAGE_SUPPORT_ALPHA
for (long y=0;y<head.biHeight;y++){
if (info.nEscape) break;
for (long x=0;x<head.biWidth;x++){
tmp.BlindSetPixelIndex(x,y,BlindGetPixelIndex(x,y));
}
}
Transfer(tmp);
return true;
}
case 24:
{
if (head.biBitCount==24) return true;
if (head.biBitCount>24) return false;
CxImage tmp;
tmp.CopyInfo(*this);
tmp.Create(head.biWidth,head.biHeight,24,info.dwType);
if (!tmp.IsValid()){
strcpy(info.szLastError,tmp.GetLastError());
return false;
}
if (info.nBkgndIndex>=0) //translate transparency
tmp.info.nBkgndColor=GetPaletteColor((BYTE)info.nBkgndIndex);
#if CXIMAGE_SUPPORT_SELECTION
tmp.SelectionCopy(*this);
#endif //CXIMAGE_SUPPORT_SELECTION
#if CXIMAGE_SUPPORT_ALPHA
tmp.AlphaCopy(*this);
if (AlphaPaletteIsValid() && !AlphaIsValid()) tmp.AlphaCreate();
#endif //CXIMAGE_SUPPORT_ALPHA
for (long y=0;y<head.biHeight;y++){
if (info.nEscape) break;
for (long x=0;x<head.biWidth;x++){
tmp.BlindSetPixelColor(x,y,BlindGetPixelColor(x,y),true);
}
}
Transfer(tmp);
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Converts the image to B&W using the desired method :
* - 0 = Floyd-Steinberg
* - 1 = Ordered-Dithering (4x4)
* - 2 = Burkes
* - 3 = Stucki
* - 4 = Jarvis-Judice-Ninke
* - 5 = Sierra
* - 6 = Stevenson-Arce
* - 7 = Bayer (4x4 ordered dithering)
*/
bool CxImage::Dither(long method)
{
if (!pDib) return false;
if (head.biBitCount == 1) return true;
GrayScale();
CxImage tmp;
tmp.CopyInfo(*this);
tmp.Create(head.biWidth, head.biHeight, 1, info.dwType);
if (!tmp.IsValid()){
strcpy(info.szLastError,tmp.GetLastError());
return false;
}
#if CXIMAGE_SUPPORT_SELECTION
tmp.SelectionCopy(*this);
#endif //CXIMAGE_SUPPORT_SELECTION
#if CXIMAGE_SUPPORT_ALPHA
tmp.AlphaCopy(*this);
#endif //CXIMAGE_SUPPORT_ALPHA
switch (method){
case 1:
{
// Multi-Level Ordered-Dithering by Kenny Hoff (Oct. 12, 1995)
#define dth_NumRows 4
#define dth_NumCols 4
#define dth_NumIntensityLevels 2
#define dth_NumRowsLessOne (dth_NumRows-1)
#define dth_NumColsLessOne (dth_NumCols-1)
#define dth_RowsXCols (dth_NumRows*dth_NumCols)
#define dth_MaxIntensityVal 255
#define dth_MaxDitherIntensityVal (dth_NumRows*dth_NumCols*(dth_NumIntensityLevels-1))
int DitherMatrix[dth_NumRows][dth_NumCols] = {{0,8,2,10}, {12,4,14,6}, {3,11,1,9}, {15,7,13,5} };
unsigned char Intensity[dth_NumIntensityLevels] = { 0,1 }; // 2 LEVELS B/W
//unsigned char Intensity[NumIntensityLevels] = { 0,255 }; // 2 LEVELS
//unsigned char Intensity[NumIntensityLevels] = { 0,127,255 }; // 3 LEVELS
//unsigned char Intensity[NumIntensityLevels] = { 0,85,170,255 }; // 4 LEVELS
//unsigned char Intensity[NumIntensityLevels] = { 0,63,127,191,255 }; // 5 LEVELS
//unsigned char Intensity[NumIntensityLevels] = { 0,51,102,153,204,255 }; // 6 LEVELS
//unsigned char Intensity[NumIntensityLevels] = { 0,42,85,127,170,213,255 }; // 7 LEVELS
//unsigned char Intensity[NumIntensityLevels] = { 0,36,73,109,145,182,219,255 }; // 8 LEVELS
int DitherIntensity, DitherMatrixIntensity, Offset, DeviceIntensity;
unsigned char DitherValue;
for (long y=0;y<head.biHeight;y++){
info.nProgress = (long)(100*y/head.biHeight);
if (info.nEscape) break;
for (long x=0;x<head.biWidth;x++){
DeviceIntensity = BlindGetPixelIndex(x,y);
DitherIntensity = DeviceIntensity*dth_MaxDitherIntensityVal/dth_MaxIntensityVal;
DitherMatrixIntensity = DitherIntensity % dth_RowsXCols;
Offset = DitherIntensity / dth_RowsXCols;
if (DitherMatrix[y&dth_NumRowsLessOne][x&dth_NumColsLessOne] < DitherMatrixIntensity)
DitherValue = Intensity[1+Offset];
else
DitherValue = Intensity[0+Offset];
tmp.BlindSetPixelIndex(x,y,DitherValue);
}
}
break;
}
case 2:
{
//Burkes error diffusion (Thanks to Franco Gerevini)
int TotalCoeffSum = 32;
long error, nlevel, coeff=1;
BYTE level;
for (long y = 0; y < head.biHeight; y++) {
info.nProgress = (long)(100 * y / head.biHeight);
if (info.nEscape)
break;
for (long x = 0; x < head.biWidth; x++) {
level = BlindGetPixelIndex(x, y);
if (level > 128) {
tmp.SetPixelIndex(x, y, 1);
error = level - 255;
} else {
tmp.SetPixelIndex(x, y, 0);
error = level;
}
nlevel = GetPixelIndex(x + 1, y) + (error * 8) / TotalCoeffSum;
level = (BYTE)min(255, max(0, (int)nlevel));
SetPixelIndex(x + 1, y, level);
nlevel = GetPixelIndex(x + 2, y) + (error * 4) / TotalCoeffSum;
level = (BYTE)min(255, max(0, (int)nlevel));
SetPixelIndex(x + 2, y, level);
int i;
for (i = -2; i < 3; i++) {
switch (i) {
case -2:
coeff = 2;
break;
case -1:
coeff = 4;
break;
case 0:
coeff = 8;
break;
case 1:
coeff = 4;
break;
case 2:
coeff = 2;
break;
}
nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum;
level = (BYTE)min(255, max(0, (int)nlevel));
SetPixelIndex(x + i, y + 1, level);
}
}
}
break;
}
case 3:
{
//Stucki error diffusion (Thanks to Franco Gerevini)
int TotalCoeffSum = 42;
long error, nlevel, coeff=1;
BYTE level;
for (long y = 0; y < head.biHeight; y++) {
info.nProgress = (long)(100 * y / head.biHeight);
if (info.nEscape)
break;
for (long x = 0; x < head.biWidth; x++) {
level = BlindGetPixelIndex(x, y);
if (level > 128) {
tmp.SetPixelIndex(x, y, 1);
error = level - 255;
} else {
tmp.SetPixelIndex(x, y, 0);
error = level;
}
nlevel = GetPixelIndex(x + 1, y) + (error * 8) / TotalCoeffSum;
level = (BYTE)min(255, max(0, (int)nlevel));
SetPixelIndex(x + 1, y, level);
nlevel = GetPixelIndex(x + 2, y) + (error * 4) / TotalCoeffSum;
level = (BYTE)min(255, max(0, (int)nlevel));
SetPixelIndex(x + 2, y, level);
int i;
for (i = -2; i < 3; i++) {
switch (i) {
case -2:
coeff = 2;
break;
case -1:
coeff = 4;
break;
case 0:
coeff = 8;
break;
case 1:
coeff = 4;
break;
case 2:
coeff = 2;
break;
}
nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum;
level = (BYTE)min(255, max(0, (int)nlevel));
SetPixelIndex(x + i, y + 1, level);
}
for (i = -2; i < 3; i++) {
switch (i) {
case -2:
coeff = 1;
break;
case -1:
coeff = 2;
break;
case 0:
coeff = 4;
break;
case 1:
coeff = 2;
break;
case 2:
coeff = 1;
break;
}
nlevel = GetPixelIndex(x + i, y + 2) + (error * coeff) / TotalCoeffSum;
level = (BYTE)min(255, max(0, (int)nlevel));
SetPixelIndex(x + i, y + 2, level);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -