📄 kmphoto.c
字号:
/*____________________________________________________________________________
Copyright (C) 1998 Network Associates, Inc.
All rights reserved.
KMPhoto.c - photoID routines
$Id: KMPhoto.c,v 1.16 1998/08/11 14:43:35 pbj Exp $
____________________________________________________________________________*/
#include "pgpPFLConfig.h"
// project header files
#include "pgpkmx.h"
// pgp header files
#include "pgpJPEG.h"
#include "pgpClientShared.h"
#include "pgpEndianConversion.h"
// external global variables
extern HINSTANCE g_hInst;
// constant definitions
#define DISPLAY_WIDTH 120
#define MAX_FILE_WIDTH 1000
#define MAX_FILE_HEIGHT 1200
#define MAX_PHOTO_WIDTH 120
#define MAX_PHOTO_HEIGHT 144
// error handler struct for JPEG library
struct my_error_mgr {
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
};
typedef struct my_error_mgr * my_error_ptr;
// ___________________________________________________
//
// extract size information from DIB
INT
KMGetDIBSize (LPBITMAPINFO lpbi, INT* piWidth, INT* piHeight)
{
INT iRowSize;
INT iDIBSize;
// return image dimensions
if (piWidth)
*piWidth = lpbi->bmiHeader.biWidth;
if (piHeight)
*piHeight = lpbi->bmiHeader.biHeight;
// rows length must be a multiple of sizeof(LONG)
iRowSize = (lpbi->bmiHeader.biWidth * lpbi->bmiHeader.biBitCount) >>3;
iRowSize = ((iRowSize+3)>>2)<<2;
// calculate image size by multiplying row length by number of rows
// and adding in header and color table sizes
iDIBSize = lpbi->bmiHeader.biSize;
iDIBSize += lpbi->bmiHeader.biClrUsed * sizeof(RGBQUAD);
iDIBSize += iRowSize * lpbi->bmiHeader.biHeight;
return iDIBSize;
}
// ___________________________________________________
//
// create logical palette from bitmap color table
static HPALETTE
sPaletteFromDIB (
LPBITMAPINFO lpbmi,
INT* piNumColors)
{
HPALETTE hPal = NULL;
LPBITMAPINFOHEADER lpbi;
LPLOGPALETTE lpPal;
HANDLE hLogPal;
INT i;
lpbi = (LPBITMAPINFOHEADER)lpbmi;
// palettes are only used on images with 8 bits/pixel or less
switch (lpbi->biBitCount) {
case 1 :
*piNumColors = 2;
break;
case 4 :
*piNumColors = 16;
break;
case 8 :
if (lpbi->biClrUsed)
*piNumColors = lpbi->biClrUsed;
else
*piNumColors = 256;
break;
default :
*piNumColors = 0;
break;
}
// if a palette is indicated, extract it from bitmap color table
if (*piNumColors) {
hLogPal = GlobalAlloc (GHND, sizeof (LOGPALETTE) +
sizeof (PALETTEENTRY) * (*piNumColors));
lpPal = (LPLOGPALETTE) GlobalLock (hLogPal);
lpPal->palVersion = 0x300;
lpPal->palNumEntries = *piNumColors;
for (i=0; i<*piNumColors; i++) {
lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed;
lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;
lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue;
lpPal->palPalEntry[i].peFlags = 0;
}
hPal = CreatePalette (lpPal);
GlobalUnlock (hLogPal);
GlobalFree (hLogPal);
}
return hPal;
}
// ___________________________________________________
//
// derive DDB and palette from DIB
HBITMAP
KMDDBfromDIB (
LPBITMAPINFO lpbi,
HPALETTE* lphPalette)
{
HBITMAP hBitmapFinal = NULL;
HDC hdc;
INT iNumColors;
LPVOID lpPixels;
hdc = GetDC (NULL);
*lphPalette = NULL;
iNumColors = 0;
if (GetDeviceCaps (hdc, RASTERCAPS) & RC_PALETTE)
*lphPalette = sPaletteFromDIB ((LPBITMAPINFO)lpbi, &iNumColors);
if (*lphPalette) {
SelectPalette (hdc, *lphPalette, FALSE);
RealizePalette (hdc);
}
lpPixels = (LPBYTE)lpbi +
lpbi->bmiHeader.biSize +
(iNumColors * sizeof(RGBQUAD));
hBitmapFinal = CreateDIBitmap (hdc,
&(lpbi->bmiHeader),
CBM_INIT,
lpPixels,
lpbi,
DIB_RGB_COLORS);
ReleaseDC (NULL, hdc);
return (hBitmapFinal);
}
// ___________________________________________________
//
// error handler routine for JPEG library
//
// converts error code to string and displays it in MessageBox
METHODDEF(void)
my_error_exit (j_common_ptr cinfo)
{
// CHAR szError [JMSG_LENGTH_MAX];
my_error_ptr myerr = (my_error_ptr) cinfo->err;
// (*cinfo->err->format_message) (cinfo, szError);
// MessageBox (NULL, szError, "JPEG Library Error", MB_OK);
//
longjmp(myerr->setjmp_buffer, 1);
}
// ___________________________________________________
//
// convert DIB to JPEG buffer
static PGPError
sJPEGFromDIB (
LPBITMAPINFO lpbmi,
INT iQuality,
INT iMaxWidth,
INT iMaxHeight,
BOOL bShrink,
LPBYTE* pbuf,
INT* piLength)
{
PGPError err = kPGPError_NoErr;
INT iColorTableLength;
INT iRowOrigLen, iRowJPEGLen, iRowDIBLen, iDIBsize;
INT i, j, index;
INT iWidth, iHeight, iZoom;
INT idxX, idxY;
struct my_error_mgr jerr;
struct jpeg_compress_struct cinfo;
FILE* outfile;
LPBYTE pDIB;
LPBYTE pRGBorig;
LPBYTE pRGBjpeg;
JSAMPROW pSampRow[1];
double fZoom, fImageRatio, fMaxRatio, fTemp;
// do we really need to shrink image ?
fZoom = 1.0;
iZoom = 1000;
iWidth = lpbmi->bmiHeader.biWidth;
iHeight = lpbmi->bmiHeader.biHeight;
if (bShrink) {
if ((lpbmi->bmiHeader.biWidth > iMaxWidth) ||
(lpbmi->bmiHeader.biHeight > iMaxHeight)) {
fImageRatio = (double)lpbmi->bmiHeader.biWidth /
(double)lpbmi->bmiHeader.biHeight;
fMaxRatio = (double)iMaxWidth / (double)iMaxHeight;
if (fImageRatio >= fMaxRatio) {
fZoom = (double)iMaxWidth /
(double)lpbmi->bmiHeader.biWidth;
fTemp = (1000.0 / fZoom);
iWidth = iMaxWidth;
iHeight = (INT)(lpbmi->bmiHeader.biHeight * fZoom);
iZoom = (INT)fTemp;
}
else {
fZoom = (double)iMaxHeight /
(double)lpbmi->bmiHeader.biHeight;
fTemp = (1000.0 / fZoom);
iHeight = iMaxHeight;
iWidth = (INT)(lpbmi->bmiHeader.biWidth * fZoom);
iZoom = (INT)fTemp;
}
}
}
// calculate length of row of image in bytes (3 color channels)
iRowOrigLen = lpbmi->bmiHeader.biWidth * 3;
iRowJPEGLen = (iWidth+1) * 3;
// calculate length of row of image in DIB structure
iRowDIBLen = (lpbmi->bmiHeader.biWidth * lpbmi->bmiHeader.biBitCount) >>3;
iRowDIBLen = ((iRowDIBLen+3)>>2)<<2;
// allocate buffer used for passing rows of RGB data into library
pRGBorig = KMAlloc (iRowOrigLen);
if (pRGBorig == NULL)
return kPGPError_OutOfMemory;
pRGBjpeg = KMAlloc (iRowJPEGLen);
if (pRGBjpeg == NULL)
return kPGPError_OutOfMemory;
// calculate size of DIB structure
iColorTableLength = lpbmi->bmiHeader.biClrUsed;
if (iColorTableLength == 0) {
switch (lpbmi->bmiHeader.biBitCount) {
case 1 :
iColorTableLength = 2;
break;
case 4 :
iColorTableLength = 16;
break;
case 8 :
iColorTableLength = 256;
break;
default :
iColorTableLength = 0;
break;
}
}
iDIBsize = sizeof(BITMAPINFOHEADER);
iDIBsize += (iColorTableLength * sizeof (RGBQUAD));
iDIBsize += (iRowDIBLen * lpbmi->bmiHeader.biHeight);
// initialize pointer to last row of DIB (DIB is stored bottom-up)
pDIB = (LPBYTE)lpbmi;
pDIB += iDIBsize;
pDIB -= iRowDIBLen;
// JPEG library will write to temporary file
outfile = tmpfile ();
// setup error handler for JPEG library
cinfo.err = jpeg_std_error (&jerr.pub);
jerr.pub.error_exit = my_error_exit;
if (setjmp(jerr.setjmp_buffer)) {
// will be here only on error in library
jpeg_destroy_compress (&cinfo);
fclose (outfile);
_rmtmp ();
return kPGPError_Win32_InvalidImage;
}
// initialize compression structure
jpeg_create_compress (&cinfo);
// specify destination of JPEG stream
jpeg_stdio_dest (&cinfo, outfile);
// specify image characteristics
cinfo.image_width = iWidth;
cinfo.image_height = iHeight;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults (&cinfo);
// specify quality of compressed image
jpeg_set_quality (&cinfo, iQuality, TRUE);
// startup compression
jpeg_start_compress (&cinfo, TRUE);
pSampRow[0] = pRGBjpeg;
idxY = 0;
while (cinfo.next_scanline < cinfo.image_height) {
// fill buffer of data on basis of number of bits/pixel
switch (lpbmi->bmiHeader.biBitCount) {
case 1 :
// B/W image
for (j=i=0; i<iRowOrigLen; i+=3) {
index = pDIB [j>>3];
index = (index >> (7 - (j&0x07))) & 0x01;
j++;
pRGBorig[i+0] = lpbmi->bmiColors[index].rgbRed;
pRGBorig[i+1] = lpbmi->bmiColors[index].rgbGreen;
pRGBorig[i+2] = lpbmi->bmiColors[index].rgbBlue;
}
break;
case 4 :
// 16 color image, derive RGB values from color table
for (j=i=0; i<iRowOrigLen; i+=3) {
if (j & 0x1)
index = pDIB [j>>1] & 0x0F;
else
index = pDIB [j>>1] >> 4;
j++;
pRGBorig[i+0] = lpbmi->bmiColors[index].rgbRed;
pRGBorig[i+1] = lpbmi->bmiColors[index].rgbGreen;
pRGBorig[i+2] = lpbmi->bmiColors[index].rgbBlue;
}
break;
case 8 :
// 256 color image, derive RGB values from color table
for (j=i=0; i<iRowOrigLen; i+=3) {
index = pDIB[j++];
pRGBorig[i+0] = lpbmi->bmiColors[index].rgbRed;
pRGBorig[i+1] = lpbmi->bmiColors[index].rgbGreen;
pRGBorig[i+2] = lpbmi->bmiColors[index].rgbBlue;
}
break;
case 24 :
// RGB image, but DIB stores it as BGR, so invert
for (i=0; i<iRowOrigLen; i+=3) {
pRGBorig[i+0] = pDIB[i+2];
pRGBorig[i+1] = pDIB[i+1];
pRGBorig[i+2] = pDIB[i+0];
}
break;
case 32 :
// RGB image, but in DIB it's 0BGR, so invert and discard byte
for (i=j=0; i<iRowOrigLen; i+=3) {
pRGBorig[i+0] = pDIB[j+3];
pRGBorig[i+1] = pDIB[j+2];
pRGBorig[i+2] = pDIB[j+1];
j += 4;
}
break;
}
// subsample the row of data
idxX = 0;
for (i=j=0; j<iRowOrigLen; j+=3) {
idxX -= 1000;
while (idxX < 0) {
pRGBjpeg[i+0] = pRGBorig[j+0];
pRGBjpeg[i+1] = pRGBorig[j+1];
pRGBjpeg[i+2] = pRGBorig[j+2];
i += 3;
idxX += iZoom;
}
}
// pass the RGB data into the library
(void) jpeg_write_scanlines (&cinfo, pSampRow, 1);
// step to previous DIB scan line
idxY += iZoom;
while (idxY > 0) {
pDIB -= iRowDIBLen;
idxY -= 1000;
}
}
// done with image
jpeg_finish_compress (&cinfo);
jpeg_destroy_compress (&cinfo);
KMFree (pRGBorig);
KMFree (pRGBjpeg);
// now extract JPEG data from file -- first calculate buffer length
fseek (outfile, 0, SEEK_END);
*piLength = ftell (outfile);
// allocate buffer
*pbuf = KMAlloc (*piLength);
// read data from file into buffer
if (*pbuf != NULL) {
rewind (outfile);
fread (*pbuf, 1, *piLength, outfile);
}
// memory allocation error
else
err = kPGPError_OutOfMemory;
fclose (outfile);
_rmtmp ();
return err;
}
// ___________________________________________________
//
// convert DIB to PhotoID buffer
static PGPError
sPhotoFromDIB (
LPBITMAPINFO lpbmi,
INT iMaxWidth,
INT iMaxHeight,
BOOL bShrink,
LPBYTE* pbuf,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -