📄 kmphoto.c
字号:
INT* piLength)
{
PGPError err;
LPBYTE pJPEGbuf;
INT iJPEGlen;
PGPPhotoUserIDHeader* pheader;
LPBYTE pdata;
PGPUInt16 usHeaderLength;
// currently we only support JPEG photoids
err = sJPEGFromDIB (lpbmi, kPGPDefaultJPEQQuality,
iMaxWidth, iMaxHeight, bShrink, &pJPEGbuf, &iJPEGlen);
if (IsntPGPError (err)) {
*piLength = iJPEGlen + sizeof(PGPPhotoUserIDHeader);
*pbuf = KMAlloc (*piLength);
if (*pbuf) {
pheader = (PGPPhotoUserIDHeader*)*pbuf;
usHeaderLength = sizeof(PGPPhotoUserIDHeader);
PGPUInt16ToStorage (usHeaderLength,
(PGPByte*)&(pheader->headerLength));
pheader->headerVersion = kPGPPhotoIDHeaderVersion;
pheader->photoIDFormat = kPGPPhotoIDFormat_JPEG;
pdata = *pbuf + usHeaderLength;
memcpy (pdata, pJPEGbuf, iJPEGlen);
}
else {
*piLength = 0;
err = kPGPError_OutOfMemory;
}
}
return err;
}
// ___________________________________________________
//
// convert JPEG buffer to DIB
static LPBITMAPINFO
sDIBfromJPEGFile (
FILE* infile,
BOOL bForDisplay)
{
LPBITMAPINFO lpbmi = NULL;
INT i, iNumBits, iDIBsize;
INT iRowDataLen, iRowDIBLen;
struct my_error_mgr jerr;
struct jpeg_decompress_struct cinfo;
HDC hdc;
JSAMPARRAY buffer;
JSAMPROW pSamp;
LPBYTE pDIB;
BOOL bQuantize;
// get pixel depth supported by the current display device
hdc = GetDC (NULL);
iNumBits = GetDeviceCaps (hdc, BITSPIXEL) * GetDeviceCaps (hdc, PLANES);
ReleaseDC (NULL, hdc);
// quantize colors only if a 256 color display
// if more than 256, display is RGB and quantization is not needed
// if less than 256, quantization does no good as system palette will
// be used regardless
if (bForDisplay && (iNumBits == 8)) bQuantize = TRUE;
else bQuantize = FALSE;
// prepare error handling structure for JPEG library
cinfo.err = jpeg_std_error (&jerr.pub);
jerr.pub.error_exit = my_error_exit;
if (setjmp(jerr.setjmp_buffer)) {
// here only when JPEG library encounters an error
jpeg_destroy_decompress (&cinfo);
return NULL;
}
// initialize decompression structure
jpeg_create_decompress (&cinfo);
// identify source of JPEG data as input file
jpeg_stdio_src (&cinfo, infile);
// load header data from file
(void) jpeg_read_header (&cinfo, TRUE);
// set scaling factor for decompression
if (bForDisplay) {
cinfo.scale_num = 1;
if (cinfo.image_width > 4*DISPLAY_WIDTH)
cinfo.scale_denom = 8;
else if (cinfo.image_width > 2*DISPLAY_WIDTH)
cinfo.scale_denom = 4;
else if (cinfo.image_width > 1*DISPLAY_WIDTH)
cinfo.scale_denom = 2;
else
cinfo.scale_denom = 1;
}
else {
cinfo.scale_num = 1;
cinfo.scale_denom = 1;
}
// set decompression parameters
if (bQuantize) {
cinfo.quantize_colors = TRUE;
cinfo.two_pass_quantize = TRUE;
cinfo.dither_mode = JDITHER_FS;
cinfo.desired_number_of_colors = 128;
}
else {
cinfo.quantize_colors = FALSE;
}
// start decompression
(void) jpeg_start_decompress (&cinfo);
// calculate bitmap size parameters and set DIB header info
if (bQuantize) {
iRowDataLen = cinfo.output_width * 1;
iRowDIBLen = ((iRowDataLen+3)>>2)<<2;
iDIBsize = sizeof(BITMAPINFOHEADER);
iDIBsize += (cinfo.actual_number_of_colors * sizeof (RGBQUAD));
iDIBsize += (iRowDIBLen * cinfo.output_height);
lpbmi = KMAlloc (iDIBsize);
lpbmi->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
lpbmi->bmiHeader.biWidth = cinfo.output_width;
lpbmi->bmiHeader.biHeight = cinfo.output_height;
lpbmi->bmiHeader.biPlanes = 1;
lpbmi->bmiHeader.biBitCount = 8;
lpbmi->bmiHeader.biCompression = BI_RGB;
lpbmi->bmiHeader.biSizeImage = iRowDIBLen * cinfo.output_height;
lpbmi->bmiHeader.biClrUsed = cinfo.actual_number_of_colors;
lpbmi->bmiHeader.biClrImportant = cinfo.actual_number_of_colors;
}
else {
iRowDataLen = cinfo.output_width * 3;
iRowDIBLen = ((iRowDataLen+3)>>2)<<2;
iDIBsize = sizeof(BITMAPINFOHEADER);
iDIBsize += (iRowDIBLen * cinfo.output_height);
lpbmi = KMAlloc (iDIBsize);
lpbmi->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
lpbmi->bmiHeader.biWidth = cinfo.output_width;
lpbmi->bmiHeader.biHeight = cinfo.output_height;
lpbmi->bmiHeader.biPlanes = 1;
lpbmi->bmiHeader.biBitCount = 24;
lpbmi->bmiHeader.biCompression = BI_RGB;
lpbmi->bmiHeader.biSizeImage = iRowDIBLen * cinfo.output_height;
lpbmi->bmiHeader.biClrUsed = 0;
lpbmi->bmiHeader.biClrImportant = 0;
}
// have JPEG library allocate buffer for data output
buffer = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo, JPOOL_IMAGE, iRowDataLen, 1);
// put color table into DIB
if (bQuantize) {
pSamp = cinfo.colormap[0];
for (i = 0; i < cinfo.actual_number_of_colors; i++)
lpbmi->bmiColors[i].rgbRed = pSamp[i];
pSamp = cinfo.colormap[1];
for (i = 0; i < cinfo.actual_number_of_colors; i++)
lpbmi->bmiColors[i].rgbGreen = pSamp[i];
pSamp = cinfo.colormap[2];
for (i = 0; i < cinfo.actual_number_of_colors; i++)
lpbmi->bmiColors[i].rgbBlue = pSamp[i];
}
// initialize pointer to last scan row of DIB (DIB is bottom-up)
pDIB = (LPBYTE)lpbmi;
pDIB += iDIBsize;
pDIB -= iRowDIBLen;
// decompress the image, one line at a time
while (cinfo.output_scanline < cinfo.output_height) {
(void) jpeg_read_scanlines (&cinfo, buffer, 1);
// if quantized, just store the colormap index in the DIB
if (bQuantize) {
pSamp = buffer[0];
for (i=0; i<iRowDataLen; i++) {
pDIB[i] = pSamp[i];
}
}
// otherwise data is RGB, but DIB are in BGR order, so invert
else {
pSamp = buffer[0];
for (i=0; i<iRowDataLen; i+=3) {
pDIB[i+2] = pSamp[i+0];
pDIB[i+1] = pSamp[i+1];
pDIB[i+0] = pSamp[i+2];
}
}
// step to previous row
pDIB -= iRowDIBLen;
}
// finished decompressing
jpeg_finish_decompress (&cinfo);
jpeg_destroy_decompress (&cinfo);
return lpbmi;
}
// ___________________________________________________
//
// convert JPEG buffer to DIB
static LPBITMAPINFO
sDIBfromJPEGBuffer (
LPBYTE buf,
INT isize,
BOOL bForDisplay)
{
LPBITMAPINFO lpbmi = NULL;
FILE* infile;
// write JPEG data to temp file for library to read from
infile = tmpfile ();
fwrite (buf, 1, isize, infile);
rewind (infile);
// convert the file
lpbmi = sDIBfromJPEGFile (infile, bForDisplay);
// close and delete temporary file
fclose (infile);
_rmtmp ();
return lpbmi;
}
// ___________________________________________________
//
// convert PhotoID buffer to DIB
PGPError
KMDIBfromPhoto (
LPBYTE buf,
INT isize,
BOOL bForDisplay,
LPBITMAPINFO* plpbmi)
{
PGPError err = kPGPError_NoErr;
PGPPhotoUserIDHeader* pheader;
LPBYTE pdata;
PGPUInt16 usHeaderLength;
if (!plpbmi) return kPGPError_BadParams;
*plpbmi = NULL;
pheader = (PGPPhotoUserIDHeader*)buf;
if (pheader->headerVersion != kPGPPhotoIDHeaderVersion)
err = kPGPError_BadParams;
else {
switch (pheader->photoIDFormat) {
case kPGPPhotoIDFormat_JPEG :
usHeaderLength =
PGPStorageToUInt16 ((PGPByte*)&pheader->headerLength);
pdata = buf + usHeaderLength;
*plpbmi = sDIBfromJPEGBuffer (pdata,
isize - usHeaderLength, bForDisplay);
break;
default :
err = kPGPError_BadParams;
}
}
return err;
}
// ___________________________________________________
//
// copy PhotoID buffer to clipboard in DIB format
PGPError
KMCopyPhotoToClipboard (HWND hWnd, LPBYTE buf, INT isize)
{
PGPError err;
LPBITMAPINFO lpbmi;
HANDLE hMem;
LPBYTE pMem;
INT iDIBsize;
err = KMDIBfromPhoto (buf, isize, FALSE, &lpbmi);
if (IsntPGPError (err)) {
iDIBsize = KMGetDIBSize (lpbmi, NULL, NULL);
hMem = GlobalAlloc (GMEM_MOVEABLE|GMEM_DDESHARE, iDIBsize);
pMem = GlobalLock (hMem);
CopyMemory (pMem, lpbmi, iDIBsize);
GlobalUnlock (hMem);
OpenClipboard (hWnd);
SetClipboardData (CF_DIB, hMem);
CloseClipboard ();
KMFree (lpbmi);
}
return err;
}
// ___________________________________________________
//
// paste data in clipboard (DIB format) into JPEG buffer
PGPError
KMPastePhotoFromClipboard (HWND hWnd, LPBYTE* pbuf, INT* pisize)
{
HANDLE hMem;
LPBITMAPINFO lpbmi;
PGPError err;
if (OpenClipboard (hWnd)) {
hMem = GetClipboardData (CF_DIB);
lpbmi = (LPBITMAPINFO)GlobalLock (hMem);
err = sPhotoFromDIB (lpbmi, MAX_PHOTO_WIDTH,
MAX_PHOTO_HEIGHT, TRUE, pbuf, pisize);
GlobalUnlock (hMem);
CloseClipboard();
}
return err;
}
// ___________________________________________________
//
// read BMP file into PhotoID buffer
static PGPError
sReadPhotoFromBMPFile (
FILE* pfile,
LPBYTE* pbuf,
INT* pisize)
{
PGPError err = kPGPError_Win32_InvalidImage;
LPBYTE pfilebuf;
BITMAPFILEHEADER bmfh;
LPBITMAPINFO lpbmi;
ULONG ulMaxFileSize;
// read file header to get size of file
rewind (pfile);
if (fread (&bmfh, 1, sizeof(bmfh), pfile) != sizeof(bmfh))
return err;
// check for internal magic number and valid size
if ((bmfh.bfType != 0x4d42) || // 'BM'
(bmfh.bfSize < (sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFO)))) {
return err;
}
// check for giant files
ulMaxFileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFO);
ulMaxFileSize += 256*sizeof(RGBQUAD);
ulMaxFileSize += MAX_FILE_WIDTH*MAX_FILE_HEIGHT*4;
if (bmfh.bfSize > ulMaxFileSize) {
return kPGPError_Win32_ImageTooBig;
}
// allocate buffer to hold entire file
pfilebuf = KMAlloc (bmfh.bfSize);
if (!pfilebuf) {
return kPGPError_OutOfMemory;
}
// read the entire file into the buffer
rewind (pfile);
if (fread (pfilebuf, 1, bmfh.bfSize, pfile) != bmfh.bfSize)
return err;
// set the pointer to byte following file header
lpbmi = (LPBITMAPINFO)(pfilebuf + sizeof(bmfh));
// check for compressed images (not supported)
if (lpbmi->bmiHeader.biCompression != BI_RGB) {
KMFree (pfilebuf);
return err;
}
// convert
err = sPhotoFromDIB (lpbmi, MAX_PHOTO_WIDTH,
MAX_PHOTO_HEIGHT, TRUE, pbuf, pisize);
KMFree (pfilebuf);
return err;
}
// ___________________________________________________
//
// read JPEG file into PhotoID buffer
static PGPError
sReadPhotoFromJPEGFile (
FILE* pfile,
LPBYTE* pbuf,
INT* pisize)
{
PGPError err = kPGPError_Win32_InvalidImage;
LPBITMAPINFO lpbmi;
// convert the JPEG file to a BMP buffer
rewind (pfile);
lpbmi = sDIBfromJPEGFile (pfile, FALSE);
// convert to photoid format
if (lpbmi) {
err = sPhotoFromDIB (lpbmi, MAX_PHOTO_WIDTH,
MAX_PHOTO_HEIGHT, TRUE, pbuf, pisize);
}
return err;
}
// ___________________________________________________
//
// read image file into PhotoID buffer
PGPError
KMReadPhotoFromFile (
LPSTR pszFile,
LPBYTE* pbuf,
INT* pisize)
{
PGPError err = kPGPError_Win32_InvalidImage;
FILE* pfile;
pfile = fopen (pszFile, "rb");
if (pfile) {
// attempt to read file as a JPEG file
err = sReadPhotoFromJPEGFile (pfile, pbuf, pisize);
// if that didn't work, try it as a BMP file
if (IsPGPError (err)) {
err = sReadPhotoFromBMPFile (pfile, pbuf, pisize);
}
fclose (pfile);
}
return err;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -