Files
Jedi-Academy/tools/ModView/image.cpp
2013-04-04 14:32:05 -07:00

986 lines
25 KiB
C++

// Filename:- image.cpp
//
#include "stdafx.h"
#include "includes.h"
#include "modview.h"
#include "textures.h"
//
#include "image.h"
#ifndef DWORD
#define DWORD unsigned long
#endif
#define iDSTAMP_CELL_PIXDIM 16 // adjust this, higher = more secure but less stamps on picture
#define iDSTAMP_CELL_PIXELS (iDSTAMP_CELL_PIXDIM * iDSTAMP_CELL_PIXDIM)
#define iDSTAMP_INSTANCE_CELLDIM 8 // leave this alone at all times!
#define iDSTAMP_INSTANCE_PIXDIM (iDSTAMP_INSTANCE_CELLDIM * iDSTAMP_CELL_PIXDIM)
#define iDSTAMP_CHAR_BITS 7
#define iHIDDENBIT 1//32 // 1,2,4,8,16,32,64, or 128
#define iHIDDENBITSHIFT 0//5 // 0,1,2,3, 4 5 6 7
#pragma pack(push,1)
typedef struct
{
char sHDR[3]; // "HDR", no trailing zero
char sDDMMYY[6]; // date/month/year, no trailing zero
char sText[14]; // text, no end trailing zero, but maybe early one
} WatermarkData_t;
typedef struct
{
WatermarkData_t Data;
DWORD dwCRC;
} Watermark_t;
typedef struct
{
byte R,G,B,A;
}Pixel_t;
#pragma pack(pop)
typedef struct
{
byte *pPixels;
int iWidth;
int iHeight;
int iPlanes;
} DStampImage_t;
typedef struct
{
DStampImage_t *pImage;
Watermark_t *pWatermark;
} DStampData_t;
Watermark_t TheWatermark;
#define PixelSetR(p,r) p.R=r
#define PixelSetG(p,g) p.G=g
#define PixelSetB(p,b) p.B=b
#define PixelSetA(p,a) p.A=a
#define PixelGetR(p) p.R
#define PixelGetG(p) p.G
#define PixelGetB(p) p.B
#define PixelGetA(p) p.A
#define PixelInit(p) memset(&p,0,sizeof(p)); // later on I'll adapt this for initing default alpha etc, but for now
#define PROGRESS_INIT \
CProgressCtrl *pProgress = NULL; \
if (((CModViewApp*)AfxGetApp())->m_pMainWnd) \
{ \
pProgress = new CProgressCtrl; \
bool bOK = !!pProgress->Create( WS_CHILD|WS_VISIBLE|PBS_SMOOTH, \
CRect(100,100,200,200), \
((CModViewApp*)AfxGetApp())->m_pMainWnd, \
1 \
); \
if (!bOK) \
{ \
delete pProgress; \
pProgress = NULL; \
} \
}
#define PROGRESS_SETRANGE(range) \
if (pProgress) \
{ \
pProgress->SetRange(0,range); \
}
#define PROGRESS_SETPOS(position) \
if (pProgress) \
{ \
pProgress->SetPos(position);\
}
#define PROGRESS_CLOSE \
if (pProgress) \
{ \
delete pProgress; \
pProgress = 0; \
}
// return NULL = legal, else string saying why not...
//
static LPCSTR DStamp_TextIsLegal(LPCSTR psText)
{
int iLen = strlen(psText);
if (iLen > sizeof(TheWatermark.Data.sText))
{
return va("\"%s\" is too long by %d chars",psText, sizeof(TheWatermark.Data.sText) - iLen);
}
for (int i=0; i<iLen; i++)
{
if (psText[i] > 127)
{
return va("\"%s\" contains hi-ascii char '%c', only 7-bit ascii allowed",psText, psText[i]);
}
}
return NULL;
}
static void DStamp_EncryptData(void *pvData, int iByteLength)
{
/* don't use this method since we need to keep as 7-bit ascii
byte *pData = (byte*) pvData;
for (int i=0; i<iByteLength; i++)
{
*pData = *pData ^ ('#'+i);
pData++;
}
*/
}
// same as encrypt at the moment, because of XOR, but may change...
//
static void DStamp_DecryptData(void *pvData, int iByteLength)
{
DStamp_EncryptData(pvData,iByteLength);
}
static DWORD DStamp_UpdateCRC(DWORD dwCRC, byte b)
{
dwCRC += (DWORD) b;
if (dwCRC & (1<<31))
{
dwCRC<<=1;
dwCRC+=2; // add 1, plus carry
}
else
{
dwCRC<<=1;
dwCRC++; // add 1, no carry
}
return dwCRC;
}
static DWORD DStamp_CalcBlockCRC(void *pvData, int iByteLength)
{
byte *pData = (byte*) pvData;
DWORD dwCRC = 0;
for (int i=0; i<iByteLength; i++)
{
dwCRC = DStamp_UpdateCRC(dwCRC, pData[i]);
}
dwCRC &= 0x7F7F7F7F; // lose 7th bit from each byte
return dwCRC;
}
static LPCSTR DStamp_GetYear(void)
{
static char sTemp[20];
time_t ltime;
time( &ltime );
struct tm *today = localtime( &ltime );
strftime( sTemp, sizeof(sTemp), "%d%m%y", today );
return &sTemp[0];
}
static Watermark_t *DStamp_InitWatermark(LPCSTR psText)
{
Watermark_t *pWatermark = &TheWatermark;
strncpy(pWatermark->Data.sHDR, "HDR", sizeof(pWatermark->Data.sHDR));
strncpy(pWatermark->Data.sText, psText, sizeof(pWatermark->Data.sText));
strncpy(pWatermark->Data.sDDMMYY, DStamp_GetYear(), sizeof(pWatermark->Data.sDDMMYY));
DStamp_EncryptData(&pWatermark->Data, sizeof(pWatermark->Data));
pWatermark->dwCRC = DStamp_CalcBlockCRC(&pWatermark->Data, sizeof(pWatermark->Data));
return pWatermark;
}
static Pixel_t *DStamp_GetImagePixel(DStampImage_t *pImage, int iXpos, int iYpos)
{
int iBPP = (pImage->iPlanes == 24)?3:4;
byte *pPixels = pImage->pPixels + (iYpos * pImage->iWidth * iBPP) + (iXpos * iBPP);
static Pixel_t Pixel;
memcpy(&Pixel, pPixels, iBPP);
if (iBPP == 3)
{
Pixel.A = 255; // actually, this can be ignored
}
return &Pixel;
}
static void DStamp_SetImagePixel(DStampImage_t *pImage, int iXpos, int iYpos, Pixel_t *pPixel)
{
int iBPP = (pImage->iPlanes == 24)?3:4;
byte *pPixels = pImage->pPixels + (iYpos * pImage->iWidth * iBPP) + (iXpos * iBPP);
memcpy(pPixels, pPixel, iBPP);
}
// returns either 0 or 1 for bits, or 2 for "finished"
//
static int DStamp_GetWaterMarkBit(int *piSourceIndex_Byte, int *piSourceIndex_Bit, void *pvBytes, int iBytesLen)
{
byte *pBytes = (byte *) pvBytes;
// if (*piSourceIndex_Byte==(int)strlen(psWatermarkString)+1) // trying to get bits from beyond trailing zero?
// return 2;
if (*piSourceIndex_Byte==iBytesLen) // trying to get bits from beyond trailing zero?
return 2;
char c = pBytes[*piSourceIndex_Byte];
int iBitReturn = (c>>*piSourceIndex_Bit)&1;
*piSourceIndex_Bit+=1; // *not* ++!
if (*piSourceIndex_Bit == iDSTAMP_CHAR_BITS)
{
*piSourceIndex_Bit = 0;
*piSourceIndex_Byte+=1; // *not* ++!
}
return iBitReturn;
}
static void DStamp_ReadCell(DStampData_t *pData, int iCellXpos, int iCellYpos, byte *b1, byte *b2, byte *b3)
{
int iWBitR = 0,
iWBitG = 0,
iWBitB = 0;
for (int iPixelY=0; iPixelY<iDSTAMP_CELL_PIXDIM; iPixelY++)
{
for (int iPixelX=0; iPixelX<iDSTAMP_CELL_PIXDIM; iPixelX++)
{
Pixel_t Pixel = *DStamp_GetImagePixel(pData->pImage, iPixelX + iCellXpos, iPixelY + iCellYpos);
iWBitR += (PixelGetR(Pixel)&iHIDDENBIT)?1:0;
iWBitG += (PixelGetG(Pixel)&iHIDDENBIT)?1:0;
iWBitB += (PixelGetB(Pixel)&iHIDDENBIT)?1:0;
}
}
// work out pixel consensuses... (consensi?)
//
// if > half the pixels are true, accept that as true...
//
*b1 = (iWBitR > iDSTAMP_CELL_PIXELS/2)?1:0;
*b2 = (iWBitG > iDSTAMP_CELL_PIXELS/2)?1:0;
*b3 = (iWBitB > iDSTAMP_CELL_PIXELS/2)?1:0;
}
static void DStamp_MarkCell(DStampData_t *pData, int iCellXpos, int iCellYpos, int *piTxtByte, int *piTxtBit)
{
byte R = DStamp_GetWaterMarkBit(piTxtByte, piTxtBit, pData->pWatermark, sizeof(*pData->pWatermark));
byte G = DStamp_GetWaterMarkBit(piTxtByte, piTxtBit, pData->pWatermark, sizeof(*pData->pWatermark));
byte B = DStamp_GetWaterMarkBit(piTxtByte, piTxtBit, pData->pWatermark, sizeof(*pData->pWatermark));
for (int iPixelY=0; iPixelY<iDSTAMP_CELL_PIXDIM; iPixelY++)
{
for (int iPixelX=0; iPixelX<iDSTAMP_CELL_PIXDIM; iPixelX++)
{
Pixel_t Pixel = *DStamp_GetImagePixel(pData->pImage, iPixelX + iCellXpos, iPixelY + iCellYpos);
PixelSetR(Pixel,( (PixelGetR(Pixel)&~iHIDDENBIT) | (((R==2)?0:R)<<iHIDDENBITSHIFT) ));
PixelSetG(Pixel,( (PixelGetG(Pixel)&~iHIDDENBIT) | (((G==2)?0:G)<<iHIDDENBITSHIFT) ));
PixelSetB(Pixel,( (PixelGetB(Pixel)&~iHIDDENBIT) | (((B==2)?0:B)<<iHIDDENBITSHIFT) ));
DStamp_SetImagePixel(pData->pImage, iPixelX + iCellXpos, iPixelY + iCellYpos, &Pixel);
}
}
/* byte R2,G2,B2;
DStamp_ReadCell(pData, iCellXpos, iCellYpos, &R2,&G2,&B2);
assert( (R2==((R==2)?0:R)) &&
(G2==((G==2)?0:G)) &&
(B2==((B==2)?0:B))
);
*/
}
// apply one watermark-instance to the image...
//
static void DStamp_MarkInstance(DStampData_t *pData, int iInstancePixelX, int iInstancePixelY)
{
int iTxtByte = 0;
int iTxtBit = 0;
for (int iYCell = 0; iYCell < iDSTAMP_INSTANCE_CELLDIM; iYCell++)
{
for (int iXCell = 0; iXCell < iDSTAMP_INSTANCE_CELLDIM; iXCell++)
{
int iCellXpos = iInstancePixelX + (iXCell * iDSTAMP_CELL_PIXDIM);
int iCellYpos = iInstancePixelY + (iYCell * iDSTAMP_CELL_PIXDIM);
DStamp_MarkCell(pData, iCellXpos, iCellYpos, &iTxtByte, &iTxtBit);
}
}
}
// see if we can read some watermark data, else return NULL...
//
static LPCSTR DStamp_ReadInstance(DStampData_t *pData, int iInstancePixelX, int iInstancePixelY)
{
LPCSTR psMessage = NULL;
int iTxtByte = 0;
int iTxtBit = 0;
byte *pbOut = (byte*) pData->pWatermark;
memset(pbOut,0,sizeof(*pData->pWatermark));
for (int iYCell = 0; iYCell < iDSTAMP_INSTANCE_CELLDIM; iYCell++)
{
for (int iXCell = 0; iXCell < iDSTAMP_INSTANCE_CELLDIM; iXCell++)
{
int iCellXpos = iInstancePixelX + (iXCell * iDSTAMP_CELL_PIXDIM);
int iCellYpos = iInstancePixelY + (iYCell * iDSTAMP_CELL_PIXDIM);
byte b1,b2,b3;
DStamp_ReadCell(pData, iCellXpos, iCellYpos, &b1,&b2,&b3);
#define DECODEBIT(DestString,bit) \
DestString[iTxtByte] |= bit<<iTxtBit++; \
if (iTxtBit==iDSTAMP_CHAR_BITS) \
{ \
iTxtBit=0; \
iTxtByte++; \
}
DECODEBIT(pbOut,b1);
DECODEBIT(pbOut,b2);
DECODEBIT(pbOut,b3);
if (iTxtByte>=3) // huge speed opt, check for header, if not found, give up on this cell...
{
if (strncmp((char*)pbOut,"HDR",3))
{
return NULL;
}
}
}
}
if (!strncmp(pData->pWatermark->Data.sHDR,"HDR",3))
{
DWORD dwCRC = DStamp_CalcBlockCRC(&pData->pWatermark->Data, sizeof(pData->pWatermark->Data));
char sString[100];
char sDate[100];
strncpy(sString,pData->pWatermark->Data.sText,sizeof(pData->pWatermark->Data.sText));
sString[sizeof(pData->pWatermark->Data.sText)] = '\0';
strncpy(sDate,pData->pWatermark->Data.sDDMMYY,sizeof(pData->pWatermark->Data.sDDMMYY));
sDate[sizeof(pData->pWatermark->Data.sDDMMYY)] = '\0';
static char sOutput[1024];
sprintf(sOutput,"SentTo: \"%s\", Date(DD/MM/YY) = %s",sString,sDate);
if (dwCRC == pData->pWatermark->dwCRC)
{
OutputDebugString(sOutput);
psMessage = &sOutput[0];
}
else
{
OutputDebugString(va("Skipping non-CRC HDR-match: %s\n",sOutput));
}
}
return psMessage;
}
// return is NULL for ok, else error string...
//
LPCSTR DStamp_MarkImage(byte *pPixels, int iWidth, int iHeight, int iPlanes, LPCSTR psText)
{
LPCSTR psError = NULL;
if (iPlanes == 24 || iPlanes == 32)
{
psError = DStamp_TextIsLegal(psText);
if (!psError)
{
DStampImage_t Image;
Image.pPixels = pPixels;
Image.iWidth = iWidth;
Image.iHeight = iHeight;
Image.iPlanes = iPlanes;
DStampData_t Data;
Data.pImage = &Image;
Data.pWatermark = DStamp_InitWatermark(psText);
int iInstances_Across = Data.pImage->iWidth / iDSTAMP_INSTANCE_PIXDIM;
int iInstances_Down = Data.pImage->iHeight / iDSTAMP_INSTANCE_PIXDIM;
int iInstancesTotal = iInstances_Across * iInstances_Down;
#ifdef _DEBUG
int iDebug_WaterMarkSize = sizeof(Watermark_t);
OutputDebugString(va("%d stamp instances on screen\n",iInstancesTotal));
#endif
if (iInstancesTotal)
{
// center the stamp grid within the image...
//
int iYStart = (Data.pImage->iHeight - (iInstances_Down * iDSTAMP_INSTANCE_PIXDIM))/2;
int iXStart = (Data.pImage->iWidth - (iInstances_Across * iDSTAMP_INSTANCE_PIXDIM))/2;
for (int iInstanceY = 0; iInstanceY < iInstances_Down; iInstanceY++)
{
for (int iInstanceX = 0; iInstanceX < iInstances_Across; iInstanceX++)
{
int iInstancePixelX = (iInstanceX * iDSTAMP_INSTANCE_PIXDIM) + iXStart;
int iInstancePixelY = (iInstanceY * iDSTAMP_INSTANCE_PIXDIM) + iYStart;
DStamp_MarkInstance(&Data, iInstancePixelX, iInstancePixelY);
// LPCSTR psMessage = DStamp_ReadInstance(&Data, iInstancePixelX, iInstancePixelY);
// if (psMessage)
// {
// OutputDebugString(va("Marked Instance with message \"%s\"\n",psMessage));
// }
// else
// {
// int z=1;
// }
}
}
}
else
{
psError = va("DStamp_MarkImage(): Unable to fit watermark on screen using iDSTAMP_CELL_PIXDIM of %d!",iDSTAMP_CELL_PIXDIM);
}
}
}
else
{
psError = "DStamp_MarkImage(): Supplied image must be 24 or 32 bit";
}
return psError;
}
bool DStamp_MarkImage(Texture_t *pTexture, LPCSTR psText)
{
LPCSTR psError = DStamp_MarkImage(pTexture->pPixels, pTexture->iWidth, pTexture->iHeight, 32, psText);
if (!psError)
return true;
ErrorBox(psError);
return false;
}
void DStamp_AnalyseImage(byte *pPixels, int iWidth, int iHeight, int iPlanes)
{
CWaitCursor wait;
const int iBlockSampleSize = 8;
PROGRESS_INIT;
PROGRESS_SETRANGE((iHeight/iBlockSampleSize));
DStampImage_t Image;
Image.pPixels = pPixels;
Image.iWidth = iWidth;
Image.iHeight = iHeight;
Image.iPlanes = iPlanes;
DStampImage_t ImageOut;
ImageOut.pPixels = (byte *) malloc (iWidth * iHeight * ((iPlanes == 24)?3:4));
ImageOut.iWidth = iWidth;
ImageOut.iHeight = iHeight;
ImageOut.iPlanes = iPlanes;
/*
// new line dup code...
//
for (int y=0; y<iHeight-3; y+=30)
{
for (int x=0; x<iWidth; x++)
{
Pixel_t *pPixel = DStamp_GetImagePixel(&Image, x, y);
DStamp_SetImagePixel(&Image, x, y+1, pPixel);
DStamp_SetImagePixel(&Image, x, y+2, pPixel);
DStamp_SetImagePixel(&Image, x, y+3, pPixel);
}
}
*/
#if 1
for (int y = 0; y+iBlockSampleSize < iHeight; y += iBlockSampleSize)
{
PROGRESS_SETPOS(y);
for (int x = 0; x+iBlockSampleSize < iWidth; x += iBlockSampleSize)
{
unsigned int r=0,g=0,b=0;
unsigned int rh=0,gh=0,bh=0;
unsigned int rl=INT_MAX,gl=INT_MAX,bl=INT_MAX;
if (x==120 && y==232)
{
int z=1;
}
int iNoisyPixels = 0;
int iMassivelyDeviantPixels = 0;
for (int iBlockPass=0; iBlockPass<3; iBlockPass++)
{
// pass 0 = read pixels, average out channels
// pass 1 = count noisy pixels
// pass 2 = colour in block as 0 or 255 to show noise if > half blocks noisy
//
for (int by=0; by < iBlockSampleSize; by++)
{
for (int bx=0; bx < iBlockSampleSize; bx++)
{
int px = x+bx;
int py = y+by;
Pixel_t *pPixel = DStamp_GetImagePixel(&Image, px, py);
switch (iBlockPass)
{
case 0: // read/accumulate pixel values...
{
r += pPixel->R;
g += pPixel->G;
b += pPixel->B;
rh = max(rh,pPixel->R);
gh = max(gh,pPixel->G);
bh = max(bh,pPixel->B);
rl = min(rl,pPixel->R);
gl = min(gl,pPixel->G);
bl = min(bl,pPixel->B);
}
break;
case 1: // analyse...
{
if (rh-rl>90 ||
gh-gl>90 ||
bh-bl>90
)
{
iMassivelyDeviantPixels++;
}
if (px>0 && px<iWidth-1 && py>0 && py<iHeight-1)
{
int this_r = pPixel->R;
int this_g = pPixel->G;
int this_b = pPixel->B;
bool bPixelIsNoisy = false;
if (px==123 && py==235)
{
int z=1;
}
for (int y2=py-1; y2<py+2 && !bPixelIsNoisy; y2++)
{
for (int x2=px-1; x2<px+2 && !bPixelIsNoisy; x2++)
{
if (x2!=px&&y2!=py)
{
pPixel = DStamp_GetImagePixel(&Image, x2, y2);
int rdiff = abs(pPixel->R - this_r);
int gdiff = abs(pPixel->G - this_g);
int bdiff = abs(pPixel->B - this_b);
const int iMinTolerance = 7;
const int iMaxTolerance = 50;
if ((rdiff > iMaxTolerance) ||
(gdiff > iMaxTolerance) ||
(bdiff > iMaxTolerance) ||
abs(pPixel->R - r) > iMaxTolerance ||
abs(pPixel->G - g) > iMaxTolerance ||
abs(pPixel->B - b) > iMaxTolerance
)
{
//iMassivelyDeviantPixels++;
iNoisyPixels-=5000; // force not to be noisy for blocks with sharp contrasts
}
else
if ((rdiff > iMinTolerance && rdiff < iMaxTolerance) ||
(gdiff > iMinTolerance && gdiff < iMaxTolerance) ||
(bdiff > iMinTolerance && bdiff < iMaxTolerance)
)
{
bPixelIsNoisy = true;
}
}
}
}
if (bPixelIsNoisy)
{
iNoisyPixels++;
}
}
}
break;
case 2: // paint...
{
pPixel->R = pPixel->G = pPixel->B = (iNoisyPixels>((iBlockSampleSize*iBlockSampleSize)/2))?255:0;
DStamp_SetImagePixel(&ImageOut, x+bx, y+by, pPixel);
}
break;
}
}
}
switch (iBlockPass)
{
case 0:
r /= iBlockSampleSize*iBlockSampleSize;
g /= iBlockSampleSize*iBlockSampleSize;
b /= iBlockSampleSize*iBlockSampleSize;
break;
case 1:
if (iMassivelyDeviantPixels > (iBlockSampleSize*iBlockSampleSize)/8)
{
// if > 1/8th of the pixels are massively deviant, then set this block so we can't use it.
iNoisyPixels-=5000; // force not to be noisy for blocks with sharp contrasts
}
break;
}
}
}
}
#endif
#if 1
// copy analysis results over input picture for saving on return...
//
DStampImage_t ImageTmp;
ImageTmp.pPixels = (byte *) malloc (iWidth * iHeight * ((iPlanes == 24)?3:4));
ImageTmp.iWidth = iWidth;
ImageTmp.iHeight = iHeight;
ImageTmp.iPlanes = iPlanes;
memcpy(ImageTmp.pPixels,ImageOut.pPixels, iWidth * iHeight * ((iPlanes == 24)?3:4));
// now eliminate any single white or black sampleblocks...
//
// for (int iEliminate = 0; iEliminate<2; iEliminate++)
{
// start one-in from all edges, so we can check 8 surrounding squares safely...
//
for (y = 0+iBlockSampleSize; y + (2*iBlockSampleSize) < iHeight; y += iBlockSampleSize)
{
for (int x = 0+iBlockSampleSize; x + (2*iBlockSampleSize) < iWidth; x+= iBlockSampleSize)
{
unsigned int r=0,g=0,b=0;
Pixel_t *pPixel = DStamp_GetImagePixel(&ImageTmp, x, y);
bool bThisPixelWasBlack = !(pPixel->R); // all channels same, so just checking R is fine
//if (bThisPixelWasBlack)
{
// now check neighbours, all 8 surrounding blocks must be same colour, or bye-bye...
//
bool bSurroundedByOpposite = true;
for (int y2=y-iBlockSampleSize; y2<y+(2*iBlockSampleSize) && bSurroundedByOpposite; y2+=iBlockSampleSize)
{
for (int x2=x-iBlockSampleSize; x2<x+(2*iBlockSampleSize) && bSurroundedByOpposite; x2+=iBlockSampleSize)
{
if (x2!=x && y2!=y)
{
Pixel_t *pPixel = DStamp_GetImagePixel(&ImageTmp, x2, y2);
bool bScanPixelWasBlack = !(pPixel->R);
if (bScanPixelWasBlack == bThisPixelWasBlack)
{
bSurroundedByOpposite = false;
}
}
}
}
if (bSurroundedByOpposite)
{
// blot this pixel out by toggling it to the other colour...
//
pPixel->R = pPixel->G = pPixel->B = bThisPixelWasBlack?255:0;
for (int py=y; py<y+iBlockSampleSize; py++)
{
for (int px=x; px<x+iBlockSampleSize; px++)
{
DStamp_SetImagePixel(&ImageOut, px, py, pPixel);
}
}
}
}
}
}
}
memcpy(ImageTmp.pPixels,ImageOut.pPixels, iWidth * iHeight * ((iPlanes == 24)?3:4));
#endif
// now highlight original pic with differences...
//
for (y=0; y+iBlockSampleSize < iHeight; y+=iBlockSampleSize)
{
for (int x=0; x+iBlockSampleSize < iWidth; x+=iBlockSampleSize)
{
Pixel_t *pPixel = DStamp_GetImagePixel(&ImageTmp, x, y);
bool bThisPixelWasBlack = !(pPixel->R); // all channels same, so just checking R is fine
// bool bPrevPixelWasBlack = true;
// if (x>=iBlockSampleSize)
// {
// pPixel = DStamp_GetImagePixel(&ImageTmp, x-iBlockSampleSize, y);
// bPrevPixelWasBlack = !(pPixel->R); // all channels same, so just checking R is fine
// }
if (!bThisPixelWasBlack )//&& !bPrevPixelWasBlack)
{
unsigned int r=0,g=0,b=0;
for (int iPass=0; iPass<2; iPass++)
{
// highlight this sample square of the original pic...
//
for (int y2=y; y2<y+iBlockSampleSize; y2++)
{
for (int x2=x; x2<x+iBlockSampleSize; x2++)
{
if (!iPass)
{
pPixel = DStamp_GetImagePixel(&Image, x2, y2);
r+= pPixel->R;
g+= pPixel->G;
b+= pPixel->B;
}
else
{
#if 1
// highlight...
//
pPixel = DStamp_GetImagePixel(&Image, x2/*-iBlockSampleSize*/, y2);
pPixel->R |= 128;
pPixel->G &=~128;
pPixel->B &=~128;
#else
pPixel = DStamp_GetImagePixel(&Image, x2, y2);
pPixel->R = (r + pPixel->R)/2;
pPixel->G = (g + pPixel->G)/2;
pPixel->B = (b + pPixel->B)/2;
#endif
DStamp_SetImagePixel(&Image, x2, y2, pPixel);
}
}
}
if (!iPass)
{
pPixel->R = r = r/(iBlockSampleSize*iBlockSampleSize);
pPixel->G = g = g/(iBlockSampleSize*iBlockSampleSize);
pPixel->B = b = b/(iBlockSampleSize*iBlockSampleSize);
}
}
}
}
}
PROGRESS_CLOSE;
free(ImageTmp.pPixels);
free(ImageOut.pPixels);
}
void DStamp_AnalyseImage(Texture_t *pTexture)
{
DStamp_AnalyseImage(pTexture->pPixels, pTexture->iWidth, pTexture->iHeight, 32);
}
LPCSTR DStamp_ReadImage(byte *pPixels, int iWidth, int iHeight, int iPlanes)
{
CWaitCursor wait;
LPCSTR psMessage = NULL;
if (iPlanes == 24 || iPlanes == 32)
{
DStampImage_t Image;
Image.pPixels = pPixels;
Image.iWidth = iWidth;
Image.iHeight = iHeight;
Image.iPlanes = iPlanes;
DStampData_t Data;
Data.pImage = &Image;
Data.pWatermark = &TheWatermark;
if (1)
{
int iInstances_Across = Data.pImage->iWidth / iDSTAMP_INSTANCE_PIXDIM;
int iInstances_Down = Data.pImage->iHeight / iDSTAMP_INSTANCE_PIXDIM;
// #ifdef _DEBUG
// int iDebug_WaterMarkSize = sizeof(Watermark_t);
// int iDebug_InstancesTotal = iInstances_Across * iInstances_Down;
// #endif
/*
#define iDSTAMP_CELL_PIXDIM 16 // adjust this, higher = more secure but less stamps on picture
#define iDSTAMP_CELL_PIXELS (iDSTAMP_CELL_PIXDIM * iDSTAMP_CELL_PIXDIM)
#define iDSTAMP_INSTANCE_CELLDIM 8 // leave this alone at all times!
#define iDSTAMP_INSTANCE_PIXDIM (iDSTAMP_INSTANCE_CELLDIM * iDSTAMP_CELL_PIXDIM)
#define iDSTAMP_CHAR_BITS 7
*/
CProgressCtrl *pProgress = NULL;
if (((CModViewApp*)AfxGetApp())->m_pMainWnd)
{
pProgress = new CProgressCtrl;
bool bOK = !!pProgress->Create( WS_CHILD|WS_VISIBLE|PBS_SMOOTH, // DWORD dwStyle,
CRect(100,100,200,200), // const RECT& rect,
((CModViewApp*)AfxGetApp())->m_pMainWnd, // CWnd* pParentWnd,
1 // UINT nID
);
if (!bOK)
{
delete pProgress;
pProgress = NULL;
}
}
// the image may have been cropped, so we need to hunt for the signature at every pixel position...
//
int iYScans = 0;
for (int iLazy = 0; iLazy<2; iLazy++)
{
for (int iYStart = 0; iYStart < iDSTAMP_INSTANCE_PIXDIM && !psMessage; iYStart++)
{
if (iLazy)
{
if (pProgress)
{
pProgress->SetRange(0,iYScans);
}
OutputDebugString(va("iYStart %%%d\n",(iYStart*100)/iDSTAMP_INSTANCE_PIXDIM));
if (pProgress)
{
pProgress->SetPos(iYStart);
// wait.Restore();
}
for (int iXStart = 0; iXStart < iDSTAMP_INSTANCE_PIXDIM && !psMessage; iXStart++)
{
// look for some stamps here...
//
for (int iInstanceY = 0; iInstanceY < iInstances_Down && !psMessage; iInstanceY++)
{
for (int iInstanceX = 0; iInstanceX < iInstances_Across && !psMessage; iInstanceX++)
{
int iInstancePixelX = (iInstanceX * iDSTAMP_INSTANCE_PIXDIM) + iXStart;
int iInstancePixelY = (iInstanceY * iDSTAMP_INSTANCE_PIXDIM) + iYStart;
if (iInstancePixelX + iDSTAMP_INSTANCE_PIXDIM >= iWidth
||
iInstancePixelY + iDSTAMP_INSTANCE_PIXDIM >= iHeight
)
{
// ... then skip this position while hunting for header start
}
else
{
psMessage = DStamp_ReadInstance(&Data, iInstancePixelX, iInstancePixelY);
}
}
}
}
}
else
{
for (int iInstanceY = 0; iInstanceY < iInstances_Down; iInstanceY++)
{
int iInstancePixelY = (iInstanceY * iDSTAMP_INSTANCE_PIXDIM) + iYStart;
if (iInstancePixelY + iDSTAMP_INSTANCE_PIXDIM >= iHeight)
{
}
else
{
iYScans++;
}
}
}
}
}
if (pProgress)
{
delete pProgress;
pProgress = 0;
}
}
}
else
{
ErrorBox("DStamp_ReadImage(): Supplied image must be 24 or 32 bit");
}
return psMessage;
}
////////////////// eof ////////////////