📄 imagefile.cpp
字号:
//////////////////////////////////////////////////////
//
// NRDB Pro - Spatial database and mapping application
//
// Copyright (c) 1989-2004 Richard D. Alexander
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// NRDB Pro is part of the Natural Resources Database Project
//
// Homepage: http://www.nrdb.co.uk/
// Users' Forum: http://nrdb.mypalawan.info/
//
#include "stdafx.h"
#include "nrdb.h"
#include "include\jpegfile.h"
#include "include\png.h"
#include "dlgprogress.h"
#include "ImageFile.h"
#include "viewmap.h"
#include "projctns.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
/////////////////////////////////////////////////////////////////////////////
//
// compress function is exported as _compress@16, however the zlib.h defines
// it as _compress therefore need to define elsewhere!
//
extern int _stdcall compressZ(BYTE *dest, ULONG *destLen, const BYTE *source, ULONG sourceLen);
extern int _stdcall uncompressZ (BYTE *dest, ULONG *destLen, const BYTE *source, ULONG sourceLen);
/////////////////////////////////////////////////////////////////////////////
void inline write(CByteArray& aData, int n)
{
int nLength= aData.GetSize();
aData.SetSize(nLength + sizeof(n));
memcpy(&aData[nLength], &n, sizeof(n));
}
void inline write(CByteArray& aData, double n)
{
int nLength= aData.GetSize();
aData.SetSize(nLength + sizeof(n));
memcpy(&aData[nLength], &n, sizeof(n));
}
/////////////////////////////////////////////////////////////////////////////
DWORD WaitProcess(HWND hWnd, HANDLE handle);
//////////////////////////////////////////////////////////////////////
//
// Exception handling for PNG images
//
static png_structp png_ptr = NULL;
static png_infop info_ptr = NULL;
static void
png_cexcept_error(png_structp png_ptr, png_const_charp msg)
{
throw msg;
}
//////////////////////////////////////////////////////////////////////
//
// Construction/Destruction
CImageFile::CImageFile()
{
m_pFile = NULL;
m_nWaterColor = 1;
m_pDC = NULL;
m_pBitmap1 = NULL;
m_pBitmap2 = NULL;
m_pDCMask = NULL;
m_bTransparent = FALSE;
}
///////////////////////////////////////////////////////////////////////////////
//
// Copy constructor necessary for custom symbols
CImageFile::CImageFile(CImageFile& rSrc)
{
*this = rSrc;
}
CImageFile& CImageFile::operator =(CImageFile& rSrc)
{
m_buffer = rSrc.m_buffer;
m_pFile = NULL;
m_bChanged = FALSE;
m_nWaterColor = 1;
m_pDC = FALSE;
m_pDCMask = FALSE;
m_pBitmap1 = FALSE;
m_pBitmap2 = FALSE;
//m_georef = rSrc.m_georef;
return *this;
};
///////////////////////////////////////////////////////////////////////////////
CImageFile::~CImageFile()
{
Close();
}
/////////////////////////////////////////////////////////////////////////////
// CImageDoc construction/destruction
Buffer::Buffer()
{
width = height = 0;
flags = 0;
image = NULL;
nChannels = 0;
}
///////////////////////////////////////////////////////////////////////////////
//
// Converts an image to a long binary for storing in the database
//
BOOL CImageFile::Open(LPCTSTR lpszPathName, int nFlag, HWND hWnd)
{
BOOL bOK = TRUE;
if (hWnd == NULL) hWnd = GetFocus();
// Tidy up from previous
Close();
m_bTransparent = nFlag & Transparent;
// Load data
AfxGetApp()->BeginWaitCursor();
// Open jpeg files
if (stricmp(lpszPathName+strlen(lpszPathName)-4,".jpg") == 0 ||
stricmp(lpszPathName+strlen(lpszPathName)-4,".png") ==0)
{
if (stricmp(lpszPathName+strlen(lpszPathName)-4,".jpg") == 0)
{
m_buffer.image = JpegFile::JpegFileToRGB(lpszPathName, (UINT*)&m_buffer.width,
(UINT*)&m_buffer.height);
m_buffer.flags = IMG_JPG;
m_buffer.nChannels = 3;
} else
{
bOK = PNGFileToRGB(lpszPathName, &m_buffer.width, &m_buffer.height, m_buffer.image);
m_buffer.flags = IMG_PNG;
}
// Now retrieve corresponding georeference coordinates if any
// If retrieving map from .nrm file then only display the georeference
// utility if not previously georeferenced
if (nFlag & GeoRef && (!m_georef.Load(lpszPathName) ||
m_georef.m_aPoints.GetSize() < 2))
{
// If image has not been georeferenced then run Image2Shp to allow
// user opportunity
CString sPath = BDGetAppPath();
if (sPath.Right(1) != "\\") sPath += "\\";
sPath += "Image2Shp.exe \"" + CString(lpszPathName) + "\" ";
// Disable window whilst Image2Shp is open to prevent
// user from closing dialog
CWnd::FromHandle(hWnd)->EnableWindow(FALSE);
// Now spawn the application
PROCESS_INFORMATION proc = {0};
STARTUPINFO start = {0};
int ret;
// Initialize the STARTUPINFO structure:
start.cb = sizeof (start);
start.wShowWindow = SW_SHOWNORMAL;
// Start the shelled application:
ret = CreateProcess(0, (LPSTR)(LPCSTR)sPath, 0, 0, TRUE,
NORMAL_PRIORITY_CLASS, 0, 0, &start, &proc);
if (ret)
{
DWORD dw = WaitProcess(AfxGetMainWnd()->GetSafeHwnd(), proc.hProcess);
// dw == 0 on error
}
CWnd::FromHandle(hWnd)->EnableWindow(TRUE);
SetFocus(hWnd);
// Now attempt to load the georeferences again
m_georef.Load(lpszPathName);
};
// Need to convert parameters from lat/long if necessary before
// georefercing
// Determine if points are in lat/long or x,y
BOOL bLatLon = TRUE;
CArray <CGeoPoint,CGeoPoint>& geopoints = m_georef.m_aPoints;
for (int i = 0; i < geopoints.GetSize(); i++)
{
if (geopoints[i].m_dWX < -180 || geopoints[i].m_dWX > 180 ||
geopoints[i].m_dWY < -90 || geopoints[i].m_dWY > 90)
{
bLatLon = FALSE;
break;
}
}
// If latitude/longitude then convert to x,y
if (bLatLon)
{
for (int i = 0; i < geopoints.GetSize(); i++)
{
long x,y;
BDProjection()->LatLonToTransMercator(geopoints[i].m_dWY, geopoints[i].m_dWX, &x,&y);
geopoints[i].m_dWX = x;
geopoints[i].m_dWY = y;
}
}
// Calcualate georeference
m_georef.Initialise(m_buffer.width, m_buffer.height);
bOK &= m_buffer.image != NULL;
}
AfxGetApp()->EndWaitCursor();
// Quit if no file selected
return bOK;
}
/////////////////////////////////////////////////////////////////////////////
//
// Load PNG image and save to buffer
//
BOOL CImageFile::PNGFileToRGB(LPCSTR pstrFileName, int* piWidth, int* piHeight, BYTE*& pbImageData)
{
static FILE *pfFile;
png_byte pbSig[8];
int iBitDepth;
int iColorType;
double dGamma;
png_color_16 *pBackground;
png_uint_32 ulChannels;
png_uint_32 ulRowBytes;
int i;
png_bytepp pbRowPointers = NULL;
// open the PNG input file
if (!pstrFileName)
{
pbImageData = NULL;
return FALSE;
}
if (!(pfFile = fopen(pstrFileName, "rb")))
{
pbImageData = NULL;
return FALSE;
}
// first check the eight byte PNG signature
fread(pbSig, 1, 8, pfFile);
if (!png_check_sig(pbSig, 8))
{
pbImageData = NULL;
return FALSE;
}
// create the two png(-info) structures
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
(png_error_ptr)png_cexcept_error, (png_error_ptr)NULL);
if (!png_ptr)
{
pbImageData = NULL;
return FALSE;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_read_struct(&png_ptr, NULL, NULL);
pbImageData = NULL;
return FALSE;
}
try
{
// initialize the png structure
png_init_io(png_ptr, pfFile);
png_set_sig_bytes(png_ptr, 8);
// read all PNG info up to image data
png_read_info(png_ptr, info_ptr);
// get width, height, bit-depth and color-type
png_get_IHDR(png_ptr, info_ptr, (unsigned long*)piWidth, (unsigned long*)piHeight, &iBitDepth,
&iColorType, NULL, NULL, NULL);
// expand images of all color-type and bit-depth to 3x8 bit RGB images
// let the library process things like alpha, transparency, background
if (iBitDepth == 16)
png_set_strip_16(png_ptr);
if (iColorType == PNG_COLOR_TYPE_PALETTE)
png_set_expand(png_ptr);
if (iBitDepth < 8)
png_set_expand(png_ptr);
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_expand(png_ptr);
if (iColorType == PNG_COLOR_TYPE_GRAY ||
iColorType == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
// set the background color to draw transparent and alpha images over.
if (png_get_bKGD(png_ptr, info_ptr, &pBackground))
{
png_set_background(png_ptr, pBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
}
// if required set gamma conversion
if (png_get_gAMA(png_ptr, info_ptr, &dGamma))
png_set_gamma(png_ptr, (double) 2.2, dGamma);
// after the transformations have been registered update info_ptr data
png_read_update_info(png_ptr, info_ptr);
// get again width, height and the new bit-depth and color-type
png_get_IHDR(png_ptr, info_ptr, (unsigned long*)piWidth, (unsigned long*)piHeight, &iBitDepth,
&iColorType, NULL, NULL, NULL);
// row_bytes is the width x number of channels
ulRowBytes = png_get_rowbytes(png_ptr, info_ptr);
ulChannels = png_get_channels(png_ptr, info_ptr);
m_buffer.nChannels = ulChannels;
// now we can allocate memory to store the image
if (pbImageData)
{
delete [] pbImageData;
pbImageData = NULL;
}
pbImageData = new png_byte[ulRowBytes * (*piHeight)
* sizeof(png_byte)];
if (pbImageData == NULL)
{
png_error(png_ptr, "Visual PNG: out of memory");
}
// and allocate memory for an array of row-pointers
if ((pbRowPointers = (png_bytepp) malloc((*piHeight)
* sizeof(png_bytep))) == NULL)
{
png_error(png_ptr, "Visual PNG: out of memory");
}
// set the individual row-pointers to point at the correct offsets
for (i = 0; i < (*piHeight); i++)
pbRowPointers[i] = pbImageData + i * ulRowBytes;
// now we can go ahead and just read the whole image
png_read_image(png_ptr, pbRowPointers);
// read the additional chunks in the PNG file (not really needed)
png_read_end(png_ptr, NULL);
// and we're done
free (pbRowPointers);
pbRowPointers = NULL;
}
catch (png_const_charp)
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
pbImageData = NULL;
if(pbRowPointers)
free (pbRowPointers);
fclose(pfFile);
return FALSE;
}
fclose (pfFile);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
//
// Save a PNG file
//
BOOL CImageFile::RGBToPNGFile(LPCSTR pstrFileName, BOOL bColour)
{
const int ciBitDepth = 8;
static FILE *pfFile;
png_uint_32 ulRowBytes;
static png_byte **ppbRowPointers = NULL;
int i;
// Set parameters
int iWidth = m_buffer.width;
int iHeight = m_buffer.height;
png_byte *pDiData = m_buffer.image;
int ciChannels = m_buffer.nChannels;
// open the PNG output file
if (!pstrFileName)
return FALSE;
if (!(pfFile = fopen(pstrFileName, "wb")))
return FALSE;
// prepare the standard PNG structures
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
(png_error_ptr)png_cexcept_error, (png_error_ptr)NULL);
if (!png_ptr)
{
fclose(pfFile);
return FALSE;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
fclose(pfFile);
png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
return FALSE;
}
try
{
// initialize the png structure
png_init_io(png_ptr, pfFile);
// we're going to write a very simple 3x8 bit RGB image
png_set_IHDR(png_ptr, info_ptr, iWidth, iHeight, ciBitDepth,
PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_BASE);
// write the file header information
png_write_info(png_ptr, info_ptr);
// row_bytes is the width x number of channels
ulRowBytes = iWidth * ciChannels;
// we can allocate memory for an array of row-pointers
if ((ppbRowPointers = (png_bytepp) malloc(iHeight * sizeof(png_bytep))) == NULL)
throw "Visualpng: Out of memory";
// set the individual row-pointers to point at the correct offsets
for (i = 0; i < iHeight; i++)
ppbRowPointers[i] = pDiData + i * (((ulRowBytes + 3) >> 2) << 2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -