mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-04-07 13:55:33 +08:00
ТОЛЬКО для windows систем, работа по unix/linux ЗАПРЕЩЕНА открытие будет только по наличию в системе длл - windowcodecs.dll (net 3.5) файл для теста Удивительная история рождения MS-Dos.docx git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@57778 954022d7-b5bf-4e40-9824-e11837661b57
3177 lines
191 KiB
C++
3177 lines
191 KiB
C++
|
||
|
||
// Здесь будут считываться метеданные
|
||
|
||
#pragma once
|
||
|
||
#include <XmlUtils.h>
|
||
#include <atlfile.h>
|
||
|
||
//#include <nmmintrin.h>
|
||
|
||
#include "../Common/ImageFileFormatChecker.h"
|
||
|
||
#pragma pack(push, 1)
|
||
struct TRational
|
||
{
|
||
int Fraction;
|
||
int Denominator;
|
||
};
|
||
struct TRationalU
|
||
{
|
||
unsigned int Fraction;
|
||
unsigned int Denominator;
|
||
};
|
||
#pragma pack(pop)
|
||
|
||
class CMetaData
|
||
{
|
||
|
||
public:
|
||
|
||
CMetaData()
|
||
{
|
||
Clear();
|
||
}
|
||
|
||
~CMetaData()
|
||
{
|
||
}
|
||
|
||
BOOL FromFile(const CStringW& strFilePath)
|
||
{
|
||
m_bMultiPageImage = FALSE;
|
||
|
||
CStringW wsFilePath( strFilePath );
|
||
|
||
const int c_nCountFileFormats = sizeof(tableSupportImageFormats) / sizeof(tableSupportImageFormats[0]);
|
||
|
||
_ImageFileFormats eFileType = tableSupportImageFormats[0].format;
|
||
|
||
int nPos = wsFilePath.ReverseFind( L'.' );
|
||
if( nPos > 0 )
|
||
{
|
||
CStringW sFileEx = wsFilePath.Right( wsFilePath.GetLength() - nPos - 1 );
|
||
sFileEx.MakeLower();
|
||
|
||
for( int i = 1; i < c_nCountFileFormats; i++ )
|
||
{
|
||
if( sFileEx == tableSupportImageFormats[i].str )
|
||
{
|
||
eFileType = tableSupportImageFormats[i].format;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
CImageFileFormatChecker checker(strFilePath);
|
||
|
||
BOOL bLoading = FALSE;
|
||
|
||
if (checker.eFileType>0 && checker.eFileType == eFileType)
|
||
{
|
||
bLoading = FromFile(eFileType,strFilePath);
|
||
}
|
||
else if (checker.eFileType || eFileType)
|
||
{
|
||
//неоднозначные ситуации не совпадения sync-word с заданным расширением
|
||
if (eFileType)
|
||
{
|
||
bLoading = FromFile(eFileType,strFilePath); //попытка открыть по расширению
|
||
}
|
||
|
||
if (!bLoading && checker.eFileType)
|
||
{
|
||
bLoading = FromFile(checker.eFileType,strFilePath); //попытка открыть по сигнатуре
|
||
}
|
||
}
|
||
|
||
return bLoading;
|
||
}
|
||
|
||
BOOL FromFile(const _ImageFileFormats type, const CStringW& strFilePath)
|
||
{
|
||
Clear();
|
||
|
||
BOOL bLoading = FALSE;
|
||
if ((type == c_Bmp)
|
||
|| (type == c_Gif)
|
||
|| (type == c_Ico)
|
||
|| (type == c_Tiff)
|
||
|| (type == c_Png))
|
||
{
|
||
bLoading = LoadBitmapMetaData(strFilePath);
|
||
}
|
||
else if (type == c_Jpg)
|
||
{
|
||
bLoading = LoadBitmapMetaData(strFilePath);
|
||
}
|
||
else if (type == c_RawFotos)
|
||
{
|
||
bLoading = LoadRawMetaData(strFilePath);
|
||
}
|
||
|
||
if (bLoading) return TRUE;
|
||
|
||
|
||
HANDLE hFile = CreateFile(strFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||
if (INVALID_HANDLE_VALUE == hFile)
|
||
return FALSE; // Невозможно открыть файл
|
||
|
||
// мапим этот файл в память - так быстрее читаются данные из файла
|
||
DWORD nFileSize = GetFileSize(hFile, NULL);
|
||
HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, nFileSize, NULL);
|
||
if (NULL == hMapFile)
|
||
{
|
||
CloseHandle( hFile );
|
||
return FALSE; // Невозможно создать отображение файла
|
||
}
|
||
|
||
// создаем view of file
|
||
DWORD nMaxBytesRead = nFileSize;
|
||
VOID* pBaseAddress = MapViewOfFile( hMapFile, FILE_MAP_READ, 0, 0, 0 );
|
||
if ( !pBaseAddress )
|
||
{
|
||
CloseHandle( hMapFile );
|
||
CloseHandle( hFile );
|
||
return FALSE;
|
||
}
|
||
BYTE* pnFile = (BYTE*)pBaseAddress;
|
||
BOOL bRetValue = FALSE;
|
||
|
||
try
|
||
{
|
||
switch(type)
|
||
{
|
||
case c_Tiff:
|
||
{
|
||
bLoading = LoadTiffMetaData(pnFile, nFileSize);
|
||
}break;
|
||
case c_Png:
|
||
{
|
||
bLoading = LoadPNGMetaData(pnFile, nFileSize);
|
||
}break;
|
||
case c_Tga:
|
||
{
|
||
bLoading = LoadTGAMetaData(pnFile, nFileSize);
|
||
}break;
|
||
case c_Psd:
|
||
{
|
||
bLoading = LoadPSDMetaData(pnFile, nFileSize);
|
||
}break;
|
||
case c_Pcx:
|
||
{
|
||
bLoading = LoadPCXMetaData(pnFile, nFileSize);
|
||
}break;
|
||
case c_Ras:
|
||
{
|
||
bLoading = LoadRasMetaData(pnFile, nFileSize);
|
||
}break;
|
||
case c_Jpeg2000:
|
||
{
|
||
bLoading = LoadJ2kMetaData(pnFile, nFileSize);
|
||
}break;
|
||
case c_RawFotos:
|
||
{
|
||
bLoading = LoadFoveonMetaData(pnFile, nFileSize);
|
||
}break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
catch (...)
|
||
{
|
||
|
||
}
|
||
UnmapViewOfFile(pBaseAddress);
|
||
CloseHandle(hMapFile);
|
||
CloseHandle( hFile );
|
||
return bLoading;
|
||
}
|
||
BOOL SaveToBMP(Bitmap* bitmap)
|
||
{
|
||
SetPropertyStr(bitmap, PropertyTagImageTitle, m_sTitle);
|
||
SetPropertyStr(bitmap, PropertyTagArtist, m_sAuthor);
|
||
SetPropertyStr(bitmap, PropertyTagImageDescription, m_sDescription);
|
||
|
||
CString sDateTime = _T("");
|
||
CString sTemp = _T("");
|
||
char sValue[33];
|
||
_itoa(m_oDateTimeCreation.nYear, sValue, 10);
|
||
|
||
sTemp = sValue;
|
||
while ( sTemp.GetLength() < 4 )
|
||
sTemp = _T("0") + sTemp;
|
||
|
||
sDateTime += sTemp + _T(":");
|
||
|
||
_itoa(m_oDateTimeCreation.nMonth, sValue, 10);
|
||
|
||
sTemp = sValue;
|
||
while ( sTemp.GetLength() < 2 )
|
||
sTemp = _T("0") + sTemp;
|
||
|
||
sDateTime += sTemp + _T(":");
|
||
|
||
_itoa(m_oDateTimeCreation.nDay, sValue, 10);
|
||
|
||
sTemp = sValue;
|
||
while ( sTemp.GetLength() < 2 )
|
||
sTemp = _T("0") + sTemp;
|
||
|
||
sDateTime += sTemp + _T(" ");
|
||
|
||
_itoa(m_oDateTimeCreation.nHour, sValue, 10);
|
||
|
||
sTemp = sValue;
|
||
while ( sTemp.GetLength() < 2 )
|
||
sTemp = _T("0") + sTemp;
|
||
|
||
sDateTime += sTemp + _T(":");
|
||
|
||
_itoa(m_oDateTimeCreation.nMinute, sValue, 10);
|
||
|
||
sTemp = sValue;
|
||
while ( sTemp.GetLength() < 2 )
|
||
sTemp = _T("0") + sTemp;
|
||
|
||
sDateTime += sTemp + _T(":");
|
||
|
||
_itoa(m_oDateTimeCreation.nSecond, sValue, 10);
|
||
|
||
sTemp = sValue;
|
||
while ( sTemp.GetLength() < 2 )
|
||
sTemp = _T("0") + sTemp;
|
||
|
||
sDateTime += sTemp;
|
||
|
||
SetPropertyStr(bitmap, PropertyTagDateTime, sDateTime);
|
||
SetPropertyStr(bitmap, PropertyTagExifUserComment, m_sComment);
|
||
SetPropertyStr(bitmap, PropertyTagCopyright, m_sCopyright);
|
||
SetPropertyStr(bitmap, PropertyTagHostComputer, m_sHostComputer);
|
||
SetPropertyStr(bitmap, PropertyTagEquipMake, m_sEquipmentType);
|
||
SetPropertyStr(bitmap, PropertyTagEquipModel, m_sEquipmentModel);
|
||
SetPropertyStr(bitmap, PropertyTagSoftwareUsed, m_sSoftwareID);
|
||
SetPropertyStr(bitmap, PropertyTagDocumentName, m_sDocumentName);
|
||
SetPropertyStr(bitmap, PropertyTagPageName, m_sPageName);
|
||
|
||
short nPageNumber = BYTE(m_nPagesCount) << 8 | BYTE(m_nPageNumber);
|
||
SetPropertyShort(bitmap, PropertyTagPageNumber, nPageNumber);
|
||
|
||
SetPropertyStr(bitmap, PropertyTagPageName, m_sDisclaimer);
|
||
//SetPropertyStr(bitmap, PropertyTagPageName, m_sJobName);
|
||
//SetPropertyUndefined(bitmap,PropertyTagExifVer, m_sVersionLetter);
|
||
SetPropertyShort(bitmap, PropertyTagExifISOSpeed, m_nISOSpeed);
|
||
//SetPropertyShort(bitmap, PropertyTagPageName, m_nBitDepth);
|
||
SetPropertyShort(bitmap, PropertyTagExifColorSpace, m_nColorSpace);
|
||
|
||
SetPropertyShort(bitmap, PropertyTagOrientation, m_nOrientation);
|
||
SetPropertyShort(bitmap, PropertyTagExifExposureProg,m_nExposureProgram);
|
||
SetPropertyShort(bitmap, PropertyTagExifFlash, m_nFlashMode);
|
||
SetPropertyShort(bitmap, PropertyTagExifMeteringMode, m_nMeteringMode);
|
||
|
||
SetPropertyRational(bitmap,PropertyTagExifFNumber,m_oFNumber);
|
||
SetPropertyRational(bitmap,PropertyTagExifExposureTime,m_oExposureTime);
|
||
SetPropertyRational(bitmap,PropertyTagExifAperture,m_oLensAperture);
|
||
SetPropertyRational(bitmap,PropertyTagExifMaxAperture,m_oMaxApertureValue);
|
||
SetPropertySRational(bitmap,PropertyTagExifShutterSpeed,m_oShutterSpeed);
|
||
SetPropertySRational(bitmap,PropertyTagExifExposureBias,m_oExposureCompensation);
|
||
SetPropertySRational(bitmap,PropertyTagExifBrightness,m_oBrightness);
|
||
SetPropertyRational(bitmap,PropertyTagExifFocalLength,m_oFocalLength);
|
||
|
||
//exif 2.2
|
||
SetPropertyShort(bitmap,PropertyTagExifExposureMode,m_nExposureMode );
|
||
SetPropertyShort(bitmap,PropertyTagExifWhiteBalance,m_nWhiteBalance);
|
||
SetPropertyShort(bitmap,PropertyTagExifSensingMethod , m_nSensingMethod);
|
||
SetPropertyShort(bitmap,PropertyTagExifFocalLengthIn35mmFilm,m_nFocalLengthIn35mmFilm);
|
||
|
||
|
||
if (bitmap->GetLastStatus() != Ok)
|
||
return FALSE;
|
||
|
||
//дополнительные данные
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL SaveToTGA(const CString& strFilePath)
|
||
{
|
||
CAtlFile file;
|
||
if (S_OK != file.Create(strFilePath, GENERIC_WRITE, FILE_SHARE_WRITE, OPEN_EXISTING))
|
||
return FALSE; // Не могу создать файл
|
||
|
||
ULONGLONG nFileSize;
|
||
file.GetSize((ULONGLONG&)nFileSize);
|
||
|
||
file.Seek(nFileSize);
|
||
SaveAsTGA(file);
|
||
file.Close();
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL SaveToPNG(const CString& strFilePath)
|
||
{
|
||
// сначала найдем указатель на последний кусочек файла
|
||
// в принципе, он должен быть равен (nFileSize - 12)
|
||
|
||
ULONGLONG nOffset = GetPNGLastPoint(strFilePath);
|
||
if ( nOffset < 0 )
|
||
return FALSE;
|
||
|
||
CAtlFile file;
|
||
if (S_OK != file.Create(strFilePath, GENERIC_WRITE, FILE_SHARE_WRITE, OPEN_EXISTING))
|
||
return FALSE; // Не могу создать файл
|
||
|
||
|
||
|
||
ULONGLONG nFileSize;
|
||
file.GetSize((ULONGLONG&)nFileSize);
|
||
|
||
//file.Seek(nFileSize - 12);
|
||
file.Seek(nOffset);
|
||
|
||
SaveAsPNG(file);
|
||
file.Close();
|
||
return TRUE;
|
||
}
|
||
|
||
void Clear()
|
||
{
|
||
m_sAuthor = _T("");
|
||
m_sTitle = _T("");
|
||
m_sDescription = _T("");
|
||
m_oDateTimeCreation.nYear = 0;
|
||
m_oDateTimeCreation.nMonth = 0;
|
||
m_oDateTimeCreation.nDay = 0;
|
||
m_oDateTimeCreation.nHour = 0;
|
||
m_oDateTimeCreation.nMinute = 0;
|
||
m_oDateTimeCreation.nSecond = 0;
|
||
m_oDateTimeCreation.sSummary = _T("");
|
||
m_sCopyright = _T("");
|
||
m_sDisclaimer = _T("");
|
||
m_sComment = _T("");
|
||
m_sEquipmentType = _T("");
|
||
m_sEquipmentModel = _T("");
|
||
m_oJobTime.nHour = 0;
|
||
m_oJobTime.nMinute = 0;
|
||
m_oJobTime.nSecond = 0;
|
||
m_sJobName = _T("");
|
||
m_sSoftwareID = _T("");
|
||
m_nVersionNumber = 0;
|
||
m_sVersionLetter = _T("");
|
||
m_sHostComputer = _T("");
|
||
m_sWarning = _T("");
|
||
m_sDocumentName = _T("");
|
||
m_sPageName = _T("");
|
||
m_nPageNumber = 0;
|
||
m_nPagesCount = 0;
|
||
|
||
// дополнительные данные для photoeditor
|
||
|
||
m_nExposureProgram = 0;
|
||
m_oExposureTime.Fraction = 0;
|
||
m_oExposureTime.Denominator = 0;
|
||
m_oExposureCompensation.Fraction = 0;
|
||
m_oExposureCompensation.Denominator = 0;
|
||
m_oShutterSpeed.Fraction = 0;
|
||
m_oShutterSpeed.Denominator = 0;
|
||
m_oLensAperture.Fraction = 0;
|
||
m_oLensAperture.Denominator = 0;
|
||
m_oFocalLength.Fraction = 0;
|
||
m_oFocalLength.Denominator = 0;
|
||
m_oFNumber.Fraction = 0;
|
||
m_oFNumber.Denominator = 0;
|
||
m_oBrightness.Denominator = 0;
|
||
m_oBrightness.Fraction = 0;
|
||
|
||
m_nISOSpeed = 0;
|
||
m_nMeteringMode = 0;
|
||
m_nFlashMode = 0;
|
||
m_nColorSpace = 0;
|
||
|
||
m_oMaxApertureValue.Fraction = 0;
|
||
m_oMaxApertureValue.Denominator = 0;
|
||
|
||
m_nSensingMethod = 0;
|
||
m_nWhiteBalance = 0;
|
||
m_nExposureMode = 0;
|
||
m_nOrientation = 1;
|
||
m_nFocalLengthIn35mmFilm = 0;
|
||
|
||
m_nBitDepth = 1;
|
||
|
||
m_sMetaDataXML = _T("");
|
||
|
||
|
||
}
|
||
CString GetXML()
|
||
{
|
||
MakeXML();
|
||
return m_sMetaDataXML;
|
||
}
|
||
|
||
void SetXML(CString sXML)
|
||
{
|
||
ParseXML(sXML);
|
||
return;
|
||
}
|
||
|
||
short GetOrientation()
|
||
{
|
||
return m_nOrientation;
|
||
}
|
||
protected:
|
||
|
||
//common functions
|
||
int IntFromBytes2( const BYTE* pBytes, int nType)
|
||
{
|
||
int nValue = 0;
|
||
|
||
if ( 0 == nType )
|
||
{
|
||
nValue = pBytes[0];
|
||
nValue = ( nValue << 8 ) | pBytes[1];
|
||
}
|
||
else
|
||
{
|
||
nValue = pBytes[1];
|
||
nValue = ( nValue << 8 ) | pBytes[0];
|
||
}
|
||
return nValue;
|
||
}
|
||
|
||
int IntFromBytes4( const BYTE* pBytes, int nType)
|
||
{
|
||
int nValue = 0;
|
||
|
||
if ( 0 == nType )
|
||
{
|
||
nValue = pBytes[0];
|
||
nValue = ( nValue << 8 ) | pBytes[1];
|
||
nValue = ( nValue << 8 ) | pBytes[2];
|
||
nValue = ( nValue << 8 ) | pBytes[3];
|
||
}
|
||
else
|
||
{
|
||
nValue = pBytes[3];
|
||
nValue = ( nValue << 8 ) | pBytes[2];
|
||
nValue = ( nValue << 8 ) | pBytes[1];
|
||
nValue = ( nValue << 8 ) | pBytes[0];
|
||
}
|
||
return nValue;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
void IntToBytes4( int nNumber, BYTE* pBytes )
|
||
{
|
||
pBytes[3] = (BYTE)nNumber; nNumber >>= 8;
|
||
pBytes[2] = (BYTE)nNumber; nNumber >>= 8;
|
||
pBytes[1] = (BYTE)nNumber; nNumber >>= 8;
|
||
pBytes[0] = (BYTE)nNumber;
|
||
}
|
||
// PNG functions
|
||
BOOL CheckPNGSignature(BYTE* pnFile)
|
||
{
|
||
// Сигнатура PNG, первые 8 байт:
|
||
// 137 80 78 71 13 10 26 10
|
||
// ЙPNG♪◙☻◙
|
||
|
||
if ( 137 == pnFile[0] && 80 == pnFile[1] && 78 == pnFile[2] && 71 == pnFile[3] &&
|
||
13 == pnFile[4] && 10 == pnFile[5] && 26 == pnFile[6] && 10 == pnFile[7] )
|
||
return TRUE;
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
CString ChunkType(const BYTE* pCurPoint)
|
||
{
|
||
CString sType = _T("");
|
||
sType += pCurPoint[0];
|
||
sType += pCurPoint[1];
|
||
sType += pCurPoint[2];
|
||
sType += pCurPoint[3];
|
||
return sType;
|
||
}
|
||
|
||
|
||
|
||
|
||
BOOL SaveChunk(ATL::CAtlFile& oFile, CString sKeyword, CString sValue)
|
||
{
|
||
TChunk oChunk;
|
||
DWORD nLenght = sKeyword.GetLength() + sValue.GetLength() + 1;
|
||
BYTE *pCheckSum = new BYTE[4 + nLenght];
|
||
|
||
IntToBytes4( nLenght, oChunk.nLenght);
|
||
oChunk.nType[0] = 't';
|
||
oChunk.nType[1] = 'E';
|
||
oChunk.nType[2] = 'X';
|
||
oChunk.nType[3] = 't';
|
||
|
||
for (int nIndex = 0; nIndex < 4; nIndex++)
|
||
pCheckSum[nIndex] = oChunk.nType[nIndex];
|
||
|
||
if( S_OK != oFile.Write( &oChunk, 8))
|
||
return FALSE;
|
||
|
||
CString sData = sKeyword.GetBuffer();
|
||
char *aData = (char*)(LPSTR)sData.GetBuffer(sData.GetLength());
|
||
|
||
for (int nIndex = 4; nIndex < 4 + sKeyword.GetLength(); nIndex++)
|
||
pCheckSum[nIndex] = aData[nIndex - 4];
|
||
|
||
//if( S_OK != oFile.Write( aData, sData.GetLength()))
|
||
// return FALSE;
|
||
|
||
pCheckSum[4 + sKeyword.GetLength()] = 0;
|
||
|
||
sData = sValue.GetBuffer();
|
||
aData = (char*)(LPSTR)sData.GetBuffer(sData.GetLength());
|
||
for (int nIndex = 4 + sKeyword.GetLength() + 1; nIndex < 4 + nLenght; nIndex++)
|
||
pCheckSum[nIndex] = aData[nIndex - ( 4 + sKeyword.GetLength() + 1 )];
|
||
|
||
//BYTE nNullSeparator = 0;
|
||
|
||
//if( S_OK != oFile.Write( &nNullSeparator, 1))
|
||
// return FALSE;
|
||
|
||
|
||
if( S_OK != oFile.Write( pCheckSum + 4, nLenght))
|
||
return FALSE;
|
||
|
||
crc32 oCRC;
|
||
oCRC.ProcessCRC(pCheckSum, nLenght + 4);
|
||
delete []pCheckSum;
|
||
|
||
BYTE pCRC[4] = {0, 0, 0, 0};
|
||
IntToBytes4( oCRC.m_crc32, pCRC);
|
||
|
||
if( S_OK != oFile.Write( pCRC, 4))
|
||
return FALSE;
|
||
|
||
return TRUE;
|
||
}
|
||
DWORD GetPNGLastPoint(const CString& strFilePath)
|
||
{
|
||
// открываем файл
|
||
HANDLE hFile = CreateFile(strFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||
if (INVALID_HANDLE_VALUE == hFile)
|
||
return FALSE; // Невозможно открыть файл
|
||
|
||
// мапим этот файл в память - так быстрее читаются данные из файла
|
||
DWORD nFileSize = GetFileSize(hFile, NULL);
|
||
HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, nFileSize, NULL);
|
||
if (NULL == hMapFile)
|
||
{
|
||
CloseHandle( hFile );
|
||
return FALSE; // Невозможно создать отображение файла
|
||
}
|
||
|
||
// создаем view of file
|
||
DWORD nMaxBytesRead = nFileSize;
|
||
VOID* pBaseAddress = MapViewOfFile( hMapFile, FILE_MAP_READ, 0, 0, 0 );
|
||
BYTE* pnFile = (BYTE*)pBaseAddress;
|
||
BOOL bRetValue = FALSE;
|
||
|
||
if ( !CheckPNGSignature(pnFile) )
|
||
return -1;
|
||
|
||
BYTE* pCurPoint = pnFile + 8;
|
||
|
||
const TChunk& oFirstChunk = *(TChunk*)pCurPoint;
|
||
CString sType = ChunkType(oFirstChunk.nType);
|
||
|
||
if ( -1 == sType.Find(_T("IHDR")) )
|
||
return -1;
|
||
|
||
DWORD nBytesAlreadyRead = 8;
|
||
int nLenght = IntFromBytes4(oFirstChunk.nLenght, 0);
|
||
int nChunkSize = nLenght + 12;
|
||
|
||
while ( -1 == sType.Find(_T("IEND")) && nBytesAlreadyRead < nFileSize )
|
||
{
|
||
pCurPoint += nChunkSize;
|
||
nBytesAlreadyRead += nChunkSize;
|
||
const TChunk& oCurChunk = *(TChunk*)pCurPoint;
|
||
sType = ChunkType(oCurChunk.nType);
|
||
nLenght = IntFromBytes4(oCurChunk.nLenght, 0);
|
||
nChunkSize = nLenght + 12;
|
||
}
|
||
CloseHandle( hFile );
|
||
return nBytesAlreadyRead;
|
||
}
|
||
// TGA functions
|
||
CString TGAASKIIValue(const BYTE* pCurPoint, int nLenght)
|
||
{
|
||
CString sReturn = _T("");
|
||
for ( int nIndex = 0; nIndex < nLenght; nIndex++ )
|
||
sReturn += pCurPoint[nIndex];
|
||
|
||
return sReturn;
|
||
}
|
||
|
||
|
||
|
||
void BytesFromString(CString sSource, BYTE *pResult, int nCount)
|
||
{
|
||
int nLen = min( (int)sSource.GetLength(), nCount);
|
||
for (int nIndex = 0; nIndex < nLen; nIndex++ )
|
||
pResult[nIndex] = sSource[nIndex];
|
||
}
|
||
|
||
// BMP functions
|
||
CString GetPropertyStr(Bitmap*& pImage, PROPID nId)
|
||
{
|
||
// reset value
|
||
CString sValue = _T("");
|
||
|
||
// retrieve property size
|
||
UINT nSize = pImage->GetPropertyItemSize(nId);
|
||
|
||
// check for valid size
|
||
if (nSize > 0)
|
||
{
|
||
// allocate memory for tag
|
||
PropertyItem* pProp = (PropertyItem*)(malloc(nSize));
|
||
if ( NULL == pProp )
|
||
return sValue;
|
||
|
||
// read tag to buffer
|
||
pImage->GetPropertyItem(nId, nSize, pProp);
|
||
|
||
// copy data to buffer
|
||
if ( NULL != pProp->value )
|
||
sValue = (const char*)pProp->value;
|
||
|
||
// release buffer
|
||
free(pProp);
|
||
}
|
||
return sValue;
|
||
}
|
||
|
||
int GetPropertyInt(Bitmap*& pImage, PROPID nId)
|
||
{
|
||
// reset value
|
||
int nValue = 0;
|
||
|
||
// retrieve property size
|
||
UINT nSize = pImage->GetPropertyItemSize(nId);
|
||
|
||
// check for valid size
|
||
if (nSize > 0)
|
||
{
|
||
// allocate memory for tag
|
||
PropertyItem* pProp = (PropertyItem*)(malloc(nSize));
|
||
if ( NULL == pProp )
|
||
return nValue;
|
||
|
||
// read tag to buffer
|
||
pImage->GetPropertyItem(nId, nSize, pProp);
|
||
|
||
// copy data to buffer
|
||
if ( NULL != pProp->value )
|
||
nValue = *(int*)pProp->value;
|
||
|
||
// release buffer
|
||
free(pProp);
|
||
}
|
||
return nValue;
|
||
}
|
||
|
||
|
||
short GetPropertyShort(Bitmap*& pImage, PROPID nId)
|
||
{
|
||
// reset value
|
||
short nValue = 0;
|
||
|
||
// retrieve property size
|
||
UINT nSize = pImage->GetPropertyItemSize(nId);
|
||
|
||
// check for valid size
|
||
if (nSize > 0)
|
||
{
|
||
// allocate memory for tag
|
||
PropertyItem* pProp = (PropertyItem*)(malloc(nSize));
|
||
if ( NULL == pProp )
|
||
return nValue;
|
||
|
||
// read tag to buffer
|
||
pImage->GetPropertyItem(nId, nSize, pProp);
|
||
|
||
// copy data to buffer
|
||
if ( NULL != pProp->value )
|
||
nValue = *(short*)pProp->value;
|
||
|
||
// release buffer
|
||
free(pProp);
|
||
}
|
||
return nValue;
|
||
}
|
||
|
||
|
||
double GetPropertyDouble(Bitmap*& pImage, PROPID nId)
|
||
{
|
||
// reset value
|
||
double dValue = 0;
|
||
|
||
// retrieve property size
|
||
UINT nSize = pImage->GetPropertyItemSize(nId);
|
||
|
||
// check for valid size
|
||
if (nSize > 0)
|
||
{
|
||
// allocate memory for tag
|
||
PropertyItem* pProp = (PropertyItem*)(malloc(nSize));
|
||
if ( NULL == pProp )
|
||
return dValue;
|
||
|
||
// read tag to buffer
|
||
pImage->GetPropertyItem(nId, nSize, pProp);
|
||
|
||
// copy data to buffer
|
||
if ( NULL != pProp->value )
|
||
dValue = *(double*)pProp->value;
|
||
|
||
// release buffer
|
||
free(pProp);
|
||
}
|
||
return dValue;
|
||
}
|
||
|
||
void GetPropertyRationalU(Bitmap*& pImage, PROPID nId, TRationalU *pResult)
|
||
{
|
||
//rational - пара двух чисел (числитель и знаменатель)
|
||
(*pResult).Denominator = 1;
|
||
(*pResult).Fraction = 0;
|
||
// retrieve property size
|
||
UINT nSize = pImage->GetPropertyItemSize(nId);
|
||
|
||
// check for valid size
|
||
if (nSize > 0)
|
||
{
|
||
// allocate memory for tag
|
||
PropertyItem* pProp = (PropertyItem*)(malloc(nSize));
|
||
if ( NULL == pProp )
|
||
return;
|
||
|
||
// read tag to buffer
|
||
pImage->GetPropertyItem(nId, nSize, pProp);
|
||
|
||
// copy data to buffer
|
||
if ( NULL != pProp->value )
|
||
*pResult = *(TRationalU*)pProp->value;
|
||
|
||
// release buffer
|
||
free(pProp);
|
||
}
|
||
}
|
||
|
||
|
||
void GetPropertyRational(Bitmap*& pImage, PROPID nId, TRational *pResult)
|
||
{
|
||
//rational - пара двух чисел (числитель и знаменатель)
|
||
(*pResult).Denominator = 1;
|
||
(*pResult).Fraction = 0;
|
||
// retrieve property size
|
||
UINT nSize = pImage->GetPropertyItemSize(nId);
|
||
|
||
// check for valid size
|
||
if (nSize > 0)
|
||
{
|
||
// allocate memory for tag
|
||
PropertyItem* pProp = (PropertyItem*)(malloc(nSize));
|
||
if ( NULL == pProp )
|
||
return;
|
||
|
||
// read tag to buffer
|
||
pImage->GetPropertyItem(nId, nSize, pProp);
|
||
|
||
// copy data to buffer
|
||
if ( NULL != pProp->value )
|
||
*pResult = *(TRational*)pProp->value;
|
||
|
||
// release buffer
|
||
free(pProp);
|
||
}
|
||
}
|
||
|
||
|
||
void SetPropertyStr(Bitmap*& pImage, PROPID nId, CString& sValue)
|
||
{
|
||
// check for valid string
|
||
if (sValue.GetLength() < 1)
|
||
return;
|
||
|
||
// create new property item
|
||
PropertyItem* pProp = new PropertyItem;
|
||
if ( NULL == pProp )
|
||
return;
|
||
|
||
// compose property item
|
||
pProp->id = nId;
|
||
pProp->length = (nId == PropertyTagDateTime) ? 20 : sValue.GetLength() + 1;
|
||
pProp->type = PropertyTagTypeASCII;
|
||
|
||
CT2A convert(sValue);
|
||
pProp->value =convert;
|
||
|
||
// sset property item
|
||
pImage->SetPropertyItem(pProp);
|
||
|
||
// delete property item
|
||
delete pProp;
|
||
}
|
||
void SetPropertyShort(Bitmap*& pImage, PROPID nId, short& nValue)
|
||
{
|
||
// create new property item
|
||
PropertyItem* pProp = new PropertyItem;
|
||
if ( NULL == pProp )
|
||
return;
|
||
|
||
// compose property item
|
||
pProp->id = nId;
|
||
pProp->length = sizeof(short);
|
||
pProp->type = PropertyTagTypeShort;
|
||
pProp->value = (short*)(&nValue);
|
||
|
||
// sset property item
|
||
pImage->SetPropertyItem(pProp);
|
||
|
||
// delete property item
|
||
delete pProp;
|
||
}
|
||
void SetPropertyRational(Bitmap*& pImage, PROPID nId, TRationalU& nValue)
|
||
{//unsignes
|
||
// create new property item
|
||
PropertyItem* pProp = new PropertyItem;
|
||
if ( NULL == pProp )
|
||
return;
|
||
|
||
// compose property item
|
||
pProp->id = nId;
|
||
pProp->length = 2 * sizeof(long);
|
||
pProp->type = PropertyTagTypeRational;
|
||
pProp->value = (unsigned long*)(&nValue);
|
||
|
||
// sset property item
|
||
pImage->SetPropertyItem(pProp);
|
||
|
||
// delete property item
|
||
delete pProp;
|
||
}
|
||
void SetPropertySRational(Bitmap*& pImage, PROPID nId, TRational& nValue)
|
||
{//signed
|
||
// create new property item
|
||
PropertyItem* pProp = new PropertyItem;
|
||
if ( NULL == pProp )
|
||
return;
|
||
|
||
// compose property item
|
||
pProp->id = nId;
|
||
pProp->length = 2 * sizeof(long);
|
||
pProp->type = PropertyTagTypeSRational;
|
||
pProp->value = (long*)(&nValue);
|
||
|
||
// sset property item
|
||
pImage->SetPropertyItem(pProp);
|
||
|
||
// delete property item
|
||
delete pProp;
|
||
}
|
||
CString RationalUToString(TRationalU oRat)
|
||
{
|
||
CString sResult = _T("");
|
||
char str[32];
|
||
_itoa(oRat.Fraction, str, 10);
|
||
sResult += str;
|
||
if ( 0 != oRat.Denominator )
|
||
{
|
||
sResult += _T("/");
|
||
_itoa(oRat.Denominator, str, 10);
|
||
sResult += str;
|
||
}
|
||
return sResult;
|
||
}
|
||
CString RationalToString(TRational oRat)
|
||
{
|
||
CString sResult = _T("");
|
||
char str[32];
|
||
_itoa(oRat.Fraction, str, 10);
|
||
sResult += str;
|
||
if ( 0 != oRat.Denominator )
|
||
{
|
||
sResult += _T("/");
|
||
_itoa(oRat.Denominator, str, 10);
|
||
sResult += str;
|
||
}
|
||
return sResult;
|
||
}
|
||
// Raw functions
|
||
BOOL ReadMakerNoteSignature(BYTE *pnMakerNote, int *pByteOrder, DWORD *pOffset)
|
||
{
|
||
int nByteOrder = -1;
|
||
|
||
// изначально читаем 10 символов для проверки сигнатуры
|
||
DWORD nOffset = 10;
|
||
|
||
TCHAR cSignature[10];
|
||
for (int nIndex = 0; nIndex < 10; nIndex++ )
|
||
cSignature[nIndex] = pnMakerNote[nIndex];
|
||
|
||
// не Tiff формат
|
||
|
||
if (!_tcsnccmp (cSignature,_T("KDK") ,3) || !_tcsnccmp (cSignature,_T("VER") ,3) ||
|
||
!_tcsnccmp (cSignature,_T("IIII"),4) || !_tcsnccmp (cSignature,_T("MMMM"),4) )
|
||
return false;
|
||
|
||
/* Konica KD-400Z, KD-510Z */
|
||
/* Minolta DiMAGE G series */
|
||
|
||
if (!_tcsnccmp (cSignature,_T("KC"),2) || !_tcsnccmp (cSignature,_T("MLY") ,3))
|
||
return false;
|
||
|
||
if (!_tcscmp (cSignature,_T("Nikon")))
|
||
{
|
||
const TTiffFileHeader& oHeader = *(TTiffFileHeader*)(pnMakerNote + 10);
|
||
CString sByteOrder(oHeader.nByteOrder);
|
||
|
||
if ( -1 != sByteOrder.Find(_T("II"), 0) )
|
||
nByteOrder = 1;
|
||
else if ( -1 != sByteOrder.Find(_T("MM"), 0) )
|
||
nByteOrder = 0;
|
||
else
|
||
return false;
|
||
|
||
int nSignature = IntFromBytes2(oHeader.nSignature, nByteOrder);
|
||
if ( 42 != nSignature )
|
||
return false;
|
||
|
||
nOffset += IntFromBytes4( oHeader.nIDFoffset, nByteOrder);
|
||
}
|
||
else if (!_tcscmp (cSignature,_T("OLYMPUS")))
|
||
{
|
||
const TTiffFileHeader& oHeader = *(TTiffFileHeader*)(pnMakerNote + 8);
|
||
CString sByteOrder(oHeader.nByteOrder);
|
||
|
||
if ( -1 != sByteOrder.Find(_T("II"), 0) )
|
||
nByteOrder = 1;
|
||
else if ( -1 != sByteOrder.Find(_T("MM"), 0) )
|
||
nByteOrder = 0;
|
||
else
|
||
return false;
|
||
|
||
nOffset += 2;
|
||
|
||
}
|
||
else if (!_tcsnccmp (cSignature,_T("FUJIFILM"),8) || !_tcsnccmp (cSignature,_T("SONY"),4) ||
|
||
!_tcscmp (cSignature,_T("Panasonic")) )
|
||
{
|
||
nByteOrder = 1;// 0x4949
|
||
nOffset += 2;
|
||
}
|
||
else if (!_tcscmp (cSignature,_T("OLYMP")) || !_tcscmp (cSignature,_T("LEICA")) ||
|
||
!_tcscmp (cSignature,_T("Ricoh")) || !_tcscmp (cSignature,_T("EPSON")) )
|
||
nOffset -= 2;
|
||
else if (!_tcscmp (cSignature,_T("AOC")) || !_tcscmp (cSignature,_T("QVC")))
|
||
nOffset -= 4;
|
||
else
|
||
nOffset -= 10;
|
||
|
||
// проверям менялся ли порядок байт
|
||
if ( nByteOrder >= 0 )
|
||
pByteOrder[0] = nByteOrder;
|
||
pOffset[0] = nOffset;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
void ReadMakerNote(BYTE *pnMakerNote, int nByteOrder, BYTE *pnFile, DWORD nBaseOffset)
|
||
{
|
||
// В MakerNote может быть свой Tiff Header ( возможно,
|
||
// со своим порядком байт), а возможно тут хранится таблица
|
||
BYTE* pCurPoint = pnMakerNote;
|
||
|
||
DWORD nOffset = 0;
|
||
|
||
if ( !ReadMakerNoteSignature(pnMakerNote, &nByteOrder, &nOffset) )
|
||
return;
|
||
|
||
pCurPoint += nOffset;
|
||
|
||
int nDirectoryEntryCount = IntFromBytes2(pCurPoint, nByteOrder);
|
||
|
||
if ( nDirectoryEntryCount > 1000 )
|
||
return;
|
||
|
||
int nIndex = 0;
|
||
|
||
while ( nDirectoryEntryCount-- )
|
||
{
|
||
|
||
BYTE* pCurDirectory = pCurPoint + 2 + 12 * nIndex;
|
||
nIndex++;
|
||
|
||
const TDirectoryEntry& oDirEntry = *(TDirectoryEntry*)(pCurDirectory);
|
||
int nTag = IntFromBytes2(oDirEntry.nTag, nByteOrder);
|
||
int nType = IntFromBytes2(oDirEntry.nType, nByteOrder);
|
||
int nCount = IntFromBytes4(oDirEntry.nCount, nByteOrder);
|
||
int nValueOffset = IntFromBytes4(oDirEntry.nValueOffset, nByteOrder);
|
||
|
||
nValueOffset += nBaseOffset;
|
||
|
||
if ( 2 == nType ) // значение типa ASCII
|
||
{
|
||
|
||
CString sCur = _T("");
|
||
if (nCount <= 4)
|
||
{
|
||
sCur = TGAASKIIValue(oDirEntry.nValueOffset, nCount);
|
||
}
|
||
else
|
||
{
|
||
if ( -1 != m_sEquipmentType.Find(_T("FUJIFILM")) )
|
||
for (int nI = 0; nI < nCount; nI++ )
|
||
sCur += (pnMakerNote + nValueOffset)[nI];
|
||
else if ( -1 != m_sEquipmentType.Find(_T("NIKON")) )
|
||
for (int nI = 0; nI < nCount; nI++ )
|
||
sCur += (pnMakerNote + nOffset - 8 + nValueOffset)[nI];
|
||
else
|
||
for (int nI = 0; nI < nCount; nI++ )
|
||
sCur += (pnFile + nValueOffset)[nI];
|
||
|
||
}
|
||
|
||
if ( -1 != m_sEquipmentType.Find(_T("OLYMP")) || -1 != m_sEquipmentType.Find(_T("EPSON")) ||
|
||
-1 != m_sEquipmentType.Find(_T("Agfa")) )
|
||
{
|
||
if ( 0x0207 == nTag )
|
||
{
|
||
m_sComment += sCur;
|
||
m_sComment += _T("\n");
|
||
}
|
||
else if ( 0x0208 == nTag )
|
||
{
|
||
m_sComment += _T("Picture Info: ") + sCur;
|
||
m_sComment += _T("\n");
|
||
}
|
||
else if ( 0x0209 == nTag )
|
||
{
|
||
m_sComment += _T("Camera ID: ") + sCur;
|
||
m_sComment += _T("\n");
|
||
}
|
||
else if ( 0x02D == nTag )
|
||
{
|
||
m_sComment += _T("Original Manufacturer Model: ") + sCur;
|
||
m_sComment += _T("\n");
|
||
}
|
||
|
||
}
|
||
|
||
if ( -1 != m_sEquipmentType.Find(_T("Canon")) )
|
||
{
|
||
if ( 0x0006 == nTag )
|
||
{
|
||
m_sComment += _T("CanonImageType: ") + sCur;
|
||
m_sComment += _T("\n");
|
||
}
|
||
else if ( 0x0007 == nTag )
|
||
{
|
||
m_sComment += sCur;
|
||
m_sComment += _T("\n");
|
||
}
|
||
else if ( 0x0009 == nTag )
|
||
m_sAuthor = sCur;
|
||
|
||
}
|
||
if ( -1 != m_sEquipmentType.Find(_T("Casio")) )
|
||
{
|
||
if ( 0x3006 == nTag )
|
||
{
|
||
m_sComment += _T("HometownCity: ") + sCur;
|
||
m_sComment += _T("\n");
|
||
}
|
||
|
||
}
|
||
|
||
if ( -1 != m_sEquipmentType.Find(_T("FUJIFILM")) )
|
||
{
|
||
if ( 0x8000 == nTag ) // fileSource
|
||
m_sDocumentName = sCur;
|
||
}
|
||
if ( -1 != m_sEquipmentType.Find(_T("Kodak")) )
|
||
{
|
||
if ( 8 == nTag && m_sEquipmentType.GetLength() < 1 )
|
||
m_sEquipmentType = sCur;
|
||
else if ( 40 == nTag && m_sEquipmentModel.GetLength() < 1 )
|
||
m_sEquipmentModel = sCur;
|
||
else if ( 32 == nType ) // originalFileName
|
||
m_sDocumentName = sCur;
|
||
}
|
||
if ( -1 != m_sEquipmentType.Find(_T("Sigma")) || -1 != m_sEquipmentType.Find(_T("Foevon")) )
|
||
{
|
||
if ( 0x0017 == nTag )
|
||
{
|
||
m_sComment += sCur.GetBuffer();
|
||
m_sComment += "\n";
|
||
}
|
||
else if ( 0x0018 == nTag )
|
||
m_sSoftwareID = sCur;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
void ReadRawIFD(BYTE* pnFile, unsigned short nIFDTag, DWORD nIFDOffset, unsigned long nByteOrder, int nIndex, DWORD nBaseOffset)
|
||
{
|
||
BYTE *nStartPoint = pnFile + nIFDOffset;
|
||
|
||
// проверяем makernote или нет
|
||
if ( 37500 == nIFDTag )
|
||
{
|
||
ReadMakerNote(nStartPoint, nByteOrder, pnFile, nBaseOffset);
|
||
return;
|
||
}
|
||
|
||
else if ( 0 == nIFDTag || //
|
||
34665 == nIFDTag )//exif
|
||
{
|
||
int nBitPerSample = 1, nSamplePerPixel = 1;
|
||
|
||
int nDirectoryEntryCount = IntFromBytes2(nStartPoint, nByteOrder);
|
||
if ( nDirectoryEntryCount > 512)
|
||
return;
|
||
for ( int nIndex = 0; nIndex < nDirectoryEntryCount; nIndex++ )
|
||
{
|
||
BYTE *pCurDirectory = nStartPoint + 2 + 12 * nIndex;
|
||
|
||
//int r1 = IntFromBytes2(nStartPoint + 12 * nIndex,0);
|
||
|
||
const TDirectoryEntry& oDirEntry = *(TDirectoryEntry*)(pCurDirectory);
|
||
int nTag = IntFromBytes2(oDirEntry.nTag, nByteOrder);
|
||
int nType = IntFromBytes2(oDirEntry.nType, nByteOrder);
|
||
int nCount = IntFromBytes4(oDirEntry.nCount, nByteOrder);
|
||
int nValueOffset = IntFromBytes4(oDirEntry.nValueOffset, nByteOrder);
|
||
|
||
nValueOffset += nBaseOffset;
|
||
if ( 34665 == nTag ) // ExifIDFTag
|
||
ReadRawIFD( pnFile, nTag, nValueOffset, nByteOrder, nIndex, nBaseOffset);
|
||
// если тип Value меньше 4 байт, тогда в переменной ValueOffset
|
||
// указан не сдвиг, а самое значение Value (см., например, таг = 297)
|
||
|
||
if (PropertyTagTypeASCII == nType )
|
||
{
|
||
CString sCur = _T("");
|
||
if (nCount <= 4)
|
||
{
|
||
sCur = TGAASKIIValue(oDirEntry.nValueOffset, nCount);
|
||
}
|
||
else
|
||
{
|
||
for (int nI = 0; nI < nCount; nI++ )
|
||
sCur += (pnFile + nValueOffset)[nI];
|
||
}
|
||
switch ( nTag )
|
||
{
|
||
case 269: m_sDocumentName = sCur; break;
|
||
case 270: m_sDescription = sCur; break;
|
||
case 271: m_sEquipmentType = sCur; break;
|
||
case 272: m_sEquipmentModel = sCur; break;
|
||
case 305: m_sSoftwareID = sCur; break;
|
||
case 306:
|
||
{
|
||
// формат строки "YYYY:MM:DD HH:MM:SS"
|
||
m_oDateTimeCreation.nYear = _ttoi( TGAASKIIValue(pnFile + nValueOffset, 4) );
|
||
m_oDateTimeCreation.nMonth = _ttoi( TGAASKIIValue(pnFile + nValueOffset + 5, 2) );
|
||
m_oDateTimeCreation.nDay = _ttoi( TGAASKIIValue(pnFile + nValueOffset + 8, 2) );
|
||
m_oDateTimeCreation.nHour = _ttoi( TGAASKIIValue(pnFile + nValueOffset + 11, 2) );
|
||
m_oDateTimeCreation.nMinute = _ttoi( TGAASKIIValue(pnFile + nValueOffset + 14, 2) );
|
||
m_oDateTimeCreation.nSecond = _ttoi( TGAASKIIValue(pnFile + nValueOffset + 17, 2) );
|
||
break;
|
||
}
|
||
case 315: m_sAuthor = sCur; break;
|
||
case 316: m_sHostComputer = sCur; break;
|
||
case 330:
|
||
// тут лежит SubIFD надо бы ее разобрать
|
||
break;
|
||
case 800: m_sTitle = sCur; break;
|
||
default:
|
||
AtlTrace ("id = 0x%x\tvalue = %s\n",nTag ,sCur);
|
||
|
||
}
|
||
}
|
||
else if ( PropertyTagTypeShort == nType || PropertyTagTypeLong == nType)
|
||
{
|
||
int nValue = 0;
|
||
if (PropertyTagTypeShort == nType)nValue = IntFromBytes2( oDirEntry.nValueOffset, nByteOrder );
|
||
if (PropertyTagTypeLong == nType) nValue = IntFromBytes4( oDirEntry.nValueOffset, nByteOrder );
|
||
switch(nTag)
|
||
{
|
||
case 0x0102:
|
||
{
|
||
nBitPerSample = nValue;
|
||
}break;
|
||
case 0x0115:
|
||
{
|
||
nSamplePerPixel = nValue;
|
||
}break;
|
||
case 297:
|
||
{
|
||
m_nPageNumber = (BYTE)oDirEntry.nValueOffset[0];
|
||
m_nPagesCount = (BYTE)oDirEntry.nValueOffset[1];
|
||
}break;
|
||
case 274:
|
||
{
|
||
m_nOrientation = max( 1, min( 8, nValue ));
|
||
}break;
|
||
case 0x8822:
|
||
{
|
||
m_nExposureProgram = nValue;
|
||
}break;
|
||
case 0x8827:
|
||
{
|
||
m_nISOSpeed = nValue;
|
||
}break;
|
||
case 0x9207:
|
||
{
|
||
m_nMeteringMode = nValue;
|
||
}break;
|
||
case 0x9209:
|
||
{
|
||
m_nFlashMode = nValue;
|
||
}
|
||
break;
|
||
case 0xA001:
|
||
{
|
||
m_nColorSpace = nValue;
|
||
}break;
|
||
case 0xa217:
|
||
{
|
||
m_nSensingMethod = nValue;
|
||
}break;
|
||
case 0xa402:
|
||
{
|
||
m_nExposureMode = nValue;
|
||
}break;
|
||
case 0xa403:
|
||
{
|
||
m_nWhiteBalance = nValue;
|
||
}break;
|
||
case 0xa405:
|
||
{
|
||
m_nFocalLengthIn35mmFilm = nValue;
|
||
}break;
|
||
default:
|
||
{
|
||
AtlTrace ("id = 0x%x\tvalue = %d\n",nTag,nValue);
|
||
}
|
||
}
|
||
}
|
||
else if ( PropertyTagTypeRational == nType || PropertyTagTypeSRational == nType)
|
||
{
|
||
int nFraction = (int)IntFromBytes4( pnFile + nValueOffset, nByteOrder );
|
||
int nDenominator = (int)IntFromBytes4( pnFile + nValueOffset + 4, nByteOrder );
|
||
switch(nTag)
|
||
{
|
||
case 0x829A:
|
||
{
|
||
m_oExposureTime.Fraction = (unsigned int)nFraction;
|
||
m_oExposureTime.Denominator = (unsigned int)nDenominator;
|
||
}break;
|
||
case 0x9201:
|
||
{
|
||
m_oShutterSpeed.Fraction = nFraction;
|
||
m_oShutterSpeed.Denominator = nDenominator;
|
||
}break;
|
||
case 0x9202:
|
||
{
|
||
m_oLensAperture.Fraction = (unsigned int)nFraction;
|
||
m_oLensAperture.Denominator = (unsigned int)nDenominator;
|
||
}break;
|
||
case 0x9203:
|
||
{
|
||
m_oBrightness.Fraction = (int)nFraction;
|
||
m_oBrightness.Denominator = (int)nDenominator;
|
||
}break;
|
||
case 0x9204:
|
||
{
|
||
m_oExposureCompensation.Fraction = (int)nFraction;
|
||
m_oExposureCompensation.Denominator = (int)nDenominator;
|
||
}break;
|
||
case 0x920A:
|
||
{
|
||
m_oFocalLength.Fraction = (unsigned int)nFraction;
|
||
m_oFocalLength.Denominator = (unsigned int)nDenominator;
|
||
}break;
|
||
case 0x829D:
|
||
{
|
||
m_oFNumber.Fraction = (unsigned int)nFraction;
|
||
m_oFNumber.Denominator = (unsigned int)nDenominator;
|
||
|
||
}break;
|
||
case 0x9205:
|
||
{
|
||
m_oMaxApertureValue.Fraction = (unsigned int)nFraction;
|
||
m_oMaxApertureValue.Denominator = (unsigned int)nDenominator;
|
||
|
||
}break;
|
||
default:
|
||
{
|
||
AtlTrace ("id = 0x%x\tvalue = %d/%d\n",nTag ,nFraction,nDenominator);
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
if ( m_nBitDepth <= 1 )
|
||
m_nBitDepth = nBitPerSample * nSamplePerPixel;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
// Raw-foveon functions
|
||
BOOL CheckFoveonSignature(BYTE* pnFile)
|
||
{
|
||
// первые четыре байта должны быть FOVb
|
||
|
||
CString sSignature = TGAASKIIValue(pnFile, 4);
|
||
if ( -1 != sSignature.Find(_T("FOVb")) )
|
||
return TRUE;
|
||
|
||
return FALSE;
|
||
}
|
||
void UTF16ToASKII(BYTE** pResult, BYTE* pSource, DWORD nLenght)
|
||
{
|
||
for ( int nIndex = 0; nIndex < nLenght; nIndex++ )
|
||
(*pResult)[nIndex] = pSource[nIndex * 2];
|
||
}
|
||
CString FoveonASKIIValue(const BYTE* pCurPoint, DWORD nTotalLenght)
|
||
{
|
||
CString sReturn = _T("");
|
||
int nIndex = 0;
|
||
while( 0 != pCurPoint[nIndex] && nIndex < nTotalLenght)
|
||
{
|
||
sReturn += pCurPoint[nIndex];
|
||
nIndex++;
|
||
}
|
||
|
||
return sReturn;
|
||
}
|
||
// Ras functions
|
||
DWORD ReverseDword(DWORD dwValue)
|
||
{
|
||
DWORD dwResult;
|
||
|
||
((BYTE*)&dwResult)[0] = ((BYTE*)&dwValue)[3];
|
||
((BYTE*)&dwResult)[1] = ((BYTE*)&dwValue)[2];
|
||
((BYTE*)&dwResult)[2] = ((BYTE*)&dwValue)[1];
|
||
((BYTE*)&dwResult)[3] = ((BYTE*)&dwValue)[0];
|
||
|
||
return dwResult;
|
||
}
|
||
|
||
// J2k functions
|
||
BOOL ReadJpxBoxHeader (BYTE **ppPointer, DWORD *pnMaxBytesRead, unsigned int *punBoxType, unsigned int *punBoxLen, unsigned int *punDataLen)
|
||
{
|
||
unsigned int unLenH;
|
||
|
||
if ( 8 > (*pnMaxBytesRead) )
|
||
return FALSE;
|
||
|
||
(*pnMaxBytesRead) -= 8;
|
||
|
||
unsigned int unLen = (unsigned int)IntFromBytes4( (*ppPointer), 0 ); (*ppPointer) += 4;
|
||
*punBoxType = (unsigned int)IntFromBytes4( (*ppPointer), 0 ); (*ppPointer) += 4;
|
||
|
||
if ( 1 == unLen )
|
||
{
|
||
if ( 0 > (*pnMaxBytesRead) )
|
||
return FALSE;
|
||
|
||
(*pnMaxBytesRead) -= 8;
|
||
|
||
unLenH = (unsigned int)IntFromBytes4( (*ppPointer), 0 ); (*ppPointer) += 4;
|
||
unLen = (unsigned int)IntFromBytes4( (*ppPointer), 0 ); (*ppPointer) += 4;
|
||
|
||
if ( unLenH )
|
||
return FALSE;
|
||
|
||
*punBoxLen = unLen;
|
||
*punDataLen = unLen - 16;
|
||
}
|
||
else if ( 0 == unLen )
|
||
{
|
||
*punBoxLen = 0;
|
||
*punDataLen = 0;
|
||
}
|
||
else
|
||
{
|
||
*punBoxLen = unLen;
|
||
*punDataLen = unLen - 8;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL ReadJpxMarkerHeader(BYTE **ppPointer, DWORD *pnMaxBytesRead, int *pnSegmentType, unsigned int *pnSegmentLen)
|
||
{
|
||
int nChar = 0;
|
||
|
||
do
|
||
{
|
||
do
|
||
{
|
||
if ( 1 > (*pnMaxBytesRead) )
|
||
return FALSE;
|
||
|
||
(*pnMaxBytesRead)--;
|
||
|
||
nChar = (*ppPointer)[0]; (*ppPointer)++;
|
||
|
||
if ( nChar == EOF )
|
||
return FALSE;
|
||
|
||
} while ( nChar != 0xff );
|
||
do
|
||
{
|
||
if ( 1 > (*pnMaxBytesRead) )
|
||
return FALSE;
|
||
|
||
(*pnMaxBytesRead)--;
|
||
|
||
nChar = (*ppPointer)[0]; (*ppPointer)++;
|
||
|
||
if ( nChar == EOF)
|
||
return FALSE;
|
||
} while ( nChar == 0xff );
|
||
} while ( nChar == 0x00 );
|
||
|
||
*pnSegmentType = nChar;
|
||
if ( ( nChar >= 0x30 && nChar <= 0x3f ) || nChar == 0x4f || nChar == 0x92 || nChar == 0x93 || nChar == 0xd9 )
|
||
{
|
||
*pnSegmentLen = 0;
|
||
return TRUE;
|
||
}
|
||
|
||
if ( 2 > (*pnMaxBytesRead) )
|
||
return FALSE;
|
||
|
||
(*pnMaxBytesRead) -= 2;
|
||
|
||
*pnSegmentLen = IntFromBytes2( (*ppPointer), 0 ); (*ppPointer) += 2;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL ReadJpxCodestream (BYTE **ppPointer, DWORD *pnMaxBytesRead, unsigned int *pnBitsPerComponent, unsigned int *pnWidth, unsigned int *pnHeight, unsigned int *pnComponentCount)
|
||
{
|
||
int nSegmentType;
|
||
unsigned int nSegmentLen;
|
||
|
||
|
||
while ( ReadJpxMarkerHeader( ppPointer, pnMaxBytesRead, &nSegmentType, &nSegmentLen ) )
|
||
{
|
||
if ( 0x51 == nSegmentType )
|
||
{
|
||
unsigned int nComponentsCount, nBPC, nXsiz, nYsiz, nXOsiz, nYOsiz;
|
||
|
||
if ( 37 > (*pnMaxBytesRead) )
|
||
return FALSE;
|
||
|
||
(*pnMaxBytesRead) -= 37;
|
||
|
||
(*ppPointer) += 2;
|
||
nXsiz = IntFromBytes4( (*ppPointer), 0 ); (*ppPointer) += 4;
|
||
nYsiz = IntFromBytes4( (*ppPointer), 0 ); (*ppPointer) += 4;
|
||
nXOsiz = IntFromBytes4( (*ppPointer), 0 ); (*ppPointer) += 4;
|
||
nYOsiz = IntFromBytes4( (*ppPointer), 0 ); (*ppPointer) += 4;
|
||
(*ppPointer) += 16;
|
||
nComponentsCount = IntFromBytes2( (*ppPointer), 0 ); (*ppPointer) += 2;
|
||
nBPC = (*ppPointer)[0]; (*ppPointer)++;
|
||
|
||
*pnBitsPerComponent = (nBPC & 0x7f) + 1;
|
||
*pnWidth = nXsiz - nXOsiz;
|
||
*pnHeight = nYsiz - nYOsiz;
|
||
|
||
*pnComponentCount = nComponentsCount;
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
BOOL ReadJpxHeader(BYTE *pnFile, DWORD nFileSize)
|
||
{
|
||
BYTE *pPointer = pnFile;
|
||
DWORD nBytesLeft = nFileSize;
|
||
|
||
if ( 1 > nBytesLeft )
|
||
return FALSE;
|
||
|
||
// Считываем первый символ
|
||
int nChar = pPointer[0];
|
||
|
||
unsigned int nBitsPerComponent = 1;
|
||
unsigned int nCSPrec = 0;
|
||
unsigned int nWidth = 0, nHeight = 0;
|
||
unsigned int nComponentsCount = 1;
|
||
|
||
if ( 0xff == nChar )
|
||
{
|
||
if ( !ReadJpxCodestream( &pPointer, &nBytesLeft, &nBitsPerComponent, &nWidth, &nHeight, &nComponentsCount ) )
|
||
return FALSE;
|
||
}
|
||
else
|
||
{
|
||
BOOL bHaveJp2Header = FALSE;
|
||
unsigned int nBoxType, nBoxLen, nDataLen;
|
||
|
||
while( ReadJpxBoxHeader( &pPointer, &nBytesLeft, &nBoxType, &nBoxLen, &nDataLen ) )
|
||
{
|
||
if ( nBoxType == 0x6a703268 ) // JP2 header
|
||
{
|
||
bHaveJp2Header = TRUE;
|
||
}
|
||
else if ( nBoxType == 0x69686472 ) // Image header
|
||
{
|
||
if ( 14 > nBytesLeft )
|
||
return FALSE;
|
||
|
||
nBytesLeft -= 14;
|
||
|
||
nBitsPerComponent = pPointer[10] + 1;
|
||
|
||
pPointer += 14;
|
||
}
|
||
else if ( nBoxType == 0x6A703263 ) // Codestream
|
||
{
|
||
if ( !ReadJpxCodestream( &pPointer, &nBytesLeft, &nBitsPerComponent, &nWidth, &nHeight, &nComponentsCount ) )
|
||
return FALSE;
|
||
}
|
||
else
|
||
{
|
||
if ( nDataLen > nBytesLeft )
|
||
break;
|
||
|
||
nBytesLeft -= nDataLen;
|
||
|
||
pPointer += nDataLen;
|
||
}
|
||
}
|
||
|
||
if ( !bHaveJp2Header )
|
||
return FALSE;
|
||
}
|
||
|
||
m_nBitDepth = nBitsPerComponent * nComponentsCount;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
// Load MetaData functions
|
||
BOOL LoadTiffMetaData(BYTE* pnFile, DWORD nFileSize)
|
||
{
|
||
if ( !m_bBitmap )
|
||
return FALSE;
|
||
|
||
BYTE *pLastPointer = pnFile + nFileSize;
|
||
int nTiffType = -1;
|
||
|
||
const TTiffFileHeader& oHeader = *(TTiffFileHeader*)pnFile;
|
||
CString sByteOrder(oHeader.nByteOrder);
|
||
|
||
if ( -1 != sByteOrder.Find(_T("II"), 0) )
|
||
nTiffType = 1;
|
||
else if ( -1 != sByteOrder.Find(_T("MM"), 0) )
|
||
nTiffType = 0;
|
||
else
|
||
return FALSE;
|
||
|
||
int nSignature = IntFromBytes2(oHeader.nSignature, nTiffType);
|
||
if ( 42 != nSignature )
|
||
return FALSE;
|
||
|
||
int nOffset = IntFromBytes4( oHeader.nIDFoffset, nTiffType);
|
||
|
||
BYTE* pIDF = pnFile + nOffset;
|
||
if ( pIDF > pLastPointer )
|
||
return FALSE;
|
||
|
||
int nBitPerSample = 1, nSamplePerPixel = 1;
|
||
|
||
BYTE* pCurDirectory;
|
||
int nDirectoryEntryCount = IntFromBytes2(pIDF, nTiffType);
|
||
for ( int nIndex = 0; nIndex < nDirectoryEntryCount; nIndex++ )
|
||
{
|
||
pCurDirectory = pIDF + 2 + 12 * nIndex;
|
||
if ( pCurDirectory > pLastPointer )
|
||
return FALSE;
|
||
const TDirectoryEntry& oDirEntry = *(TDirectoryEntry*)(pCurDirectory);
|
||
int nTag = IntFromBytes2(oDirEntry.nTag, nTiffType);
|
||
int nType = IntFromBytes2(oDirEntry.nType, nTiffType);
|
||
int nCount = IntFromBytes4(oDirEntry.nCount, nTiffType);
|
||
int nValueOffset = IntFromBytes4(oDirEntry.nValueOffset, nTiffType);
|
||
// если тип Value меньше 4 байт, тогда в переменной ValueOffset
|
||
// указан не сдвиг, а самое значение Value (см., например, таг = 297)
|
||
|
||
if ( 2 == nType ) // значение типa ASCII
|
||
{
|
||
CString sCur = _T("");
|
||
if (nCount <= 4)
|
||
{
|
||
sCur = TGAASKIIValue(oDirEntry.nValueOffset, nCount);
|
||
}
|
||
else
|
||
{
|
||
for (int nI = 0; nI < nCount; nI++ )
|
||
sCur += (pnFile + nValueOffset)[nI];
|
||
}
|
||
switch ( nTag )
|
||
{
|
||
case 269: m_sDocumentName = sCur; break;
|
||
case 270: m_sDescription = sCur; break;
|
||
case 271: m_sEquipmentType = sCur; break;
|
||
case 272: m_sEquipmentModel = sCur; break;
|
||
case 305: m_sSoftwareID = sCur; break;
|
||
case 306:
|
||
{
|
||
// формат строки "YYYY:MM:DD HH:MM:SS"
|
||
m_oDateTimeCreation.nYear = _ttoi( TGAASKIIValue(pnFile + nValueOffset, 4) );
|
||
m_oDateTimeCreation.nMonth = _ttoi( TGAASKIIValue(pnFile + nValueOffset + 5, 2) );
|
||
m_oDateTimeCreation.nDay = _ttoi( TGAASKIIValue(pnFile + nValueOffset + 8, 2) );
|
||
m_oDateTimeCreation.nHour = _ttoi( TGAASKIIValue(pnFile + nValueOffset + 11, 2) );
|
||
m_oDateTimeCreation.nMinute = _ttoi( TGAASKIIValue(pnFile + nValueOffset + 14, 2) );
|
||
m_oDateTimeCreation.nSecond = _ttoi( TGAASKIIValue(pnFile + nValueOffset + 17, 2) );
|
||
break;
|
||
}
|
||
case 315: m_sAuthor = sCur; break;
|
||
case 316: m_sHostComputer = sCur; break;
|
||
case 800: m_sTitle = sCur; break;
|
||
}
|
||
}
|
||
else if ( 3 == nType ) // значение типа short
|
||
{
|
||
if ( 0x0102 == nTag )
|
||
{
|
||
nBitPerSample = (short)IntFromBytes2(oDirEntry.nValueOffset, nTiffType);
|
||
}
|
||
else if ( 0x0115 == nTag )
|
||
{
|
||
nSamplePerPixel = (short)IntFromBytes2(oDirEntry.nValueOffset, nTiffType);
|
||
}
|
||
else if ( 297 == nTag )
|
||
{
|
||
m_nPageNumber = (BYTE)oDirEntry.nValueOffset[0];
|
||
m_nPagesCount = (BYTE)oDirEntry.nValueOffset[1];
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
|
||
if ( m_nBitDepth <= 1 )
|
||
m_nBitDepth = nBitPerSample * nBitPerSample;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL LoadPNGMetaData(BYTE* pnFile, DWORD nFileSize)
|
||
{
|
||
if ( !m_bBitmap )
|
||
return FALSE;
|
||
|
||
// проверяем сигнатуру PNG файла
|
||
|
||
if ( !CheckPNGSignature(pnFile) )
|
||
return FALSE;
|
||
|
||
BYTE* pCurPoint = pnFile + 8;
|
||
|
||
const TChunk& oFirstChunk = *(TChunk*)pCurPoint;
|
||
CString sType = ChunkType(oFirstChunk.nType);
|
||
|
||
if ( -1 == sType.Find(_T("IHDR")) )
|
||
return FALSE;
|
||
|
||
DWORD nBytesAlreadyRead = 8;
|
||
int nLenght = IntFromBytes4(oFirstChunk.nLenght, 0);
|
||
int nChunkSize = nLenght + 12;
|
||
|
||
nBytesAlreadyRead += nChunkSize;
|
||
|
||
while ( -1 == sType.Find(_T("IEND")) && nBytesAlreadyRead < nFileSize )
|
||
{
|
||
pCurPoint += nChunkSize;
|
||
|
||
|
||
const TChunk& oCurChunk = *(TChunk*)pCurPoint;
|
||
sType = ChunkType(oCurChunk.nType);
|
||
nLenght = IntFromBytes4(oCurChunk.nLenght, 0);
|
||
nChunkSize = nLenght + 12;
|
||
|
||
// чексуммы последних четырех байтов
|
||
crc32 oCRC;
|
||
oCRC.ProcessCRC(pCurPoint + 4, 4 + nLenght);
|
||
BYTE pCRC[4] = {(pCurPoint + 8 + nLenght)[0], (pCurPoint + 8 + nLenght)[1], (pCurPoint + 8 + nLenght)[2], (pCurPoint + 8 + nLenght)[3]};
|
||
DWORD nCRC = IntFromBytes4( pCRC, 0);
|
||
if ( oCRC.m_crc32 != nCRC)
|
||
return FALSE;
|
||
|
||
if ( -1 != sType.Find(_T("zTXt")) )
|
||
{
|
||
CString sKeyword = _T(""), sValue = _T("");
|
||
int nIndex = 0;
|
||
for ( ; nIndex < nLenght && (pCurPoint + 8)[nIndex] != 0; nIndex++ )
|
||
sKeyword += (pCurPoint + 8)[nIndex];
|
||
|
||
nIndex++;
|
||
int nCompressionMethod = (pCurPoint + 8)[nIndex];
|
||
|
||
nIndex++;
|
||
|
||
|
||
|
||
//for ( ; nIndex < nLenght; nIndex++ )
|
||
// sValue += (pCurPoint + 8)[nIndex];
|
||
|
||
//Stream^ ms = gcnew Stream;
|
||
|
||
//ms->Position = 0;
|
||
//for (int nI = nIndex; nI < nLenght; nI++ )
|
||
// ms->WriteByte((pCurPoint + 8)[nI]);
|
||
////ms->EndWrite();
|
||
//ms->Position = 0;
|
||
//DeflateStream ^zipStream = gcnew DeflateStream(ms , CompressionMode::Decompress);
|
||
//for (int nI = nIndex; nI < nLenght; nI++ )
|
||
// zipStream->WriteByte((pCurPoint + 8)[nI]);
|
||
//
|
||
//for (int i = 0 ; i < ms->Length; i++ )
|
||
//{
|
||
// BYTE nCurByte;
|
||
// nCurByte = zipStream->ReadByte();
|
||
// sValue += nCurByte;
|
||
//}
|
||
////zipStream->Write( pCurPoint + 8 + nIndex, 0, nLength );
|
||
|
||
//
|
||
////Stream
|
||
|
||
//array<Byte>^decompressedBuffer = gcnew array<Byte>(nLenght + 100);
|
||
|
||
}
|
||
if ( -1 != sType.Find(_T("iTXt")) )
|
||
{
|
||
CString sKeyword = _T("");
|
||
int nIndex = 0;
|
||
|
||
for ( ; nIndex < nLenght && (pCurPoint + 8)[nIndex] != 0; nIndex++ )
|
||
sKeyword += (pCurPoint + 8)[nIndex];
|
||
|
||
nIndex++;
|
||
|
||
int nCompressionFlag = (pCurPoint + 8)[nIndex];
|
||
int nCompressionMethod = (pCurPoint + 8)[nIndex + 1];
|
||
|
||
nIndex += 2;
|
||
|
||
CString sLanguageTag = _T("");
|
||
|
||
for ( ; nIndex < nLenght && (pCurPoint + 8)[nIndex] != 0; nIndex++ )
|
||
sLanguageTag += (pCurPoint + 8)[nIndex];
|
||
|
||
nIndex ++;
|
||
|
||
CString sText = _T("");
|
||
|
||
for ( ; nIndex < nLenght && (pCurPoint + 8)[nIndex] != 0; nIndex++ )
|
||
sText += (pCurPoint + 8)[nIndex];
|
||
|
||
|
||
}
|
||
if ( -1 != sType.Find(_T("tEXt")) )
|
||
{
|
||
CString sKeyword = _T(""), sValue = _T("");
|
||
int nIndex = 0;
|
||
for ( ; nIndex < nLenght && (pCurPoint + 8)[nIndex] != 0; nIndex++ )
|
||
sKeyword += (pCurPoint + 8)[nIndex];
|
||
nIndex++;
|
||
|
||
for ( ; nIndex < nLenght; nIndex++ )
|
||
sValue += (pCurPoint + 8)[nIndex];
|
||
|
||
if ( -1 != sKeyword.Find(_T("Title")) )
|
||
m_sTitle = sValue;
|
||
else if ( -1 != sKeyword.Find(_T("Author")) )
|
||
m_sAuthor = sValue;
|
||
else if ( -1 != sKeyword.Find(_T("Description")) )
|
||
m_sDescription = sValue;
|
||
else if ( -1 != sKeyword.Find(_T("Copyright")) )
|
||
m_sCopyright = sValue;
|
||
else if ( -1 != sKeyword.Find(_T("Software")) )
|
||
m_sSoftwareID = sValue;
|
||
else if ( -1 != sKeyword.Find(_T("Disclaimer")) )
|
||
m_sDisclaimer = sValue;
|
||
else if ( -1 != sKeyword.Find(_T("Warning")) )
|
||
m_sWarning = sValue;
|
||
else if ( -1 != sKeyword.Find(_T("Source")) )
|
||
m_sEquipmentType = sValue;
|
||
else if ( -1 != sKeyword.Find(_T("Comment")) )
|
||
m_sComment = sValue;
|
||
else if ( -1 != sKeyword.Find(_T("Creation Time")) )
|
||
m_oDateTimeCreation.sSummary = sValue;
|
||
|
||
}
|
||
if ( -1 != sType.Find(_T("tIME")) )
|
||
{
|
||
const TChunkTIME& oTIMEChunk = *(TChunkTIME*)(pCurPoint + 8);
|
||
int nYear = IntFromBytes2(oTIMEChunk.nYear, 0);
|
||
|
||
}
|
||
if ( -1 != sType.Find(_T("acTL")) )
|
||
{
|
||
const TChunkACTL& oACTLChunk = *(TChunkACTL*)(pCurPoint + 8);
|
||
unsigned int unNumFrames = IntFromBytes4( oACTLChunk.unNumFrames, 0 );
|
||
unsigned int unNumPlays = IntFromBytes4( oACTLChunk.unNumPlays, 0 );
|
||
if ( unNumFrames > 1 )
|
||
m_bMultiPageImage = TRUE;
|
||
}
|
||
|
||
nBytesAlreadyRead += nLenght + 12;
|
||
}
|
||
|
||
|
||
return TRUE;
|
||
}
|
||
BOOL LoadTGAMetaData(BYTE* pnFile, DWORD nFileSize)
|
||
{
|
||
if ( m_bBitmap )
|
||
return FALSE;
|
||
|
||
// ищем FileFooter (26 последних байт в файле), если он есть
|
||
|
||
BOOL bNewTGA = FALSE;
|
||
|
||
if ( nFileSize < 26 )
|
||
return FALSE;
|
||
|
||
// Cчитываем Bit Depth (16-ый байт в файле)
|
||
if ( m_nBitDepth <= 1 )
|
||
m_nBitDepth = (short)pnFile[16];
|
||
|
||
BYTE* pnFileFooter = pnFile + nFileSize - 26 * sizeof(BYTE);
|
||
|
||
const TFileFooter& oFooter = *(TFileFooter*)pnFileFooter;
|
||
|
||
BYTE aTemp[19];
|
||
::memcpy( aTemp, oFooter.arrSignature, 18);
|
||
aTemp[18] = '\0';
|
||
|
||
CString sSignature(aTemp);
|
||
|
||
if ( oFooter.nExtensionAreaOffset > nFileSize )
|
||
return FALSE;
|
||
|
||
// Проверяем версию TGA, если в конце есть строка "TRUEVISION-XFILE"
|
||
// значит TGA версии 2.0
|
||
if ( -1 != sSignature.Find(_T("TRUEVISION-XFILE"), 0) && 0 != oFooter.nExtensionAreaOffset )
|
||
{
|
||
BYTE* pnExtArea = pnFile + oFooter.nExtensionAreaOffset * sizeof(BYTE);
|
||
const TExtensionArea& oExtArea = *(TExtensionArea*)pnExtArea;
|
||
|
||
// проверяем валидность формата: если значение не 495, то
|
||
// это не TGA 2.0
|
||
if ( 495 == oExtArea.nExtensionSize )
|
||
{
|
||
m_sAuthor = TGAASKIIValue(oExtArea.sAuthorName, 41);
|
||
m_sComment = TGAASKIIValue(oExtArea.sComments, 324);
|
||
m_oDateTimeCreation.nYear = oExtArea.nDateTime[2];
|
||
m_oDateTimeCreation.nMonth = oExtArea.nDateTime[0];
|
||
m_oDateTimeCreation.nDay = oExtArea.nDateTime[1];
|
||
m_oDateTimeCreation.nHour = oExtArea.nDateTime[3];
|
||
m_oDateTimeCreation.nMinute = oExtArea.nDateTime[4];
|
||
m_oDateTimeCreation.nSecond = oExtArea.nDateTime[5];
|
||
|
||
m_sJobName = TGAASKIIValue(oExtArea.sJobName, 41);
|
||
m_oJobTime.nHour = oExtArea.nJobTime[0];
|
||
m_oJobTime.nMinute = oExtArea.nJobTime[1];
|
||
m_oJobTime.nSecond = oExtArea.nJobTime[2];
|
||
|
||
m_sSoftwareID = TGAASKIIValue(oExtArea.sSoftwareID, 41);
|
||
|
||
m_nVersionNumber = oExtArea.nSoftwareVersionNumber;
|
||
m_sVersionLetter += oExtArea.nSoftwareVersionLetter;
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
else
|
||
{
|
||
return FALSE;
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
BOOL LoadFoveonMetaData(BYTE* pnFile, DWORD nFileSize)
|
||
{
|
||
if ( m_bBitmap )
|
||
return FALSE;
|
||
|
||
// это Raw формат, но метаданные в нем имеют
|
||
// струтуру отличную от tiff, поэтому читаются
|
||
// отдельным способом
|
||
|
||
if ( !CheckFoveonSignature(pnFile) )
|
||
return FALSE;
|
||
|
||
// смещяемся на последние 4 байта, там хранится смещение
|
||
// на Directory Section
|
||
|
||
const int nByteOrder = 1;
|
||
|
||
BYTE* pCurPoint = pnFile + nFileSize - 4;
|
||
|
||
DWORD nDirectoryOffset = IntFromBytes4(pCurPoint, nByteOrder);
|
||
// считываем заголовок Directory Section (12 байт)
|
||
|
||
if ( nDirectoryOffset > nFileSize )
|
||
return FALSE;
|
||
pCurPoint = pnFile + nDirectoryOffset;
|
||
|
||
|
||
const TFoveonDirectorySectionHeader &oDirectoryHeader = *(TFoveonDirectorySectionHeader *) pCurPoint;
|
||
|
||
// проверяем сигнатуру Directory Section, должна быть SECd
|
||
if ( !(oDirectoryHeader.pSignature[0] == 'S' && oDirectoryHeader.pSignature[1] == 'E' &&
|
||
oDirectoryHeader.pSignature[2] == 'C' && oDirectoryHeader.pSignature[3] == 'd') )
|
||
return FALSE;
|
||
|
||
DWORD nDirectoryCount = oDirectoryHeader.nDirectoryEntriesCount;
|
||
pCurPoint += 12;
|
||
|
||
for ( int nIndex = 0; nIndex < nDirectoryCount; nIndex++, pCurPoint += 12 )
|
||
{
|
||
const TFoveonDirectoryEntries &oEntry = *(TFoveonDirectoryEntries *) pCurPoint;
|
||
|
||
CString sType = TGAASKIIValue(oEntry.pType, 4);
|
||
DWORD nLenght = oEntry.nLenght;
|
||
DWORD nOffset = oEntry.nOffeset;
|
||
|
||
if ( -1 != sType.Find(_T("PROP")) )
|
||
{
|
||
BYTE* pPROP = pnFile + nOffset;
|
||
const TFoveonPROPHeader &oPROPHeader = *(TFoveonPROPHeader *) pPROP;
|
||
|
||
CString sPROPSignature = TGAASKIIValue(oPROPHeader.pSignature, 4);
|
||
// проверяем сигнатуру PROP, должна быть SECp
|
||
if ( -1 == sPROPSignature.Find(_T("SECp")) )
|
||
continue;
|
||
|
||
DWORD nPROPCount = oPROPHeader.nEntriesCount;
|
||
// 13 - максимальная длина имени типа, а именно IMAGERBOARDID
|
||
DWORD nNameLenght = min(13, oPROPHeader.nTotalLenght);
|
||
|
||
BYTE* pPROPEntry = pPROP + 24;
|
||
|
||
BYTE* pData = new BYTE[oPROPHeader.nTotalLenght];
|
||
BYTE* pDataStart = pPROP + 24 + 8 * nPROPCount;
|
||
UTF16ToASKII(&pData, pDataStart, oPROPHeader.nTotalLenght);
|
||
|
||
for ( int nPROPIndex = 0; nPROPIndex < nPROPCount; nPROPIndex++, pPROPEntry += 8 )
|
||
{
|
||
const TFoveonPROPOffsets oOffsets = *(TFoveonPROPOffsets *) pPROPEntry;
|
||
CString sName = FoveonASKIIValue(pData + oOffsets.nName, oPROPHeader.nTotalLenght);
|
||
CString sValue = FoveonASKIIValue(pData + oOffsets.nValue, oPROPHeader.nTotalLenght);
|
||
|
||
if ( -1 != sName.Find(_T("CAMMANUF")) )
|
||
{
|
||
m_sEquipmentType = sValue;
|
||
}
|
||
|
||
else if ( -1 != sName.Find(_T("CAMMODEL")) )
|
||
{
|
||
m_sEquipmentModel = sValue;
|
||
}
|
||
|
||
else if ( -1 != sName.Find(_T("CAMNAME")) )
|
||
{
|
||
m_sTitle = sValue;
|
||
}
|
||
else if ( -1 != sName.Find(_T("CAMSERIAL")) )
|
||
{
|
||
m_sEquipmentModel += sValue;
|
||
}
|
||
else if ( -1 != sName.Find(_T("FIRMVERS")) )
|
||
{
|
||
m_sComment += _T("Firmware ") + sValue;
|
||
}
|
||
else if ( -1 != sName.Find(_T("TIME")) )
|
||
{
|
||
|
||
// время в формате UnixTime, т.е. количество
|
||
// секунд с полуночи 1/1/1970
|
||
|
||
_int64 nTime = _ttoi64( sValue.GetBuffer() );
|
||
long nMinutes = long(nTime / 60);
|
||
long nSeconds = long(nTime % 60);
|
||
long nHours = nMinutes / 60;
|
||
nMinutes = nMinutes % 60;
|
||
long nDays = nHours / 24;
|
||
nHours = nHours % 24;
|
||
|
||
|
||
int nYear = 1970;
|
||
|
||
while ( TRUE )
|
||
{
|
||
int nCurDays = 365;
|
||
|
||
if ( 0 == nYear % 4 )
|
||
{
|
||
if ( 0 == nYear % 100 && 0 != nYear % 400)
|
||
nCurDays = 365;
|
||
else
|
||
nCurDays = 366;
|
||
}
|
||
|
||
|
||
nDays -= nCurDays;
|
||
if ( nDays < 0 )
|
||
{
|
||
nDays += nCurDays;
|
||
break;
|
||
}
|
||
nYear++;
|
||
|
||
}
|
||
|
||
int arMonths[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||
if ( 0 == nYear % 4 )
|
||
{
|
||
if ( !(0 == nYear % 100 && 0 != nYear % 400) )
|
||
arMonths[1]++;
|
||
}
|
||
|
||
short nMonth = 1;
|
||
|
||
for ( int nMonthIndex = 0; nMonthIndex < 12; nMonthIndex++ )
|
||
{
|
||
if ( nDays < arMonths[nMonthIndex] )
|
||
break;
|
||
nDays -= arMonths[nMonthIndex];
|
||
nMonth++;
|
||
}
|
||
|
||
|
||
m_oDateTimeCreation.nYear = short( nYear );
|
||
m_oDateTimeCreation.nMonth = nMonth;
|
||
m_oDateTimeCreation.nDay = short( nDays + 1 );
|
||
m_oDateTimeCreation.nHour = short( nHours );
|
||
m_oDateTimeCreation.nMinute = short( nMinutes );
|
||
m_oDateTimeCreation.nSecond = short( nSeconds );
|
||
|
||
}
|
||
|
||
}
|
||
|
||
delete pData;
|
||
|
||
}
|
||
}
|
||
|
||
// Bit Depth всегда 24
|
||
m_nBitDepth = 24;
|
||
|
||
return TRUE;
|
||
}
|
||
BOOL LoadRawMetaData(CString sFilePath)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL LoadBitmapMetaData(const CStringW& strFilePath)
|
||
{
|
||
Bitmap* bitmap = 0; // Gdi+ Bitmap object
|
||
|
||
bitmap = new Bitmap(strFilePath);
|
||
|
||
// check for valid bitmap
|
||
if ( !bitmap || bitmap->GetLastStatus() != Ok )
|
||
{
|
||
if (bitmap) delete bitmap;
|
||
return FALSE;
|
||
}
|
||
try
|
||
{
|
||
// retrieve info properties
|
||
m_sTitle = GetPropertyStr(bitmap, PropertyTagImageTitle);
|
||
m_sAuthor = GetPropertyStr(bitmap, PropertyTagArtist);
|
||
m_sDescription = GetPropertyStr(bitmap, PropertyTagImageDescription);
|
||
|
||
CString sDateTime = GetPropertyStr(bitmap, PropertyTagDateTime);
|
||
|
||
if ( 19 <= sDateTime.GetLength() )
|
||
{
|
||
TCHAR *pDateTime = sDateTime.GetBuffer();
|
||
m_oDateTimeCreation.nYear = _ttoi( pDateTime );
|
||
m_oDateTimeCreation.nMonth = _ttoi( pDateTime + 5 );
|
||
m_oDateTimeCreation.nDay = _ttoi( pDateTime + 8 );
|
||
m_oDateTimeCreation.nHour = _ttoi( pDateTime + 11 );
|
||
m_oDateTimeCreation.nMinute = _ttoi( pDateTime + 14 );
|
||
m_oDateTimeCreation.nSecond = _ttoi( pDateTime + 17 );
|
||
|
||
}
|
||
else
|
||
m_oDateTimeCreation.sSummary = sDateTime;
|
||
|
||
m_sCopyright = GetPropertyStr(bitmap, PropertyTagCopyright);
|
||
m_sHostComputer = GetPropertyStr(bitmap, PropertyTagHostComputer);
|
||
m_sEquipmentType = GetPropertyStr(bitmap, PropertyTagEquipMake);
|
||
m_sEquipmentModel = GetPropertyStr(bitmap, PropertyTagEquipModel);
|
||
m_sSoftwareID = GetPropertyStr(bitmap, PropertyTagSoftwareUsed);
|
||
m_sDocumentName = GetPropertyStr(bitmap, PropertyTagDocumentName);
|
||
m_sPageName = GetPropertyStr(bitmap, PropertyTagPageName);
|
||
|
||
short nPages = GetPropertyInt(bitmap, PropertyTagPageNumber);
|
||
|
||
m_nPageNumber = (BYTE)nPages;
|
||
m_nPagesCount = (BYTE)nPages>> 8;
|
||
|
||
GetPropertyRationalU(bitmap, PropertyTagExifExposureTime, &m_oExposureTime);
|
||
GetPropertyRational (bitmap, PropertyTagExifExposureBias, &m_oExposureCompensation);
|
||
GetPropertyRational (bitmap, PropertyTagExifShutterSpeed, &m_oShutterSpeed);
|
||
GetPropertyRationalU(bitmap, PropertyTagExifAperture, &m_oLensAperture);
|
||
GetPropertyRationalU(bitmap, PropertyTagExifFocalLength, &m_oFocalLength);
|
||
GetPropertyRationalU(bitmap, PropertyTagExifFNumber, &m_oFNumber);
|
||
GetPropertyRational (bitmap, PropertyTagExifBrightness, &m_oBrightness);
|
||
GetPropertyRationalU (bitmap, PropertyTagExifMaxAperture, &m_oMaxApertureValue);
|
||
|
||
m_nExposureProgram = GetPropertyShort(bitmap, PropertyTagExifExposureProg);
|
||
m_nISOSpeed = GetPropertyShort(bitmap, PropertyTagExifISOSpeed);
|
||
m_nMeteringMode = GetPropertyShort(bitmap, PropertyTagExifMeteringMode);
|
||
m_nFlashMode = GetPropertyShort(bitmap, PropertyTagExifFlash);
|
||
m_nColorSpace = GetPropertyShort(bitmap, PropertyTagExifColorSpace);
|
||
m_nExposureMode =GetPropertyShort(bitmap,PropertyTagExifExposureMode);
|
||
m_nWhiteBalance =GetPropertyShort(bitmap,PropertyTagExifWhiteBalance);
|
||
m_nSensingMethod =GetPropertyShort(bitmap,PropertyTagExifSensingMethod);
|
||
m_nFocalLengthIn35mmFilm=GetPropertyShort(bitmap,PropertyTagExifFocalLengthIn35mmFilm);
|
||
m_nOrientation = GetPropertyShort(bitmap, PropertyTagOrientation);
|
||
|
||
if ( m_nBitDepth <= 1 )
|
||
m_nBitDepth = (short)GetPixelFormatSize( bitmap->GetPixelFormat() );
|
||
|
||
|
||
// Запрашиваем формат картинки
|
||
GUID guidFormat;
|
||
bitmap->GetRawFormat( &guidFormat );
|
||
|
||
// check for format type
|
||
if ( ImageFormatTIFF == guidFormat )
|
||
{
|
||
if( bitmap->GetFrameCount(&FrameDimensionPage) > 1 )
|
||
m_bMultiPageImage = TRUE;
|
||
}
|
||
else if ( ImageFormatGIF == guidFormat )
|
||
{
|
||
if( bitmap->GetFrameCount(&FrameDimensionTime) > 1 )
|
||
m_bMultiPageImage = TRUE;
|
||
}
|
||
|
||
}
|
||
catch(...)
|
||
{
|
||
}
|
||
|
||
if (bitmap) delete bitmap;
|
||
return TRUE;
|
||
}
|
||
BOOL LoadPSDMetaData(BYTE* pnFile, DWORD nFileSize)
|
||
{
|
||
if ( m_bBitmap )
|
||
return FALSE;
|
||
|
||
DWORD nHeaderSize = sizeof(TPSDFileHeader);
|
||
|
||
if( nHeaderSize > nFileSize )
|
||
return FALSE;
|
||
|
||
const TPSDFileHeader& oHeader = *(TPSDFileHeader*)pnFile;
|
||
|
||
// Проверяем сигнатуру
|
||
if( 0x38425053 /* 8BPS */ != IntFromBytes4( oHeader.nSignature, 0 ) )
|
||
return FALSE;
|
||
|
||
if( 1 != IntFromBytes2( oHeader.nVersion, 0 ) )
|
||
return FALSE;
|
||
|
||
int nWidth = IntFromBytes4( oHeader.nColumns, 0 );
|
||
int nHeight = IntFromBytes4( oHeader.nRows, 0 );
|
||
|
||
int nChannels = IntFromBytes2( oHeader.nChannels, 0 );
|
||
int nPlaneDepth = IntFromBytes2( oHeader.nDepth, 0 );
|
||
|
||
m_nBitDepth = nChannels * nPlaneDepth;
|
||
|
||
return TRUE;
|
||
}
|
||
BOOL LoadPCXMetaData(BYTE* pnFile, DWORD nFileSize)
|
||
{
|
||
if ( m_bBitmap )
|
||
return FALSE;
|
||
|
||
DWORD nHeaderSize = sizeof(TPCXFileHeader);
|
||
|
||
if( nHeaderSize > nFileSize )
|
||
return FALSE;
|
||
|
||
const TPCXFileHeader& oHeader = *(TPCXFileHeader*)pnFile;
|
||
|
||
// Проверяем формат
|
||
if( 10 != oHeader.nManufacturer )
|
||
return FALSE;
|
||
|
||
switch( oHeader.nVersion )
|
||
{
|
||
case 0: break;
|
||
case 2: break;
|
||
case 3: break;
|
||
case 4: break;
|
||
case 5: break;
|
||
default: return FALSE;
|
||
}
|
||
|
||
switch( oHeader.bEncoding )
|
||
{
|
||
case 0: break;
|
||
case 1: break;
|
||
default: return FALSE;
|
||
}
|
||
|
||
switch( oHeader.nBitsPerPixelPerPlane )
|
||
{
|
||
case 1: break;
|
||
case 4: break;
|
||
case 8: break;
|
||
case 16: break;
|
||
case 24: break;
|
||
case 32: break;
|
||
default: return FALSE;
|
||
}
|
||
|
||
|
||
int nWidth = oHeader.nMaxX - oHeader.nMinX + 1;
|
||
int nHeight = oHeader.nMaxY - oHeader.nMinY + 1;
|
||
BOOL bGreyScale = (2 == oHeader.bGrayscalePalette) ? TRUE : FALSE;
|
||
int nPlanes = oHeader.nPlanes;
|
||
int nDepth = oHeader.nBitsPerPixelPerPlane;
|
||
int nBytesPerLinePerPlane = oHeader.nBytesPerLinePerPlane;
|
||
|
||
m_nBitDepth = nPlanes * nDepth;
|
||
|
||
return TRUE;
|
||
}
|
||
BOOL LoadRasMetaData(BYTE* pnFile, DWORD nFileSize)
|
||
{
|
||
if ( m_bBitmap )
|
||
return FALSE;
|
||
|
||
DWORD nHeaderSize = sizeof(TRasFileHeader);
|
||
|
||
if( nHeaderSize > nFileSize )
|
||
return FALSE;
|
||
|
||
const TRasFileHeader& oHeader = *(TRasFileHeader*)pnFile;
|
||
|
||
// Проверяем сигнатуру
|
||
if( 0x59a66a95 != ReverseDword( oHeader.nMagicNumber ) )
|
||
return FALSE;
|
||
|
||
int nWidth = ReverseDword( oHeader.nWidth );
|
||
int nHeight = ReverseDword( oHeader.nHeight );
|
||
|
||
if ( 0 == nWidth || 0 == nHeight )
|
||
return FALSE;
|
||
|
||
int nDepth = ReverseDword( oHeader.nDepth );
|
||
switch( nDepth )
|
||
{
|
||
case 1: break;
|
||
case 8: break;
|
||
case 24: break;
|
||
case 32: break;
|
||
default: return FALSE;
|
||
}
|
||
|
||
|
||
int nBytesPerLine = ReverseDword(oHeader.nSize) / nHeight;
|
||
if( nBytesPerLine < 2 )
|
||
return FALSE;
|
||
|
||
BOOL bPalette;
|
||
switch( ReverseDword(oHeader.nPaletteType) )
|
||
{
|
||
case 0: bPalette = FALSE; break;
|
||
case 1: bPalette = TRUE; break;
|
||
default: return FALSE;
|
||
}
|
||
|
||
BOOL bCompressed = FALSE;
|
||
switch( ReverseDword(oHeader.nType) )
|
||
{
|
||
case 0: break; // old format
|
||
case 1: break; // standart format
|
||
case 2: bCompressed = TRUE; break;
|
||
case 3: break; // RGB format
|
||
case 4: break; // convert from TIFF format
|
||
case 5: break; // convert from IFF format
|
||
default: return FALSE;
|
||
}
|
||
|
||
m_nBitDepth = nDepth;
|
||
|
||
return TRUE;
|
||
}
|
||
BOOL LoadJ2kMetaData(BYTE* pnFile, DWORD nFileSize)
|
||
{
|
||
if ( m_bBitmap )
|
||
return FALSE;
|
||
|
||
return ReadJpxHeader( pnFile, nFileSize );
|
||
}
|
||
// Save MetaDatafunctions
|
||
BOOL SaveAsTGA(ATL::CAtlFile& oResultFile)
|
||
{
|
||
//сохранение метадынных (ExtensionArea)
|
||
|
||
TExtensionArea oExtArea;
|
||
|
||
ZeroMemory( &oExtArea, sizeof(TExtensionArea) );
|
||
|
||
oExtArea.nExtensionSize = 495;
|
||
BytesFromString(m_sAuthor, oExtArea.sAuthorName, 41);
|
||
BytesFromString(m_sComment, oExtArea.sComments, 324);
|
||
oExtArea.nDateTime[0] = m_oDateTimeCreation.nMonth;
|
||
oExtArea.nDateTime[1] = m_oDateTimeCreation.nDay;
|
||
oExtArea.nDateTime[2] = m_oDateTimeCreation.nYear;
|
||
oExtArea.nDateTime[3] = m_oDateTimeCreation.nHour;
|
||
oExtArea.nDateTime[4] = m_oDateTimeCreation.nMinute;
|
||
oExtArea.nDateTime[5] = m_oDateTimeCreation.nSecond;
|
||
BytesFromString(m_sJobName, oExtArea.sJobName, 41);
|
||
oExtArea.nJobTime[0] = m_oJobTime.nHour;
|
||
oExtArea.nJobTime[1] = m_oJobTime.nMinute;
|
||
oExtArea.nJobTime[2] = m_oJobTime.nSecond;
|
||
BytesFromString(m_sSoftwareID, oExtArea.sSoftwareID, 41);
|
||
BytesFromString(m_sVersionLetter, &oExtArea.nSoftwareVersionLetter, 1);
|
||
oExtArea.nSoftwareVersionNumber = m_nVersionNumber;
|
||
oExtArea.nKeyColor = 0;
|
||
oExtArea.nPixelAspectRatio[0] = 0;
|
||
oExtArea.nPixelAspectRatio[1] = 0;
|
||
oExtArea.nGammaValue[0] = 0;
|
||
oExtArea.nGammaValue[1] = 0;
|
||
oExtArea.nColorCorrectionOffset = 0;
|
||
oExtArea.nPostageStampOffset = 0;
|
||
oExtArea.nScanLineOffset = 0;
|
||
oExtArea.nAttributesType = 0;
|
||
|
||
DWORD nBytesWritten = 0;
|
||
if( S_OK != oResultFile.Write( &oExtArea, sizeof(TExtensionArea), &nBytesWritten))
|
||
return FALSE;
|
||
|
||
ULONGLONG nLen;
|
||
oResultFile.GetSize((ULONGLONG&)nLen);
|
||
|
||
//сохранение FileFooter
|
||
|
||
TFileFooter oFileFooter;
|
||
|
||
ZeroMemory( &oFileFooter, sizeof(TFileFooter) );
|
||
|
||
//посчитать размер файла и вычесть 495
|
||
oFileFooter.nExtensionAreaOffset = long(nLen) - 495;
|
||
oFileFooter.nDeveloperAreaOffset = 0;
|
||
BYTE sSignature[18] = {'T', 'R', 'U', 'E', 'V', 'I', 'S', 'I', 'O', 'N', '-', 'X', 'F', 'I', 'L', 'E', '.', 0x00};
|
||
for (int nIndex = 0; nIndex < 18; nIndex++ )
|
||
oFileFooter.arrSignature[nIndex] = sSignature[nIndex];
|
||
|
||
if( S_OK != oResultFile.Write( &oFileFooter, 26, &nBytesWritten))
|
||
return FALSE;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL SaveAsPNG(ATL::CAtlFile& oResultFile)
|
||
{
|
||
if ( 0 < m_sTitle.GetLength() )
|
||
SaveChunk(oResultFile, _T("Title"), m_sTitle);
|
||
if ( 0 < m_sAuthor.GetLength() )
|
||
SaveChunk(oResultFile, _T("Author"), m_sAuthor);
|
||
if ( 0 < m_sDescription.GetLength() )
|
||
SaveChunk(oResultFile, _T("Description"), m_sDescription);
|
||
if ( 0 < m_sCopyright.GetLength() )
|
||
SaveChunk(oResultFile, _T("Copyright"), m_sCopyright);
|
||
if ( 0 < m_oDateTimeCreation.sSummary.GetLength() )
|
||
SaveChunk(oResultFile, _T("Creation Time"), m_oDateTimeCreation.sSummary);
|
||
if ( 0 < m_sSoftwareID.GetLength() )
|
||
SaveChunk(oResultFile, _T("Software"), m_sSoftwareID);
|
||
if ( 0 < m_sDisclaimer.GetLength() )
|
||
SaveChunk(oResultFile, _T("Disclaimer"), m_sDisclaimer);
|
||
if ( 0 < m_sWarning.GetLength() )
|
||
SaveChunk(oResultFile, _T("Warning"), m_sWarning);
|
||
//CString sSource = m_sEquipmentType + " " + m_sEquipmentModel;
|
||
//if ( 1 < sSource.GetLength() )
|
||
// SaveChunk(oResultFile, "Source", sSource, 0);
|
||
if ( 0 < m_sEquipmentType.GetLength() )
|
||
SaveChunk(oResultFile, _T("Source"), m_sEquipmentType);
|
||
if ( 0 < m_sComment.GetLength() )
|
||
SaveChunk(oResultFile, _T("Comment"), m_sComment);
|
||
|
||
TChunk oLastChunk;
|
||
IntToBytes4(0, oLastChunk.nLenght);
|
||
oLastChunk.nType[0] = 'I';
|
||
oLastChunk.nType[1] = 'E';
|
||
oLastChunk.nType[2] = 'N';
|
||
oLastChunk.nType[3] = 'D';
|
||
|
||
crc32 oCRC;
|
||
oCRC.ProcessCRC(oLastChunk.nType, 4);
|
||
|
||
|
||
|
||
BYTE CRC[4] = {0, 0, 0, 0};
|
||
IntToBytes4(oCRC.m_crc32, CRC);
|
||
if( S_OK != oResultFile.Write( &oLastChunk, 8))
|
||
return FALSE;
|
||
if( S_OK != oResultFile.Write( CRC, 4))
|
||
return FALSE;
|
||
|
||
|
||
// С записью DATE/TIME что-то не так
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
void WriteNode(XmlUtils::CXmlWriter &oXmlWriter, const CString &m_sName, const CString &m_sValue)
|
||
{
|
||
CString sValue = m_sValue;
|
||
sValue.Replace(_T("&"), _T("&"));
|
||
sValue.Replace(_T("<"), _T("<"));
|
||
sValue.Replace(_T(">"), _T(">"));
|
||
sValue.Replace(_T("'"), _T("'"));
|
||
sValue.Replace(_T("\""), _T("""));
|
||
oXmlWriter.WriteNode(m_sName, sValue.GetBuffer());
|
||
}
|
||
|
||
BOOL GetValueOfAttribute(CString sAttribute, CString *sValue)
|
||
{
|
||
int nPosition = m_sMetaDataXML.Find(sAttribute);
|
||
|
||
if ( -1 == nPosition )
|
||
return FALSE;
|
||
|
||
nPosition += int(m_sMetaDataXML.GetLength());
|
||
while ( ' ' != m_sMetaDataXML[nPosition] && '\\' != m_sMetaDataXML[nPosition] )
|
||
{
|
||
*sValue += m_sMetaDataXML[nPosition];
|
||
nPosition++;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
void ReadNodeText(XmlUtils::CXmlReader &oReader, const CString &sName, CString *sValue)
|
||
{
|
||
oReader.ReadRootNode();
|
||
oReader.ReadNode(sName);
|
||
*sValue = oReader.ReadNodeText();
|
||
}
|
||
void ReadNodeText(XmlUtils::CXmlReader &oReader, const CString &sName, TRational *oValue)
|
||
{
|
||
CString sValue = _T("");
|
||
oReader.ReadRootNode();
|
||
oReader.ReadNode(sName);
|
||
sValue = oReader.ReadNodeText();
|
||
int pos_flash = sValue.Find(_T("/"));
|
||
int pos_point = sValue.Find(_T("."));
|
||
|
||
if (pos_flash >=0)
|
||
{
|
||
oValue->Fraction = _ttoi(sValue.Left(pos_flash));
|
||
oValue->Denominator = _ttoi(sValue.Mid(pos_flash+1));
|
||
}
|
||
else
|
||
{
|
||
if (pos_point>=0)
|
||
{
|
||
float fValue = _tstof(sValue);
|
||
oValue->Denominator = 100;
|
||
oValue->Fraction = int(fValue*100);
|
||
}
|
||
else
|
||
{
|
||
oValue->Fraction = _ttoi(sValue);
|
||
oValue->Denominator = 0;
|
||
}
|
||
}
|
||
}
|
||
void ReadNodeText(XmlUtils::CXmlReader &oReader, const CString &sName, TRationalU *oValue)
|
||
{
|
||
CString sValue = _T("");
|
||
oReader.ReadRootNode();
|
||
oReader.ReadNode(sName);
|
||
sValue = oReader.ReadNodeText();
|
||
int pos_flash = sValue.Find(_T("/"));
|
||
int pos_point = sValue.Find(_T("."));
|
||
|
||
if (pos_flash >=0)
|
||
{
|
||
oValue->Fraction = _ttoi(sValue.Left(pos_flash));
|
||
oValue->Denominator = _ttoi(sValue.Mid(pos_flash+1));
|
||
}
|
||
else
|
||
{
|
||
if (pos_point>=0)
|
||
{
|
||
float fValue = _tstof(sValue);
|
||
oValue->Denominator = 100;
|
||
oValue->Fraction = int(fValue*100);
|
||
}
|
||
else
|
||
{
|
||
oValue->Fraction = _ttoi(sValue);
|
||
oValue->Denominator = 0;
|
||
}
|
||
}
|
||
}
|
||
void ReadNodeText(XmlUtils::CXmlReader &oReader, const CString &sName, short *nValue)
|
||
{
|
||
CString sValue = _T("");
|
||
oReader.ReadRootNode();
|
||
oReader.ReadNode(sName);
|
||
sValue = oReader.ReadNodeText();
|
||
*nValue = _ttoi(sValue);
|
||
}
|
||
void ReadNodeText(XmlUtils::CXmlReader &oReader, const CString &sName, BOOL *nValue)
|
||
{
|
||
CString sValue = _T("");
|
||
oReader.ReadRootNode();
|
||
oReader.ReadNode(sName);
|
||
sValue = oReader.ReadNodeText();
|
||
*nValue = _ttoi(sValue);
|
||
}
|
||
void ReadSubNodeText(XmlUtils::CXmlReader &oReader, const CString &sNodeName, const CString &sSubNodeName, CString *sValue)
|
||
{
|
||
oReader.ReadRootNode();
|
||
oReader.ReadNode(sNodeName);
|
||
oReader.ReadNode(sSubNodeName);
|
||
*sValue = oReader.ReadNodeText();
|
||
}
|
||
|
||
void ReadSubNodeText(XmlUtils::CXmlReader &oReader, const CString &sNodeName, const CString &sSubNodeName, short *nValue)
|
||
{
|
||
CString sValue = _T("");
|
||
oReader.ReadRootNode();
|
||
oReader.ReadNode(sNodeName);
|
||
oReader.ReadNode(sSubNodeName);
|
||
sValue = oReader.ReadNodeText();
|
||
*nValue = _ttoi(sValue);
|
||
}
|
||
|
||
BOOL MakeXML()
|
||
{
|
||
XmlUtils::CXmlWriter oXmlWriter;
|
||
|
||
oXmlWriter.WriteNodeBegin(_T("MetaData"));
|
||
|
||
WriteNode(oXmlWriter, _T("Title"), m_sTitle);
|
||
WriteNode(oXmlWriter, _T("Author"), m_sAuthor);
|
||
WriteNode(oXmlWriter, _T("Description"), m_sDescription);
|
||
|
||
oXmlWriter.WriteNodeBegin(_T("DateTime"));
|
||
|
||
oXmlWriter.WriteNode(_T("Year"), m_oDateTimeCreation.nYear);
|
||
oXmlWriter.WriteNode(_T("Month"), m_oDateTimeCreation.nMonth);
|
||
oXmlWriter.WriteNode(_T("Day"), m_oDateTimeCreation.nDay);
|
||
oXmlWriter.WriteNode(_T("Hour"), m_oDateTimeCreation.nHour);
|
||
oXmlWriter.WriteNode(_T("Minute"), m_oDateTimeCreation.nMinute);
|
||
oXmlWriter.WriteNode(_T("Second"), m_oDateTimeCreation.nSecond);
|
||
WriteNode(oXmlWriter, _T("Summary"), m_oDateTimeCreation.sSummary);
|
||
|
||
oXmlWriter.WriteNodeEnd(_T("DateTime"));
|
||
|
||
WriteNode(oXmlWriter, _T("Copyright"), m_sCopyright);
|
||
WriteNode(oXmlWriter, _T("Disclaimer"), m_sDisclaimer);
|
||
WriteNode(oXmlWriter, _T("Comment"), m_sComment);
|
||
WriteNode(oXmlWriter,_T("EquipmentType"), m_sEquipmentType);
|
||
WriteNode(oXmlWriter, _T("EquipmentModel"), m_sEquipmentModel);
|
||
|
||
oXmlWriter.WriteNodeBegin(_T("JobTime"));
|
||
|
||
oXmlWriter.WriteNode(_T("Hour"), m_oJobTime.nHour);
|
||
oXmlWriter.WriteNode(_T("Minute"), m_oJobTime.nMinute);
|
||
oXmlWriter.WriteNode(_T("Second"), m_oJobTime.nSecond);
|
||
|
||
oXmlWriter.WriteNodeEnd(_T("JobTime"));
|
||
|
||
WriteNode(oXmlWriter, _T("JobName"), m_sJobName);
|
||
WriteNode(oXmlWriter, _T("SoftwareID"), m_sSoftwareID);
|
||
oXmlWriter.WriteNode(_T("VersionNumber"), m_nVersionNumber);
|
||
WriteNode(oXmlWriter, _T("VersionLetter"), m_sVersionLetter);
|
||
WriteNode(oXmlWriter, _T("HostComputer"), m_sHostComputer);
|
||
WriteNode(oXmlWriter, _T("Warning"), m_sWarning);
|
||
WriteNode(oXmlWriter, _T("DocumentName"), m_sDocumentName);
|
||
WriteNode(oXmlWriter, _T("PageName"), m_sPageName);
|
||
oXmlWriter.WriteNode(_T("PageNumber"), m_nPageNumber);
|
||
oXmlWriter.WriteNode(_T("PagesCount"), m_nPagesCount);
|
||
|
||
if ( 1 == m_oExposureTime.Fraction || ( 0 != m_oExposureTime.Fraction && 0 == fmod( (float)m_oExposureTime.Denominator, (float)m_oExposureTime.Fraction ) ) )
|
||
{
|
||
WriteNode(oXmlWriter, _T("ExposureTime"), RationalUToString(m_oExposureTime) );
|
||
}
|
||
else if ( 0 != m_oExposureTime.Denominator )
|
||
{
|
||
float fExposureTime = (float)m_oExposureTime.Fraction / (float)m_oExposureTime.Denominator;
|
||
CString sExposureTime;
|
||
sExposureTime.Format(_T("%.1f"), fExposureTime);
|
||
WriteNode(oXmlWriter, _T("ExposureTime"), sExposureTime );
|
||
}
|
||
else WriteNode(oXmlWriter, _T("ExposureTime"), _T("0") );
|
||
|
||
CString sExposureProgram = _T("");
|
||
switch(m_nExposureProgram)
|
||
{
|
||
case 0: sExposureProgram = _T("Not Defined"); break;
|
||
case 1: sExposureProgram = _T("Manual"); break;
|
||
case 2: sExposureProgram = _T("Normal program"); break;
|
||
case 3: sExposureProgram = _T("Aperture priority"); break;
|
||
case 4: sExposureProgram = _T("Shutter priority"); break;
|
||
case 5: sExposureProgram = _T("Creative program (Slow speed)"); break;
|
||
case 6: sExposureProgram = _T("Action program (High speed)"); break;
|
||
case 7: sExposureProgram = _T("Portrait mode"); break;
|
||
case 8: sExposureProgram = _T("Landscape mode"); break;
|
||
}
|
||
WriteNode(oXmlWriter, _T("ExposureProgram"), sExposureProgram);
|
||
|
||
if ( 1 == m_oShutterSpeed.Fraction || ( 0 != m_oShutterSpeed.Fraction && 0 == fmod( (float)m_oShutterSpeed.Denominator, (float)m_oShutterSpeed.Fraction ) ) )
|
||
{
|
||
WriteNode(oXmlWriter, _T("ShutterSpeed"), RationalToString(m_oShutterSpeed) );
|
||
}
|
||
else if ( 0 != m_oShutterSpeed.Denominator )
|
||
{
|
||
float fShutterSpeed = (float)m_oShutterSpeed.Fraction / (float)m_oShutterSpeed.Denominator;
|
||
CString sShutterSpeed;
|
||
sShutterSpeed.Format(_T("%.2f"), fShutterSpeed);
|
||
WriteNode(oXmlWriter, _T("ShutterSpeed"), sShutterSpeed );
|
||
}
|
||
else
|
||
{
|
||
oXmlWriter.WriteNode( _T("ShutterSpeed"), m_oShutterSpeed.Fraction );
|
||
}
|
||
|
||
WriteNode(oXmlWriter, _T("LensAperture"), RationalUToString(m_oLensAperture) );
|
||
WriteNode(oXmlWriter, _T("MaxApertureValue"), RationalUToString(m_oMaxApertureValue) );
|
||
WriteNode(oXmlWriter, _T("FocalLength"), RationalUToString(m_oFocalLength) );
|
||
|
||
if ( 0 != m_oFNumber.Denominator )
|
||
{
|
||
float fFNumber = (float)m_oFNumber.Fraction / (float)m_oFNumber.Denominator;
|
||
CString sFNumber;
|
||
sFNumber.Format(_T("%.2f"), fFNumber);
|
||
WriteNode(oXmlWriter, _T("FNumber"), sFNumber );
|
||
}
|
||
else oXmlWriter.WriteNode( _T("FNumber"), (int)m_oFNumber.Fraction);
|
||
|
||
if ( 0 != m_oBrightness.Denominator )
|
||
{
|
||
float fFNumber = (float)m_oBrightness.Fraction / (float)m_oBrightness.Denominator;
|
||
CString sFNumber;
|
||
sFNumber.Format(_T("%.2f"), fFNumber);
|
||
WriteNode(oXmlWriter, _T("Brightness"), sFNumber );
|
||
}
|
||
else oXmlWriter.WriteNode( _T("Brightness"), (int)m_oBrightness.Fraction);
|
||
|
||
if ( 0 != m_oExposureCompensation.Denominator )
|
||
{
|
||
float fFNumber = (float)m_oExposureCompensation.Fraction / (float)m_oExposureCompensation.Denominator;
|
||
CString sFNumber;
|
||
sFNumber.Format(_T("%.2f"), fFNumber);
|
||
WriteNode(oXmlWriter, _T("ExposureCompensation"), sFNumber );
|
||
}
|
||
else oXmlWriter.WriteNode( _T("ExposureCompensation"), (int)m_oExposureCompensation.Fraction);
|
||
|
||
oXmlWriter.WriteNode(_T("ISOSpeed"), m_nISOSpeed);
|
||
oXmlWriter.WriteNode(_T("SensingMethod"), m_nSensingMethod);
|
||
oXmlWriter.WriteNode(_T("WhiteBalance"), m_nWhiteBalance);
|
||
oXmlWriter.WriteNode(_T("ExposureMode"), m_nExposureMode);
|
||
oXmlWriter.WriteNode(_T("FocalLengthIn35mmFilm"), m_nFocalLengthIn35mmFilm);
|
||
|
||
CString sMeteringMode = _T("");
|
||
switch(m_nMeteringMode)
|
||
{
|
||
case 0: sMeteringMode = _T("Unknown"); break;
|
||
case 1: sMeteringMode = _T("Average"); break;
|
||
case 2: sMeteringMode = _T("Center-weighted average"); break;
|
||
case 3: sMeteringMode = _T("Spot"); break;
|
||
case 4: sMeteringMode = _T("Multi-spot"); break;
|
||
case 5: sMeteringMode = _T("Pattern"); break;
|
||
case 6: sMeteringMode = _T("Partial"); break;
|
||
case 255: sMeteringMode = _T(""); break;
|
||
}
|
||
WriteNode(oXmlWriter, _T("MeteringMode"), sMeteringMode);
|
||
|
||
CString sFlashMode = _T("");
|
||
switch(m_nFlashMode)
|
||
{
|
||
case 0x0: sFlashMode = _T("No Flash"); break;
|
||
case 0x1: sFlashMode = _T("Fired"); break;
|
||
case 0x5: sFlashMode = _T("Fired, Return not detected"); break;
|
||
case 0x7: sFlashMode = _T("Fired, Return detected"); break;
|
||
case 0x8: sFlashMode = _T("On, Did not fire"); break;
|
||
case 0x9: sFlashMode = _T("On, Fired"); break;
|
||
case 0xd: sFlashMode = _T("On, Return not detected"); break;
|
||
case 0xf: sFlashMode = _T("On, Return detected"); break;
|
||
case 0x10: sFlashMode = _T("Off, Did not fire"); break;
|
||
case 0x14: sFlashMode = _T("Off, Did not fire, Return not detected"); break;
|
||
case 0x18: sFlashMode = _T("Auto, Did not fire"); break;
|
||
case 0x19: sFlashMode = _T("Auto, Fired"); break;
|
||
case 0x1d: sFlashMode = _T("Auto, Fired, Return not detected"); break;
|
||
case 0x1f: sFlashMode = _T("Auto, Fired, Return detected"); break;
|
||
case 0x20: sFlashMode = _T("No flash function"); break;
|
||
case 0x30: sFlashMode = _T("Off, No flash function"); break;
|
||
case 0x41: sFlashMode = _T("Fired, Red-eye reduction"); break;
|
||
case 0x45: sFlashMode = _T("Fired, Red-eye reduction, Return not detected"); break;
|
||
case 0x47: sFlashMode = _T("Fired, Red-eye reduction, Return detected"); break;
|
||
case 0x49: sFlashMode = _T("On, Red-eye reduction"); break;
|
||
case 0x4d: sFlashMode = _T("On, Red-eye reduction, Return not detected"); break;
|
||
case 0x4f: sFlashMode = _T("On, Red-eye reduction, Return detected"); break;
|
||
case 0x50: sFlashMode = _T("Off, Red-eye reduction"); break;
|
||
case 0x58: sFlashMode = _T("Auto, Did not fire, Red-eye reduction"); break;
|
||
case 0x59: sFlashMode = _T("Auto, Fired, Red-eye reduction"); break;
|
||
case 0x5d: sFlashMode = _T("Auto, Fired, Red-eye reduction, Return not detected"); break;
|
||
case 0x5f: sFlashMode = _T("Auto, Fired, Red-eye reduction, Return detected"); break;
|
||
}
|
||
WriteNode(oXmlWriter, _T("FlashMode"), sFlashMode);
|
||
|
||
CString sColorSpace = _T("");
|
||
switch(m_nColorSpace)
|
||
{
|
||
case 1: sColorSpace = _T("sRGB"); break;
|
||
case 65535: sColorSpace = _T("Uncalibrated"); break;
|
||
}
|
||
WriteNode(oXmlWriter, _T("ColorSpace"), sColorSpace);
|
||
|
||
|
||
// Дополнительный параметр
|
||
oXmlWriter.WriteNode(_T("BitDepth"), m_nBitDepth);
|
||
oXmlWriter.WriteNode(_T("MultiPageImage"), (int)m_bMultiPageImage );
|
||
|
||
oXmlWriter.WriteNodeEnd(_T("MetaData"));
|
||
#ifdef _UNICODE
|
||
oXmlWriter.EncodingUnicodeToUTF8();
|
||
#else
|
||
oXmlWriter.EncodingASCIIToUTF8();
|
||
#endif
|
||
|
||
m_sMetaDataXML = oXmlWriter.GetXmlString();
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL ParseXML(CString sXML)
|
||
{
|
||
XmlUtils::CXmlReader oReader;
|
||
|
||
oReader.SetXmlString(sXML);
|
||
|
||
ReadNodeText(oReader, _T("Title"), &m_sTitle);
|
||
ReadNodeText(oReader, _T("Author"), &m_sAuthor);
|
||
ReadNodeText(oReader, _T("Description"), &m_sDescription);
|
||
|
||
ReadSubNodeText(oReader, _T("DateTime"), _T("Year"), &m_oDateTimeCreation.nYear);
|
||
ReadSubNodeText(oReader, _T("DateTime"), _T("Month"), &m_oDateTimeCreation.nMonth);
|
||
ReadSubNodeText(oReader, _T("DateTime"), _T("Day"), &m_oDateTimeCreation.nDay);
|
||
ReadSubNodeText(oReader, _T("DateTime"), _T("Hour"), &m_oDateTimeCreation.nHour);
|
||
ReadSubNodeText(oReader, _T("DateTime"), _T("Minute"), &m_oDateTimeCreation.nMinute);
|
||
ReadSubNodeText(oReader, _T("DateTime"), _T("Second"), &m_oDateTimeCreation.nSecond);
|
||
ReadSubNodeText(oReader, _T("DateTime"), _T("Summary"), &m_oDateTimeCreation.sSummary);
|
||
|
||
ReadNodeText(oReader, _T("Copyright"), &m_sCopyright);
|
||
ReadNodeText(oReader, _T("Disclaimer"), &m_sDisclaimer);
|
||
ReadNodeText(oReader, _T("Comment"), &m_sComment);
|
||
ReadNodeText(oReader, _T("EquipmentType"), &m_sEquipmentType);
|
||
ReadNodeText(oReader, _T("EquipmentModel"), &m_sEquipmentModel);
|
||
|
||
ReadSubNodeText(oReader, _T("JobTime"), _T("Hour"), &m_oJobTime.nHour);
|
||
ReadSubNodeText(oReader, _T("JobTime"), _T("Minute"), &m_oJobTime.nMinute);
|
||
ReadSubNodeText(oReader, _T("JobTime"), _T("Second"), &m_oJobTime.nSecond);
|
||
|
||
ReadNodeText(oReader, _T("JobName"), &m_sJobName);
|
||
ReadNodeText(oReader, _T("SoftwareID"), &m_sSoftwareID);
|
||
ReadNodeText(oReader, _T("VersionNumber"), &m_nVersionNumber);
|
||
ReadNodeText(oReader, _T("VersionLetter"), &m_sVersionLetter);
|
||
ReadNodeText(oReader, _T("HostComputer"), &m_sHostComputer);
|
||
ReadNodeText(oReader, _T("Warning"), &m_sWarning);
|
||
ReadNodeText(oReader, _T("DocumentName"), &m_sDocumentName);
|
||
ReadNodeText(oReader, _T("PageName"), &m_sPageName);
|
||
ReadNodeText(oReader, _T("PageNumber"), &m_nPageNumber);
|
||
ReadNodeText(oReader, _T("PagesCount"), &m_nPagesCount);
|
||
|
||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
ReadNodeText(oReader, _T("ExposureTime"),&m_oExposureTime);
|
||
ReadNodeText(oReader, _T("ExposureCompensation"),&m_oExposureCompensation);
|
||
ReadNodeText(oReader, _T("ExposureCompensation"),&m_oBrightness);
|
||
|
||
CString strExposureProgram;
|
||
ReadNodeText(oReader, _T("ExposureProgram"),&strExposureProgram);
|
||
if(strExposureProgram == _T("Not Defined"))m_nExposureProgram =0;
|
||
if(strExposureProgram == _T("Manual"))m_nExposureProgram =1;
|
||
if(strExposureProgram == _T("Normal program"))m_nExposureProgram =2;
|
||
if(strExposureProgram == _T("Aperture priority"))m_nExposureProgram =3;
|
||
if(strExposureProgram == _T("Shutter priority"))m_nExposureProgram =4;
|
||
if(strExposureProgram == _T("Creative program (Slow speed)"))m_nExposureProgram =5;
|
||
if(strExposureProgram == _T("Action program (High speed)"))m_nExposureProgram =6;
|
||
if(strExposureProgram == _T("Portrait mode"))m_nExposureProgram =7;
|
||
if(strExposureProgram == _T("Landscape mode"))m_nExposureProgram =8;
|
||
|
||
ReadNodeText(oReader, _T("LensAperture"),&m_oLensAperture);
|
||
ReadNodeText(oReader, _T("MaxApertureValue"),&m_oMaxApertureValue);
|
||
ReadNodeText(oReader, _T("FocalLength"),&m_oFocalLength);
|
||
ReadNodeText(oReader, _T("FNumber"),&m_oFNumber);
|
||
|
||
ReadNodeText(oReader, _T("ISOSpeed"), &m_nISOSpeed);
|
||
ReadNodeText(oReader, _T("SensingMethod"), &m_nSensingMethod);
|
||
ReadNodeText(oReader, _T("WhiteBalance"), &m_nWhiteBalance);
|
||
ReadNodeText(oReader, _T("ExposureMode"), &m_nExposureMode);
|
||
ReadNodeText(oReader, _T("FocalLengthIn35mmFilm"), &m_nFocalLengthIn35mmFilm);
|
||
|
||
CString strMeteringMode ;
|
||
ReadNodeText(oReader, _T("MeteringMode"), &strMeteringMode);
|
||
if(strMeteringMode == _T("Unknown"))m_nMeteringMode =0;
|
||
if(strMeteringMode == _T("Average"))m_nMeteringMode =1;
|
||
if(strMeteringMode == _T("Center-weighted average"))m_nMeteringMode =2;
|
||
if(strMeteringMode == _T("Spot"))m_nMeteringMode =3;
|
||
if(strMeteringMode == _T("Multi-spot"))m_nMeteringMode =4;
|
||
if(strMeteringMode == _T("Pattern"))m_nMeteringMode =5;
|
||
if(strMeteringMode == _T("Partial"))m_nMeteringMode =6;
|
||
if(strMeteringMode == _T(""))m_nMeteringMode =255;
|
||
|
||
CString strFlashMode;
|
||
ReadNodeText(oReader, _T("FlashMode"), &strFlashMode);
|
||
if (strFlashMode == _T("No Flash")) m_nFlashMode =0x0;
|
||
if (strFlashMode == _T("Fired")) m_nFlashMode = 0x1;
|
||
if (strFlashMode == _T("Fired, Return not detected")) m_nFlashMode = 0x5;
|
||
if (strFlashMode == _T("Fired, Return detected")) m_nFlashMode = 0x7;
|
||
if (strFlashMode == _T("On, Did not fire")) m_nFlashMode = 0x8;
|
||
if (strFlashMode == _T("On, Fired")) m_nFlashMode = 0x9;
|
||
if (strFlashMode == _T("On, Return not detected")) m_nFlashMode = 0xd;
|
||
if (strFlashMode == _T("On, Return detected")) m_nFlashMode = 0xf;
|
||
if (strFlashMode == _T("Off, Did not fire")) m_nFlashMode = 0x10;
|
||
if (strFlashMode == _T("Off, Did not fire, Return not detected")) m_nFlashMode = 0x14;
|
||
if (strFlashMode == _T("Auto, Did not fire")) m_nFlashMode = 0x18;
|
||
if (strFlashMode == _T("Auto, Fired")) m_nFlashMode = 0x19;
|
||
if (strFlashMode == _T("Auto, Fired, Return not detected")) m_nFlashMode = 0x1d;
|
||
if (strFlashMode == _T("Auto, Fired, Return detected")) m_nFlashMode = 0x1f;
|
||
if (strFlashMode == _T("No flash function")) m_nFlashMode = 0x20;
|
||
if (strFlashMode == _T("Off, No flash function")) m_nFlashMode = 0x30;
|
||
if (strFlashMode == _T("Fired, Red-eye reduction")) m_nFlashMode = 0x41;
|
||
if (strFlashMode == _T("Fired, Red-eye reduction, Return not detected")) m_nFlashMode = 0x45;
|
||
if (strFlashMode == _T("Fired, Red-eye reduction, Return detected")) m_nFlashMode = 0x47;
|
||
if (strFlashMode == _T("On, Red-eye reduction")) m_nFlashMode = 0x49;
|
||
if (strFlashMode == _T("On, Red-eye reduction, Return not detected")) m_nFlashMode = 0x4d;
|
||
if (strFlashMode == _T("On, Red-eye reduction, Return detected")) m_nFlashMode = 0x4f;
|
||
if (strFlashMode == _T("Off, Red-eye reduction")) m_nFlashMode = 0x50;
|
||
if (strFlashMode == _T("Auto, Did not fire, Red-eye reduction")) m_nFlashMode = 0x58;
|
||
if (strFlashMode == _T("Auto, Fired, Red-eye reduction")) m_nFlashMode = 0x59;
|
||
if (strFlashMode == _T("Auto, Fired, Red-eye reduction, Return not detected")) m_nFlashMode = 0x5d;
|
||
if (strFlashMode == _T("Auto, Fired, Red-eye reduction, Return detected")) m_nFlashMode =0x5f;
|
||
|
||
CString strColorSpace;
|
||
ReadNodeText(oReader, _T("ColorSpace"), &strColorSpace);
|
||
if (strColorSpace == _T("sRGB"))m_nColorSpace =1;
|
||
if (strColorSpace == _T("Uncalibrated"))m_nColorSpace =65535;
|
||
|
||
ReadNodeText(oReader, _T("BitDepth"),&m_nBitDepth);
|
||
ReadNodeText(oReader, _T("MultiPageImage"), &m_bMultiPageImage );
|
||
|
||
return TRUE;
|
||
}
|
||
private:
|
||
|
||
struct TDateTime
|
||
{
|
||
short nYear;
|
||
short nMonth;
|
||
short nDay;
|
||
short nHour;
|
||
short nMinute;
|
||
short nSecond;
|
||
CString sSummary;
|
||
};
|
||
|
||
CString m_sAuthor;
|
||
CString m_sTitle;
|
||
CString m_sDescription;
|
||
TDateTime m_oDateTimeCreation;
|
||
CString m_sCopyright;
|
||
CString m_sDisclaimer;
|
||
CString m_sComment;
|
||
CString m_sEquipmentType;
|
||
CString m_sEquipmentModel;
|
||
TDateTime m_oJobTime;
|
||
CString m_sJobName;
|
||
CString m_sSoftwareID;
|
||
short m_nVersionNumber;
|
||
CString m_sVersionLetter;
|
||
CString m_sHostComputer;
|
||
CString m_sWarning;
|
||
CString m_sDocumentName;
|
||
CString m_sPageName;
|
||
short m_nPageNumber;
|
||
short m_nPagesCount;
|
||
|
||
short m_nExposureProgram;
|
||
TRationalU m_oExposureTime;
|
||
TRational m_oExposureCompensation;
|
||
TRational m_oShutterSpeed;
|
||
TRationalU m_oLensAperture;
|
||
TRationalU m_oFocalLength;
|
||
TRationalU m_oFNumber;
|
||
TRationalU m_oMaxApertureValue;
|
||
TRational m_oBrightness;
|
||
|
||
short m_nISOSpeed;
|
||
short m_nMeteringMode;
|
||
short m_nFlashMode;
|
||
short m_nColorSpace;
|
||
|
||
short m_nSensingMethod;
|
||
short m_nWhiteBalance;
|
||
short m_nExposureMode ;
|
||
short m_nFocalLengthIn35mmFilm;
|
||
|
||
short m_nOrientation;
|
||
|
||
short m_nBitDepth;
|
||
BOOL m_bMultiPageImage;
|
||
|
||
CString m_sMetaDataXML;
|
||
|
||
BOOL m_bBitmap;
|
||
|
||
protected:
|
||
|
||
#pragma pack(push,1)
|
||
|
||
// Tiff структуры
|
||
struct TTiffFileHeader
|
||
{
|
||
BYTE nByteOrder[2];
|
||
BYTE nSignature[2];
|
||
BYTE nIDFoffset[4];
|
||
};
|
||
|
||
struct TDirectoryEntry
|
||
{
|
||
BYTE nTag[2];
|
||
BYTE nType[2];
|
||
BYTE nCount[4];
|
||
BYTE nValueOffset[4];
|
||
};
|
||
|
||
|
||
|
||
// PNG структуры
|
||
struct TChunk
|
||
{
|
||
BYTE nLenght[4];
|
||
BYTE nType[4];
|
||
};
|
||
struct TChunkTIME
|
||
{
|
||
BYTE nYear[2];
|
||
BYTE nMonth;
|
||
BYTE nDay;
|
||
BYTE nHour;
|
||
BYTE nMinute;
|
||
BYTE nSecond;
|
||
};
|
||
struct TChunkACTL
|
||
{
|
||
BYTE unNumFrames[4];
|
||
BYTE unNumPlays[4];
|
||
};
|
||
|
||
|
||
// TGA структуры
|
||
struct TFileFooter
|
||
{
|
||
DWORD nExtensionAreaOffset;
|
||
DWORD nDeveloperAreaOffset;
|
||
BYTE arrSignature[18];
|
||
};
|
||
struct TExtensionArea
|
||
{
|
||
WORD nExtensionSize;
|
||
BYTE sAuthorName[41];
|
||
BYTE sComments[324];
|
||
short nDateTime[6];
|
||
BYTE sJobName[41];
|
||
short nJobTime[3];
|
||
BYTE sSoftwareID[41];
|
||
short nSoftwareVersionNumber;
|
||
BYTE nSoftwareVersionLetter;
|
||
long nKeyColor;
|
||
short nPixelAspectRatio[2];
|
||
short nGammaValue[2];
|
||
long nColorCorrectionOffset;
|
||
long nPostageStampOffset;
|
||
long nScanLineOffset;
|
||
BYTE nAttributesType;
|
||
};
|
||
|
||
|
||
// Raw струтуры
|
||
// Raw-foveon
|
||
struct TFoveonDirectorySectionHeader
|
||
{
|
||
BYTE pSignature[4];
|
||
short nVersion[2];
|
||
DWORD nDirectoryEntriesCount;
|
||
};
|
||
|
||
struct TFoveonDirectoryEntries
|
||
{
|
||
DWORD nOffeset;
|
||
DWORD nLenght;
|
||
BYTE pType[4];
|
||
};
|
||
|
||
struct TFoveonPROPHeader
|
||
{
|
||
BYTE pSignature[4];
|
||
DWORD nVersion;
|
||
DWORD nEntriesCount;
|
||
DWORD nFormat;
|
||
BYTE pRESERVED[4]; // не используется
|
||
DWORD nTotalLenght;
|
||
// total, потомучто тут сумма длины имени
|
||
// свойста и его значения
|
||
};
|
||
struct TFoveonPROPOffsets
|
||
{
|
||
DWORD nName;
|
||
DWORD nValue;
|
||
};
|
||
|
||
// PDS структуры
|
||
struct TPSDFileHeader
|
||
{
|
||
BYTE nSignature[4]; // always equal 8BPS, do not read file if not
|
||
BYTE nVersion[2]; // always equal 1, do not read file if not
|
||
BYTE nReserved[6]; // must be zero
|
||
BYTE nChannels[2]; // numer of channels including any alpha channels, supported range 1 to 24
|
||
BYTE nRows[4]; // height in PIXELS, supported range 1 to 30000
|
||
BYTE nColumns[4]; // width in PIXELS, supported range 1 to 30000
|
||
BYTE nDepth[2]; // number of bpp
|
||
BYTE nMode[2]; // colour mode of the EColorMode
|
||
};
|
||
// PCX структуры
|
||
struct TPCXFileHeader
|
||
{
|
||
BYTE nManufacturer; // код производителя (редактора)
|
||
BYTE nVersion; // версия файла
|
||
BYTE bEncoding; // сжатие данных: 0 - нет, 1 - да
|
||
BYTE nBitsPerPixelPerPlane; // количество бит на пиксел в слое
|
||
WORD nMinX, nMinY; // координаты изображения
|
||
WORD nMaxX, nMaxY; //
|
||
WORD nScreenHorResolution; // разрешение монитора по горизонтали
|
||
WORD nScreenVerResolution; // разрешение монитора по вертикали
|
||
BYTE arrColorMap[48]; // палитра RGB на 16 цветов
|
||
BYTE nReserved; // номер видеорижима (сейчас не используеться)
|
||
BYTE nPlanes; // количество слоёв
|
||
WORD nBytesPerLinePerPlane; // количество байт на строку в слое
|
||
WORD bGrayscalePalette; // итерпритация цветов палитры: 0 - оттенки серого, 1 - RGB
|
||
WORD nScannerHorResolution; // разрешение сканера по горизонтали
|
||
WORD nScannerVerResolution; // разрешение сканера по вертикали
|
||
BYTE arrExtraData[54]; // дополнительная информация
|
||
};
|
||
// Ras структуры
|
||
struct TRasFileHeader
|
||
{
|
||
DWORD nMagicNumber; // Magic (identification) number
|
||
DWORD nWidth; // Width of image in pixels
|
||
DWORD nHeight; // Height of image in pixels
|
||
DWORD nDepth; // Number of bits per pixel
|
||
DWORD nSize; // Size of image data in bytes
|
||
DWORD nType; // Type of raster file
|
||
DWORD nPaletteType; // Type of color map
|
||
DWORD nPaletteLength; // Size of the color map in bytes
|
||
};
|
||
|
||
|
||
#pragma pack(pop)
|
||
|
||
// класс для проверки чексуммы
|
||
// каждого кусочка файлов формата PNG
|
||
class crc32
|
||
{
|
||
|
||
protected:
|
||
|
||
unsigned m_Table[256];
|
||
|
||
public:
|
||
|
||
unsigned m_crc32;
|
||
crc32()
|
||
{
|
||
const unsigned CRC_POLY = 0xEDB88320;
|
||
unsigned i, j, r;
|
||
for (i = 0; i < 256; i++)
|
||
{
|
||
for (r = i, j = 8; j; j--)
|
||
r = r & 1? (r >> 1) ^ CRC_POLY: r >> 1;
|
||
m_Table[i] = r;
|
||
}
|
||
m_crc32 = 0;
|
||
}
|
||
void ProcessCRC(void* pData, int nLen)
|
||
{
|
||
const unsigned CRC_MASK = 0xD202EF8D;
|
||
register unsigned char* pdata = reinterpret_cast<unsigned char*>(pData);
|
||
register unsigned crc = m_crc32;
|
||
while (nLen--)
|
||
{
|
||
crc = m_Table[static_cast<unsigned char>(crc) ^ *pdata++] ^ crc >> 8;
|
||
crc ^= CRC_MASK;
|
||
}
|
||
m_crc32 = crc;
|
||
}
|
||
};
|
||
|
||
|
||
|
||
public:
|
||
|
||
|
||
};
|
||
|
||
|
||
|
||
|
||
|