1. 최초 커밋
This commit is contained in:
+371
@@ -0,0 +1,371 @@
|
|||||||
|
|
||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/visualstudio
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudio
|
||||||
|
|
||||||
|
### VisualStudio ###
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*[.json, .xml, .info]
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
### VisualStudio Patch ###
|
||||||
|
# Additional files built by Visual Studio
|
||||||
|
*.tlog
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/visualstudio
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||||
|
# Visual Studio 2010
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Raw2Bmp_MFC", "Raw2Bmp_MFC\Raw2Bmp_MFC.vcxproj", "{C2BB4747-AA19-43FF-9484-FCBE8004EB82}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Win32 = Debug|Win32
|
||||||
|
Release|Win32 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{C2BB4747-AA19-43FF-9484-FCBE8004EB82}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{C2BB4747-AA19-43FF-9484-FCBE8004EB82}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{C2BB4747-AA19-43FF-9484-FCBE8004EB82}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{C2BB4747-AA19-43FF-9484-FCBE8004EB82}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 3.7 MiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 3.8 MiB |
Binary file not shown.
@@ -0,0 +1,301 @@
|
|||||||
|
#include "StdAfx.h"
|
||||||
|
#include "ImageUtility.h"
|
||||||
|
|
||||||
|
HINTERNET g_hOpen, g_hConnect;
|
||||||
|
|
||||||
|
/////////////////// WorkerFunction //////////////////////
|
||||||
|
DWORD WINAPI WorkerFunction(IN LPVOID vThreadParm)
|
||||||
|
/*
|
||||||
|
Purpose:
|
||||||
|
Call InternetConnect to establish a FTP session
|
||||||
|
Arguments:
|
||||||
|
vThreadParm - points to PARM passed to thread
|
||||||
|
Returns:
|
||||||
|
returns 0
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
//PARM* pThreadParm;
|
||||||
|
// Initialize local pointer to void pointer passed to thread
|
||||||
|
//pThreadParm = (PARM*)vThreadParm;
|
||||||
|
|
||||||
|
FTP_INFO *ftpinfo = (FTP_INFO*)vThreadParm;
|
||||||
|
|
||||||
|
if (ftpinfo == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
g_hConnect = 0;
|
||||||
|
|
||||||
|
if ( !( g_hConnect = InternetConnect (
|
||||||
|
g_hOpen,
|
||||||
|
ftpinfo->ConnectAddress,
|
||||||
|
ftpinfo->ConnectPort,
|
||||||
|
ftpinfo->Id,
|
||||||
|
ftpinfo->Pw,
|
||||||
|
INTERNET_SERVICE_FTP,
|
||||||
|
INTERNET_FLAG_PASSIVE,
|
||||||
|
0 ) ) )
|
||||||
|
{
|
||||||
|
//cerr << "Error on InternetConnnect: " << GetLastError() << endl;
|
||||||
|
|
||||||
|
return 1; // failure
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // success
|
||||||
|
}
|
||||||
|
|
||||||
|
CImageUtility::CImageUtility(void) : pFtpUploadThread(NULL), pFtpUploadThread_ing(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CImageUtility::~CImageUtility(void)
|
||||||
|
{
|
||||||
|
if (pFtpUploadThread_ing)
|
||||||
|
{
|
||||||
|
if (WaitForSingleObject (pFtpUploadThread_ing->m_hThread, 2000) == WAIT_TIMEOUT)
|
||||||
|
{
|
||||||
|
AfxMessageBox(_T("Current File Upload Cancel"), MB_OK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CImageUtility::FileRead(CString FilePath, uint32_t Width, uint32_t Height, void *mem, uint32_t TypeSize)
|
||||||
|
{
|
||||||
|
FILE* fp;
|
||||||
|
|
||||||
|
int errorno = 0;
|
||||||
|
int FileLen = Width * Height;
|
||||||
|
if((errorno = fopen_s(&fp,FilePath,"rb")))
|
||||||
|
{
|
||||||
|
AfxMessageBox("Read File Open Error 00");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
fseek(fp,0L,SEEK_END);
|
||||||
|
long len =ftell(fp);
|
||||||
|
fseek(fp, len-FileLen*TypeSize, SEEK_SET);
|
||||||
|
int ReadCount = fread(mem,TypeSize,FileLen,fp);
|
||||||
|
if(ReadCount < FileLen)
|
||||||
|
{
|
||||||
|
AfxMessageBox("File Read error 00!");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT CImageUtility::FileRead_Thread ( LPVOID pParam )
|
||||||
|
{
|
||||||
|
FTP_INFO *ftpinfo = (FTP_INFO*)pParam;
|
||||||
|
|
||||||
|
if (ftpinfo == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if( g_hConnect == NULL ) return 0;
|
||||||
|
|
||||||
|
if( !FtpSetCurrentDirectory( g_hConnect, ftpinfo->DirPath ) )
|
||||||
|
{
|
||||||
|
AfxMessageBox(_T("FTP Path Error"));
|
||||||
|
|
||||||
|
InternetCloseHandle( g_hConnect );
|
||||||
|
InternetCloseHandle( g_hOpen );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !FtpPutFile( g_hConnect, ftpinfo->UploadFile, ftpinfo->UploadFile, INTERNET_FLAG_TRANSFER_BINARY|INTERNET_FLAG_RELOAD, 0 ))
|
||||||
|
{
|
||||||
|
AfxMessageBox(_T("FTP File Put Error"));
|
||||||
|
|
||||||
|
InternetCloseHandle( g_hConnect );
|
||||||
|
InternetCloseHandle( g_hOpen );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CImageUtility::FileUpload (FTP_INFO *ftpinfo)
|
||||||
|
{
|
||||||
|
if (ftpinfo == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CONNECT_RETRY:
|
||||||
|
|
||||||
|
BOOL bRetry = FALSE;
|
||||||
|
|
||||||
|
// FTP 오픈
|
||||||
|
if( (g_hOpen = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, NULL)) == NULL )
|
||||||
|
{
|
||||||
|
DWORD dwgle = GetLastError();
|
||||||
|
CString strTempory;
|
||||||
|
strTempory.Format(_T("Can't Use Network, Windows Code : 0x%08X"), dwgle);
|
||||||
|
AfxMessageBox(strTempory);
|
||||||
|
SAFE_DELETE(ftpinfo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FTP 서버 연결
|
||||||
|
|
||||||
|
pFtpUploadThread = AfxBeginThread( (AFX_THREADPROC)WorkerFunction, ftpinfo, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
|
||||||
|
pFtpUploadThread->m_bAutoDelete = FALSE;
|
||||||
|
pFtpUploadThread->ResumeThread();
|
||||||
|
|
||||||
|
if (!pFtpUploadThread)
|
||||||
|
{
|
||||||
|
AfxMessageBox(_T("Windows Thread Fail"));
|
||||||
|
SAFE_DELETE(ftpinfo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD dwResult = WaitForSingleObject (pFtpUploadThread->m_hThread, 5000);
|
||||||
|
|
||||||
|
// 쓰레드 타임아웃 (접속지연)
|
||||||
|
if (dwResult == WAIT_TIMEOUT)
|
||||||
|
{
|
||||||
|
if ( g_hOpen )
|
||||||
|
{
|
||||||
|
InternetCloseHandle ( g_hOpen );
|
||||||
|
}
|
||||||
|
|
||||||
|
// 쓰레드가 TimeOut된 상황은 InternetCloseHandle로서 해제됨
|
||||||
|
WaitForSingleObject (pFtpUploadThread->m_hThread, INFINITE);
|
||||||
|
|
||||||
|
bRetry = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 쓰레드 완료 (접속 불가)
|
||||||
|
if (dwResult == WAIT_OBJECT_0 && !g_hConnect)
|
||||||
|
{
|
||||||
|
if ( g_hOpen )
|
||||||
|
{
|
||||||
|
InternetCloseHandle ( g_hOpen );
|
||||||
|
}
|
||||||
|
|
||||||
|
bRetry = TRUE;
|
||||||
|
}
|
||||||
|
// 쓰레드 완료 (접속 성공)
|
||||||
|
else if (dwResult == WAIT_OBJECT_0 && g_hConnect)
|
||||||
|
{
|
||||||
|
bRetry = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete pFtpUploadThread;
|
||||||
|
pFtpUploadThread = NULL;
|
||||||
|
|
||||||
|
// 접속 재시도 확인
|
||||||
|
if (bRetry)
|
||||||
|
{
|
||||||
|
if (ftpinfo->CheckConnect)
|
||||||
|
{
|
||||||
|
SAFE_DELETE(ftpinfo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AfxMessageBox(_T("FTP Connect Fail, Retry?"), MB_RETRYCANCEL) == IDRETRY)
|
||||||
|
{
|
||||||
|
goto CONNECT_RETRY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SAFE_DELETE(ftpinfo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FTP 업로드
|
||||||
|
|
||||||
|
pFtpUploadThread_ing = AfxBeginThread( (AFX_THREADPROC)FileRead_Thread, ftpinfo, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
|
||||||
|
pFtpUploadThread_ing->m_bAutoDelete = FALSE;
|
||||||
|
pFtpUploadThread_ing->ResumeThread();
|
||||||
|
|
||||||
|
if (pFtpUploadThread_ing)
|
||||||
|
{
|
||||||
|
DWORD dwResult = WaitForSingleObject (pFtpUploadThread_ing->m_hThread, 30000);
|
||||||
|
|
||||||
|
if (dwResult == WAIT_TIMEOUT)
|
||||||
|
AfxMessageBox(_T("Image Upload TimeOut (max 30sec)"));
|
||||||
|
|
||||||
|
delete pFtpUploadThread_ing;
|
||||||
|
pFtpUploadThread_ing = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( g_hOpen )
|
||||||
|
{
|
||||||
|
InternetCloseHandle( g_hOpen );
|
||||||
|
g_hOpen = NULL;
|
||||||
|
}
|
||||||
|
if( g_hConnect )
|
||||||
|
{
|
||||||
|
InternetCloseHandle( g_hConnect );
|
||||||
|
g_hConnect = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SAFE_DELETE(ftpinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CImageUtility::MakeImage (CString strRawFilePath, CString strOutFilePath, uint32_t Width, uint32_t Height, UINT Type/* = 14*/)
|
||||||
|
{
|
||||||
|
CxImage img;
|
||||||
|
|
||||||
|
// RAW 메모리 로드
|
||||||
|
BYTE *pRaw = new BYTE[Width*Height*2];
|
||||||
|
if (!FileRead(strRawFilePath,Width, Height,pRaw,sizeof(WORD)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
WORD nMin = 0xFFFF;
|
||||||
|
WORD nMax = 0;
|
||||||
|
WORD nTemp;
|
||||||
|
double dTemp;
|
||||||
|
|
||||||
|
// min, max 탐색
|
||||||
|
WORD *pWord = (WORD *)pRaw;
|
||||||
|
for (UINT i=0; i<Width*Height; i++)
|
||||||
|
{
|
||||||
|
// 2Byte 리딩
|
||||||
|
nTemp = pWord[i] >> (16 - Type);
|
||||||
|
|
||||||
|
if( nTemp > nMax )
|
||||||
|
nMax = nTemp;
|
||||||
|
if( nTemp < nMin )
|
||||||
|
nMin = nTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// min, max를 통한 값 보정
|
||||||
|
for (UINT i=0; i<Width*Height; i++)
|
||||||
|
{
|
||||||
|
// 2Byte 리딩
|
||||||
|
nTemp = pWord[i] >> (16 - Type);
|
||||||
|
|
||||||
|
dTemp = (((double)nTemp - (double)nMin) / ((double)nMax - (double)nMin)) * 0xFF /*8bit*/;
|
||||||
|
|
||||||
|
pWord[i] = (WORD)dTemp;
|
||||||
|
//pRaw[i] = (BYTE)pWord[i];
|
||||||
|
pRaw[i] = (BYTE)pWord[i] * -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!img.CreateFromArray(pRaw, Width, Height, 8, Width, TRUE))
|
||||||
|
{
|
||||||
|
delete [] pRaw;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!img.Save(strOutFilePath, CXIMAGE_FORMAT_PNG))
|
||||||
|
{
|
||||||
|
delete [] pRaw;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete [] pRaw;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CImageUtility::ResizeImage (CString strFilePath, uint32_t Width, uint32_t Height)
|
||||||
|
{
|
||||||
|
CxImage img;
|
||||||
|
|
||||||
|
img.Load(strFilePath);
|
||||||
|
img.Resample(Width, Width);
|
||||||
|
img.Save(strFilePath, CXIMAGE_FORMAT_PNG);
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <wininet.h>
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
/*
|
||||||
|
//CString raw = _T("./1.raw");
|
||||||
|
//CString dst = _T("./1.png");
|
||||||
|
|
||||||
|
//CImageUtility IU;
|
||||||
|
//IU.MakeImage(raw, dst, 2520, 3032); default 14 bit
|
||||||
|
//IU.MakeImage(raw, dst, 3072, 3072, 14);
|
||||||
|
//IU.MakeImage(raw, dst, 2520, 3032, 16);
|
||||||
|
|
||||||
|
//IU.ResizeImage (dst, 480, 480);
|
||||||
|
|
||||||
|
//FTP_INFO *FI = new FTP_INFO;
|
||||||
|
//FI->ConnectAddress = _T("192.168.51.5");
|
||||||
|
//FI->ConnectPort = 21;
|
||||||
|
//FI->Id = _T("-----");
|
||||||
|
//FI->Pw = _T("-----");
|
||||||
|
//FI->DirPath = _T("/¼ÒÇÁÆ®¿þ¾î¿¬±¸¼Òtmp");
|
||||||
|
//FI->UploadFile = dst;
|
||||||
|
|
||||||
|
//IU.FileUpload ( FI );
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SAFE_DELETE(x) if (ftpinfo) delete ftpinfo; ftpinfo = NULL;
|
||||||
|
|
||||||
|
DWORD WINAPI WorkerFunction( LPVOID );
|
||||||
|
|
||||||
|
typedef struct _FTP_INFO
|
||||||
|
{
|
||||||
|
CString ConnectAddress;
|
||||||
|
INTERNET_PORT ConnectPort;
|
||||||
|
CString DirPath;
|
||||||
|
CString Id;
|
||||||
|
CString Pw;
|
||||||
|
CString UploadFile;
|
||||||
|
BOOL CheckConnect;
|
||||||
|
|
||||||
|
_FTP_INFO (BOOL bCheckConnect = FALSE)
|
||||||
|
{
|
||||||
|
CheckConnect = bCheckConnect;
|
||||||
|
};
|
||||||
|
|
||||||
|
}FTP_INFO;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
CHAR* pHost;
|
||||||
|
CHAR* pUser;
|
||||||
|
CHAR* pPass;
|
||||||
|
} PARM;
|
||||||
|
|
||||||
|
class CImageUtility
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CImageUtility(void);
|
||||||
|
virtual ~CImageUtility(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BOOL FileRead (CString FilePath, uint32_t Width, uint32_t Height, void *mem, uint32_t TypeSize);
|
||||||
|
|
||||||
|
// ThreadFnc
|
||||||
|
CWinThread *pFtpUploadThread;
|
||||||
|
CWinThread *pFtpUploadThread_ing;
|
||||||
|
|
||||||
|
static UINT FileRead_Thread ( LPVOID pParam );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
public:
|
||||||
|
|
||||||
|
BOOL MakeImage (CString strRawFilePath, CString strOutFilePath, uint32_t Width, uint32_t Height, UINT Type = 14);
|
||||||
|
void ResizeImage (CString strFilePath, uint32_t Width, uint32_t Height);
|
||||||
|
void FileUpload (FTP_INFO *ftpinfo);
|
||||||
|
};
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
|
||||||
|
// Raw2Bmp_MFC.cpp : 응용 프로그램에 대한 클래스 동작을 정의합니다.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "Raw2Bmp_MFC.h"
|
||||||
|
#include "Raw2Bmp_MFCDlg.h"
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#define new DEBUG_NEW
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// CRaw2Bmp_MFCApp
|
||||||
|
|
||||||
|
BEGIN_MESSAGE_MAP(CRaw2Bmp_MFCApp, CWinApp)
|
||||||
|
ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
|
||||||
|
END_MESSAGE_MAP()
|
||||||
|
|
||||||
|
|
||||||
|
// CRaw2Bmp_MFCApp 생성
|
||||||
|
|
||||||
|
CRaw2Bmp_MFCApp::CRaw2Bmp_MFCApp()
|
||||||
|
{
|
||||||
|
// 다시 시작 관리자 지원
|
||||||
|
m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
|
||||||
|
|
||||||
|
// TODO: 여기에 생성 코드를 추가합니다.
|
||||||
|
// InitInstance에 모든 중요한 초기화 작업을 배치합니다.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 유일한 CRaw2Bmp_MFCApp 개체입니다.
|
||||||
|
|
||||||
|
CRaw2Bmp_MFCApp theApp;
|
||||||
|
|
||||||
|
|
||||||
|
// CRaw2Bmp_MFCApp 초기화
|
||||||
|
|
||||||
|
BOOL CRaw2Bmp_MFCApp::InitInstance()
|
||||||
|
{
|
||||||
|
// 응용 프로그램 매니페스트가 ComCtl32.dll 버전 6 이상을 사용하여 비주얼 스타일을
|
||||||
|
// 사용하도록 지정하는 경우, Windows XP 상에서 반드시 InitCommonControlsEx()가 필요합니다.
|
||||||
|
// InitCommonControlsEx()를 사용하지 않으면 창을 만들 수 없습니다.
|
||||||
|
INITCOMMONCONTROLSEX InitCtrls;
|
||||||
|
InitCtrls.dwSize = sizeof(InitCtrls);
|
||||||
|
// 응용 프로그램에서 사용할 모든 공용 컨트롤 클래스를 포함하도록
|
||||||
|
// 이 항목을 설정하십시오.
|
||||||
|
InitCtrls.dwICC = ICC_WIN95_CLASSES;
|
||||||
|
InitCommonControlsEx(&InitCtrls);
|
||||||
|
|
||||||
|
CWinApp::InitInstance();
|
||||||
|
|
||||||
|
if (!AfxSocketInit())
|
||||||
|
{
|
||||||
|
AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AfxEnableControlContainer();
|
||||||
|
|
||||||
|
// 대화 상자에 셸 트리 뷰 또는
|
||||||
|
// 셸 목록 뷰 컨트롤이 포함되어 있는 경우 셸 관리자를 만듭니다.
|
||||||
|
CShellManager *pShellManager = new CShellManager;
|
||||||
|
|
||||||
|
// 표준 초기화
|
||||||
|
// 이들 기능을 사용하지 않고 최종 실행 파일의 크기를 줄이려면
|
||||||
|
// 아래에서 필요 없는 특정 초기화
|
||||||
|
// 루틴을 제거해야 합니다.
|
||||||
|
// 해당 설정이 저장된 레지스트리 키를 변경하십시오.
|
||||||
|
// TODO: 이 문자열을 회사 또는 조직의 이름과 같은
|
||||||
|
// 적절한 내용으로 수정해야 합니다.
|
||||||
|
SetRegistryKey(_T("로컬 응용 프로그램 마법사에서 생성된 응용 프로그램"));
|
||||||
|
|
||||||
|
CRaw2Bmp_MFCDlg dlg;
|
||||||
|
m_pMainWnd = &dlg;
|
||||||
|
INT_PTR nResponse = dlg.DoModal();
|
||||||
|
if (nResponse == IDOK)
|
||||||
|
{
|
||||||
|
// TODO: 여기에 [확인]을 클릭하여 대화 상자가 없어질 때 처리할
|
||||||
|
// 코드를 배치합니다.
|
||||||
|
}
|
||||||
|
else if (nResponse == IDCANCEL)
|
||||||
|
{
|
||||||
|
// TODO: 여기에 [취소]를 클릭하여 대화 상자가 없어질 때 처리할
|
||||||
|
// 코드를 배치합니다.
|
||||||
|
}
|
||||||
|
|
||||||
|
// 위에서 만든 셸 관리자를 삭제합니다.
|
||||||
|
if (pShellManager != NULL)
|
||||||
|
{
|
||||||
|
delete pShellManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 대화 상자가 닫혔으므로 응용 프로그램의 메시지 펌프를 시작하지 않고 응용 프로그램을 끝낼 수 있도록 FALSE를
|
||||||
|
// 반환합니다.
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
// Raw2Bmp_MFC.h : PROJECT_NAME 응용 프로그램에 대한 주 헤더 파일입니다.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef __AFXWIN_H__
|
||||||
|
#error "PCH에 대해 이 파일을 포함하기 전에 'stdafx.h'를 포함합니다."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "resource.h" // 주 기호입니다.
|
||||||
|
|
||||||
|
|
||||||
|
// CRaw2Bmp_MFCApp:
|
||||||
|
// 이 클래스의 구현에 대해서는 Raw2Bmp_MFC.cpp을 참조하십시오.
|
||||||
|
//
|
||||||
|
|
||||||
|
class CRaw2Bmp_MFCApp : public CWinApp
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CRaw2Bmp_MFCApp();
|
||||||
|
|
||||||
|
// 재정의입니다.
|
||||||
|
public:
|
||||||
|
virtual BOOL InitInstance();
|
||||||
|
|
||||||
|
// 구현입니다.
|
||||||
|
|
||||||
|
DECLARE_MESSAGE_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
extern CRaw2Bmp_MFCApp theApp;
|
||||||
Binary file not shown.
@@ -0,0 +1,164 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{C2BB4747-AA19-43FF-9484-FCBE8004EB82}</ProjectGuid>
|
||||||
|
<RootNamespace>Raw2Bmp_MFC</RootNamespace>
|
||||||
|
<Keyword>MFCProj</Keyword>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<UseOfMfc>Dynamic</UseOfMfc>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<UseOfMfc>Dynamic</UseOfMfc>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>$(ProjectDir)include</AdditionalIncludeDirectories>
|
||||||
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalLibraryDirectories>$(ProjectDir)include</AdditionalLibraryDirectories>
|
||||||
|
<AdditionalDependencies>
|
||||||
|
</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
<Midl>
|
||||||
|
<MkTypLibCompatible>false</MkTypLibCompatible>
|
||||||
|
<ValidateAllParameters>true</ValidateAllParameters>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</Midl>
|
||||||
|
<ResourceCompile>
|
||||||
|
<Culture>0x0412</Culture>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
</ResourceCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<AdditionalLibraryDirectories>$(ProjectDir)include</AdditionalLibraryDirectories>
|
||||||
|
</Link>
|
||||||
|
<Midl>
|
||||||
|
<MkTypLibCompatible>false</MkTypLibCompatible>
|
||||||
|
<ValidateAllParameters>true</ValidateAllParameters>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</Midl>
|
||||||
|
<ResourceCompile>
|
||||||
|
<Culture>0x0412</Culture>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
</ResourceCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="ReadMe.txt" />
|
||||||
|
<None Include="res\Raw2Bmp_MFC.ico" />
|
||||||
|
<None Include="res\Raw2Bmp_MFC.rc2" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="ImageUtility.h" />
|
||||||
|
<ClInclude Include="include\stdint.h" />
|
||||||
|
<ClInclude Include="include\xfile.h" />
|
||||||
|
<ClInclude Include="include\ximabmp.h" />
|
||||||
|
<ClInclude Include="include\ximacfg.h" />
|
||||||
|
<ClInclude Include="include\ximadef.h" />
|
||||||
|
<ClInclude Include="include\ximage.h" />
|
||||||
|
<ClInclude Include="include\ximagif.h" />
|
||||||
|
<ClInclude Include="include\ximaico.h" />
|
||||||
|
<ClInclude Include="include\ximaiter.h" />
|
||||||
|
<ClInclude Include="include\ximajas.h" />
|
||||||
|
<ClInclude Include="include\ximajbg.h" />
|
||||||
|
<ClInclude Include="include\ximajpg.h" />
|
||||||
|
<ClInclude Include="include\ximamng.h" />
|
||||||
|
<ClInclude Include="include\ximapcx.h" />
|
||||||
|
<ClInclude Include="include\ximapng.h" />
|
||||||
|
<ClInclude Include="include\ximapsd.h" />
|
||||||
|
<ClInclude Include="include\ximaraw.h" />
|
||||||
|
<ClInclude Include="include\ximaska.h" />
|
||||||
|
<ClInclude Include="include\ximatga.h" />
|
||||||
|
<ClInclude Include="include\ximath.h" />
|
||||||
|
<ClInclude Include="include\ximatif.h" />
|
||||||
|
<ClInclude Include="include\ximawbmp.h" />
|
||||||
|
<ClInclude Include="include\ximawmf.h" />
|
||||||
|
<ClInclude Include="include\xiofile.h" />
|
||||||
|
<ClInclude Include="include\xmemfile.h" />
|
||||||
|
<ClInclude Include="Raw2Bmp_MFC.h" />
|
||||||
|
<ClInclude Include="Raw2Bmp_MFCDlg.h" />
|
||||||
|
<ClInclude Include="Resource.h" />
|
||||||
|
<ClInclude Include="stdafx.h" />
|
||||||
|
<ClInclude Include="targetver.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="ImageUtility.cpp" />
|
||||||
|
<ClCompile Include="Raw2Bmp_MFC.cpp" />
|
||||||
|
<ClCompile Include="Raw2Bmp_MFCDlg.cpp" />
|
||||||
|
<ClCompile Include="stdafx.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="Raw2Bmp_MFC.rc" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
<ProjectExtensions>
|
||||||
|
<VisualStudio>
|
||||||
|
<UserProperties RESOURCE_FILE="Raw2Bmp_MFC.rc" />
|
||||||
|
</VisualStudio>
|
||||||
|
</ProjectExtensions>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="소스 파일">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="헤더 파일">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="리소스 파일">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="ximage">
|
||||||
|
<UniqueIdentifier>{0e9eada1-a1fb-4757-9922-164453846424}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="ReadMe.txt" />
|
||||||
|
<None Include="res\Raw2Bmp_MFC.rc2">
|
||||||
|
<Filter>리소스 파일</Filter>
|
||||||
|
</None>
|
||||||
|
<None Include="res\Raw2Bmp_MFC.ico">
|
||||||
|
<Filter>리소스 파일</Filter>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="Raw2Bmp_MFC.h">
|
||||||
|
<Filter>헤더 파일</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Raw2Bmp_MFCDlg.h">
|
||||||
|
<Filter>헤더 파일</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="stdafx.h">
|
||||||
|
<Filter>헤더 파일</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="targetver.h">
|
||||||
|
<Filter>헤더 파일</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Resource.h">
|
||||||
|
<Filter>헤더 파일</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximatif.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximawbmp.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximawmf.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\xiofile.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\xmemfile.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\stdint.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\xfile.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximabmp.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximacfg.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximadef.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximage.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximagif.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximaico.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximaiter.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximajas.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximajbg.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximajpg.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximamng.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximapcx.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximapng.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximapsd.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximaraw.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximaska.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximatga.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ximath.h">
|
||||||
|
<Filter>ximage</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="ImageUtility.h">
|
||||||
|
<Filter>헤더 파일</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Raw2Bmp_MFC.cpp">
|
||||||
|
<Filter>소스 파일</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Raw2Bmp_MFCDlg.cpp">
|
||||||
|
<Filter>소스 파일</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="stdafx.cpp">
|
||||||
|
<Filter>소스 파일</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="ImageUtility.cpp">
|
||||||
|
<Filter>소스 파일</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="Raw2Bmp_MFC.rc">
|
||||||
|
<Filter>리소스 파일</Filter>
|
||||||
|
</ResourceCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
|
||||||
|
// Raw2Bmp_MFCDlg.cpp : 구현 파일
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "Raw2Bmp_MFC.h"
|
||||||
|
#include "Raw2Bmp_MFCDlg.h"
|
||||||
|
#include "afxdialogex.h"
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#define new DEBUG_NEW
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// CRaw2Bmp_MFCDlg 대화 상자
|
||||||
|
|
||||||
|
#define RAW_WIDTH 3072
|
||||||
|
#define RAW_HEIGHT 3072
|
||||||
|
|
||||||
|
CRaw2Bmp_MFCDlg::CRaw2Bmp_MFCDlg(CWnd* pParent /*=NULL*/)
|
||||||
|
: CDialogEx(CRaw2Bmp_MFCDlg::IDD, pParent)
|
||||||
|
{
|
||||||
|
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CRaw2Bmp_MFCDlg::DoDataExchange(CDataExchange* pDX)
|
||||||
|
{
|
||||||
|
CDialogEx::DoDataExchange(pDX);
|
||||||
|
}
|
||||||
|
|
||||||
|
BEGIN_MESSAGE_MAP(CRaw2Bmp_MFCDlg, CDialogEx)
|
||||||
|
ON_WM_PAINT()
|
||||||
|
ON_WM_QUERYDRAGICON()
|
||||||
|
ON_BN_CLICKED(IDOK, &CRaw2Bmp_MFCDlg::OnBnClickedOk)
|
||||||
|
END_MESSAGE_MAP()
|
||||||
|
|
||||||
|
|
||||||
|
// CRaw2Bmp_MFCDlg 메시지 처리기
|
||||||
|
|
||||||
|
BOOL CRaw2Bmp_MFCDlg::OnInitDialog()
|
||||||
|
{
|
||||||
|
CDialogEx::OnInitDialog();
|
||||||
|
|
||||||
|
// 이 대화 상자의 아이콘을 설정합니다. 응용 프로그램의 주 창이 대화 상자가 아닐 경우에는
|
||||||
|
// 프레임워크가 이 작업을 자동으로 수행합니다.
|
||||||
|
SetIcon(m_hIcon, TRUE); // 큰 아이콘을 설정합니다.
|
||||||
|
SetIcon(m_hIcon, FALSE); // 작은 아이콘을 설정합니다.
|
||||||
|
|
||||||
|
// TODO: 여기에 추가 초기화 작업을 추가합니다.
|
||||||
|
|
||||||
|
return TRUE; // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.
|
||||||
|
}
|
||||||
|
|
||||||
|
// 대화 상자에 최소화 단추를 추가할 경우 아이콘을 그리려면
|
||||||
|
// 아래 코드가 필요합니다. 문서/뷰 모델을 사용하는 MFC 응용 프로그램의 경우에는
|
||||||
|
// 프레임워크에서 이 작업을 자동으로 수행합니다.
|
||||||
|
|
||||||
|
void CRaw2Bmp_MFCDlg::OnPaint()
|
||||||
|
{
|
||||||
|
if (IsIconic())
|
||||||
|
{
|
||||||
|
CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.
|
||||||
|
|
||||||
|
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
|
||||||
|
|
||||||
|
// 클라이언트 사각형에서 아이콘을 가운데에 맞춥니다.
|
||||||
|
int cxIcon = GetSystemMetrics(SM_CXICON);
|
||||||
|
int cyIcon = GetSystemMetrics(SM_CYICON);
|
||||||
|
CRect rect;
|
||||||
|
GetClientRect(&rect);
|
||||||
|
int x = (rect.Width() - cxIcon + 1) / 2;
|
||||||
|
int y = (rect.Height() - cyIcon + 1) / 2;
|
||||||
|
|
||||||
|
// 아이콘을 그립니다.
|
||||||
|
dc.DrawIcon(x, y, m_hIcon);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CDialogEx::OnPaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 사용자가 최소화된 창을 끄는 동안에 커서가 표시되도록 시스템에서
|
||||||
|
// 이 함수를 호출합니다.
|
||||||
|
HCURSOR CRaw2Bmp_MFCDlg::OnQueryDragIcon()
|
||||||
|
{
|
||||||
|
return static_cast<HCURSOR>(m_hIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CRaw2Bmp_MFCDlg::OnBnClickedOk()
|
||||||
|
{
|
||||||
|
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
|
||||||
|
|
||||||
|
//CString raw = _T("./Sample.RAW");
|
||||||
|
//CString dst = _T("./Sample.png");
|
||||||
|
|
||||||
|
CString raw = _T("./1.raw");
|
||||||
|
CString dst = _T("./1.png");
|
||||||
|
|
||||||
|
//IU.MakeImage(raw, dst, 2520, 3032); default 14 bit
|
||||||
|
//IU.MakeImage(raw, dst, 3072, 3072, 16);
|
||||||
|
//IU.MakeImage(raw, dst, 2520, 3032, 16);
|
||||||
|
//IU.MakeImage(raw, dst, 3052, 3052, 16);
|
||||||
|
|
||||||
|
//IU.ResizeImage (dst, 480, 480);
|
||||||
|
|
||||||
|
FTP_INFO *FI = new FTP_INFO;
|
||||||
|
FI->ConnectAddress = _T("192.168.51.5");
|
||||||
|
FI->ConnectPort = 21;
|
||||||
|
FI->Id = _T("chodadoo");
|
||||||
|
FI->Pw = _T("");
|
||||||
|
FI->DirPath = _T("");
|
||||||
|
FI->UploadFile = dst;
|
||||||
|
|
||||||
|
IU.FileUpload ( FI );
|
||||||
|
|
||||||
|
//CDialogEx::OnOK();
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
// Raw2Bmp_MFCDlg.h : 헤더 파일
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ImageUtility.h"
|
||||||
|
|
||||||
|
// CRaw2Bmp_MFCDlg 대화 상자
|
||||||
|
class CRaw2Bmp_MFCDlg : public CDialogEx
|
||||||
|
{
|
||||||
|
// 생성입니다.
|
||||||
|
public:
|
||||||
|
CRaw2Bmp_MFCDlg(CWnd* pParent = NULL); // 표준 생성자입니다.
|
||||||
|
|
||||||
|
// 대화 상자 데이터입니다.
|
||||||
|
enum { IDD = IDD_RAW2BMP_MFC_DIALOG };
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 지원입니다.
|
||||||
|
|
||||||
|
|
||||||
|
// 구현입니다.
|
||||||
|
protected:
|
||||||
|
HICON m_hIcon;
|
||||||
|
|
||||||
|
// 생성된 메시지 맵 함수
|
||||||
|
virtual BOOL OnInitDialog();
|
||||||
|
afx_msg void OnPaint();
|
||||||
|
afx_msg HCURSOR OnQueryDragIcon();
|
||||||
|
DECLARE_MESSAGE_MAP()
|
||||||
|
public:
|
||||||
|
afx_msg void OnBnClickedOk();
|
||||||
|
|
||||||
|
CImageUtility IU;
|
||||||
|
};
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
================================================================================
|
||||||
|
MFC 라이브러리 : Raw2Bmp_MFC 프로젝트 개요
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
응용 프로그램 마법사에서 이 Raw2Bmp_MFC 응용 프로그램을
|
||||||
|
만들었습니다. 이 응용 프로그램은 MFC의 기본 사용법을 보여 줄 뿐만 아니라 응용
|
||||||
|
프로그램작성을 위한 기본 구조를 제공합니다.
|
||||||
|
|
||||||
|
이 파일에는 Raw2Bmp_MFC 응용 프로그램을 구성하는 각 파일에 대한
|
||||||
|
요약 설명이 포함되어 있습니다.
|
||||||
|
|
||||||
|
Raw2Bmp_MFC.vcxproj
|
||||||
|
응용 프로그램 마법사를 사용하여 생성된 VC++ 프로젝트의 주 프로젝트 파일입니다.
|
||||||
|
파일을 생성한 Visual C++ 버전에 대한 정보와 응용 프로그램 마법사를 사용하여 선택한
|
||||||
|
플랫폼, 구성 및 프로젝트 기능에 대한 정보가 들어 있습니다.
|
||||||
|
|
||||||
|
Raw2Bmp_MFC.vcxproj.filters
|
||||||
|
응용 프로그램 마법사를 사용하여 생성된 VC++ 프로젝트의 필터 파일입니다.
|
||||||
|
이 파일에는 프로젝트의 파일과 필터 간의 연결 정보가 들어 있습니다. 이러한
|
||||||
|
연결은 특정 노드에서 유사한 확장명으로 그룹화된 파일을 표시하기 위해
|
||||||
|
IDE에서 사용됩니다. 예를 들어 ".cpp" 파일은 "소스 파일" 필터와 연결되어
|
||||||
|
있습니다.
|
||||||
|
|
||||||
|
|
||||||
|
Raw2Bmp_MFC.h
|
||||||
|
응용 프로그램의 기본 헤더 파일입니다. 여기에는 다른 프로젝트 관련
|
||||||
|
헤더(Resource.h 포함)가 들어 있고 CRaw2Bmp_MFCApp 응용 프로그램
|
||||||
|
클래스를 선언합니다.
|
||||||
|
|
||||||
|
Raw2Bmp_MFC.cpp
|
||||||
|
응용 프로그램 클래스 CRaw2Bmp_MFCApp이(가) 들어 있는 기본 응용 프로그램
|
||||||
|
소스 파일입니다.
|
||||||
|
|
||||||
|
Raw2Bmp_MFC.rc
|
||||||
|
프로그램에서 사용하는 모든 Microsoft Windows 리소스의 목록입니다.
|
||||||
|
여기에는 RES 하위 디렉터리에 저장된 아이콘, 비트맵 및 커서가
|
||||||
|
포함됩니다. 이 파일은 Microsoft Visual C++에서 직접
|
||||||
|
편집할 수 있습니다. 프로젝트 리소스는 1042에 있습니다.
|
||||||
|
|
||||||
|
res\Raw2Bmp_MFC.ico
|
||||||
|
응용 프로그램의 아이콘으로 사용되는 아이콘 파일입니다. 이 아이콘은
|
||||||
|
주 리소스 파일인 Raw2Bmp_MFC.rc에 의해 포함됩니다.
|
||||||
|
|
||||||
|
res\Raw2Bmp_MFC.rc2
|
||||||
|
이 파일에는 Microsoft Visual C++ 이외의 다른 도구에서 편집한 리소스가
|
||||||
|
들어 있습니다. 리소스 편집기로 편집할 수 없는 모든 리소스는
|
||||||
|
이 파일에 넣어야 합니다.
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
응용 프로그램 마법사에서 하나의 대화 상자 클래스가 만들어집니다.
|
||||||
|
|
||||||
|
Raw2Bmp_MFCDlg.h, Raw2Bmp_MFCDlg.cpp - 대화 상자
|
||||||
|
이 파일에는 CRaw2Bmp_MFCDlg 클래스가 들어 있습니다. 이 클래스는
|
||||||
|
응용 프로그램의 주 대화 상자 동작을 정의합니다. 대화 상자의 템플릿은
|
||||||
|
Microsoft Visual C++에서 편집할 수 있는 Raw2Bmp_MFC.rc에 있습니다.
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
기타 기능:
|
||||||
|
|
||||||
|
ActiveX 컨트롤
|
||||||
|
응용 프로그램에서 ActiveX 컨트롤을 사용할 수 있도록 지원합니다.
|
||||||
|
|
||||||
|
Windows 소켓
|
||||||
|
응용 프로그램에서 TCP/IP 네트워크를 사용한 통신을 지원합니다.
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
기타 표준 파일:
|
||||||
|
|
||||||
|
StdAfx.h, StdAfx.cpp
|
||||||
|
이 파일은 미리 컴파일된 헤더 파일(PCH)인 Raw2Bmp_MFC.pch와
|
||||||
|
미리 컴파일된 형식 파일인 StdAfx.obj를 빌드하는 데 사용됩니다.
|
||||||
|
|
||||||
|
Resource.h
|
||||||
|
새 리소스 ID를 정의하는 표준 헤더 파일입니다.
|
||||||
|
Microsoft Visual C++에서 이 파일을 읽고 업데이트합니다.
|
||||||
|
|
||||||
|
Raw2Bmp_MFC.manifest
|
||||||
|
응용 프로그램 매니페스트 파일은 Windows XP에서 특정 버전의 Side-by-Side
|
||||||
|
어셈블리에 대한 응용 프로그램 종속성을 설명하는 데 사용됩니다. 로더는 이 정보를
|
||||||
|
사용하여 어셈블리 캐시에서 적절한 어셈블리를 로드하거나 응용 프로그램에서 전용
|
||||||
|
어셈블리를 로드합니다. 응용 프로그램 매니페스트는 응용 프로그램 실행 파일과 같은
|
||||||
|
폴더에 설치된 외부 .manifest 파일로 재배포를 위해 포함되거나 리소스의 형태로
|
||||||
|
실행 파일에 포함될 수 있습니다.
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
기타 참고:
|
||||||
|
|
||||||
|
응용 프로그램 마법사는 "TODO:"를 사용하여 추가하거나 사용자 지정해야 하는
|
||||||
|
소스 코드 부분을 나타냅니다.
|
||||||
|
|
||||||
|
응용 프로그램이 공유 DLL에서 MFC를 사용하는 경우 해당 MFC DLL을
|
||||||
|
재배포해야 합니다. 그리고 응용 프로그램이 운영 체제의 로캘과
|
||||||
|
다른 언어를 사용하는 경우 해당 지역화된 리소스인 MFC100XXX.DLL을
|
||||||
|
재배포해야 합니다. 이 두가지 항목에 대한 자세한 내용은
|
||||||
|
MSDN 설명서의 Visual C++ 응용 프로그램 재배포 항목을
|
||||||
|
참조하십시오.
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
//{{NO_DEPENDENCIES}}
|
||||||
|
// Microsoft Visual C++에서 생성한 포함 파일입니다.
|
||||||
|
// Raw2Bmp_MFC.rc에서 사용됩니다.
|
||||||
|
//
|
||||||
|
#define IDR_MAINFRAME 128
|
||||||
|
#define IDD_RAW2BMP_MFC_DIALOG 102
|
||||||
|
#define IDP_SOCKETS_INIT_FAILED 103
|
||||||
|
|
||||||
|
// 다음은 새 개체에 사용할 기본값입니다.
|
||||||
|
//
|
||||||
|
#ifdef APSTUDIO_INVOKED
|
||||||
|
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||||
|
|
||||||
|
#define _APS_NEXT_RESOURCE_VALUE 129
|
||||||
|
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||||
|
#define _APS_NEXT_SYMED_VALUE 101
|
||||||
|
#define _APS_NEXT_COMMAND_VALUE 32771
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 3.6 MiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,249 @@
|
|||||||
|
// ISO C9x compliant stdint.h for Microsoft Visual Studio
|
||||||
|
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2008 Alexander Chemeris
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
//
|
||||||
|
// 3. The name of the author may be used to endorse or promote products
|
||||||
|
// derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef _MSC_VER // [
|
||||||
|
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||||
|
#endif // _MSC_VER ]
|
||||||
|
|
||||||
|
#ifndef _MSC_STDINT_H_ // [
|
||||||
|
#define _MSC_STDINT_H_
|
||||||
|
|
||||||
|
#if _MSC_VER > 1000
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
||||||
|
// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
|
||||||
|
// or compiler give many errors like this:
|
||||||
|
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||||
|
/*
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
# include <wchar.h>
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Define _W64 macros to mark types changing their size, like intptr_t.
|
||||||
|
#ifndef _W64
|
||||||
|
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
|
||||||
|
# define _W64 __w64
|
||||||
|
# else
|
||||||
|
# define _W64
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// 7.18.1 Integer types
|
||||||
|
|
||||||
|
// 7.18.1.1 Exact-width integer types
|
||||||
|
|
||||||
|
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
|
||||||
|
// realize that, e.g. char has the same size as __int8
|
||||||
|
// so we give up on __intX for them.
|
||||||
|
#if (_MSC_VER < 1300)
|
||||||
|
typedef signed char int8_t;
|
||||||
|
typedef signed short int16_t;
|
||||||
|
typedef signed int int32_t;
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef unsigned short uint16_t;
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
#else
|
||||||
|
typedef signed __int8 int8_t;
|
||||||
|
typedef signed __int16 int16_t;
|
||||||
|
typedef signed __int32 int32_t;
|
||||||
|
typedef unsigned __int8 uint8_t;
|
||||||
|
typedef unsigned __int16 uint16_t;
|
||||||
|
typedef unsigned __int32 uint32_t;
|
||||||
|
#endif
|
||||||
|
typedef signed __int64 int64_t;
|
||||||
|
typedef unsigned __int64 uint64_t;
|
||||||
|
|
||||||
|
|
||||||
|
// 7.18.1.2 Minimum-width integer types
|
||||||
|
typedef int8_t int_least8_t;
|
||||||
|
typedef int16_t int_least16_t;
|
||||||
|
typedef int32_t int_least32_t;
|
||||||
|
typedef int64_t int_least64_t;
|
||||||
|
typedef uint8_t uint_least8_t;
|
||||||
|
typedef uint16_t uint_least16_t;
|
||||||
|
typedef uint32_t uint_least32_t;
|
||||||
|
typedef uint64_t uint_least64_t;
|
||||||
|
|
||||||
|
// 7.18.1.3 Fastest minimum-width integer types
|
||||||
|
typedef int8_t int_fast8_t;
|
||||||
|
typedef int16_t int_fast16_t;
|
||||||
|
typedef int32_t int_fast32_t;
|
||||||
|
typedef int64_t int_fast64_t;
|
||||||
|
typedef uint8_t uint_fast8_t;
|
||||||
|
typedef uint16_t uint_fast16_t;
|
||||||
|
typedef uint32_t uint_fast32_t;
|
||||||
|
typedef uint64_t uint_fast64_t;
|
||||||
|
|
||||||
|
// 7.18.1.4 Integer types capable of holding object pointers
|
||||||
|
#ifdef _WIN64 // [
|
||||||
|
typedef signed __int64 intptr_t;
|
||||||
|
typedef unsigned __int64 uintptr_t;
|
||||||
|
#else // _WIN64 ][
|
||||||
|
typedef _W64 signed int intptr_t;
|
||||||
|
typedef _W64 unsigned int uintptr_t;
|
||||||
|
#endif // _WIN64 ]
|
||||||
|
|
||||||
|
// 7.18.1.5 Greatest-width integer types
|
||||||
|
typedef int64_t intmax_t;
|
||||||
|
typedef uint64_t uintmax_t;
|
||||||
|
|
||||||
|
|
||||||
|
// 7.18.2 Limits of specified-width integer types
|
||||||
|
|
||||||
|
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
|
||||||
|
|
||||||
|
// 7.18.2.1 Limits of exact-width integer types
|
||||||
|
#define INT8_MIN ((int8_t)_I8_MIN)
|
||||||
|
#define INT8_MAX _I8_MAX
|
||||||
|
#define INT16_MIN ((int16_t)_I16_MIN)
|
||||||
|
#define INT16_MAX _I16_MAX
|
||||||
|
#define INT32_MIN ((int32_t)_I32_MIN)
|
||||||
|
#define INT32_MAX _I32_MAX
|
||||||
|
#define INT64_MIN ((int64_t)_I64_MIN)
|
||||||
|
#define INT64_MAX _I64_MAX
|
||||||
|
#define UINT8_MAX _UI8_MAX
|
||||||
|
#define UINT16_MAX _UI16_MAX
|
||||||
|
#define UINT32_MAX _UI32_MAX
|
||||||
|
#define UINT64_MAX _UI64_MAX
|
||||||
|
|
||||||
|
// 7.18.2.2 Limits of minimum-width integer types
|
||||||
|
#define INT_LEAST8_MIN INT8_MIN
|
||||||
|
#define INT_LEAST8_MAX INT8_MAX
|
||||||
|
#define INT_LEAST16_MIN INT16_MIN
|
||||||
|
#define INT_LEAST16_MAX INT16_MAX
|
||||||
|
#define INT_LEAST32_MIN INT32_MIN
|
||||||
|
#define INT_LEAST32_MAX INT32_MAX
|
||||||
|
#define INT_LEAST64_MIN INT64_MIN
|
||||||
|
#define INT_LEAST64_MAX INT64_MAX
|
||||||
|
#define UINT_LEAST8_MAX UINT8_MAX
|
||||||
|
#define UINT_LEAST16_MAX UINT16_MAX
|
||||||
|
#define UINT_LEAST32_MAX UINT32_MAX
|
||||||
|
#define UINT_LEAST64_MAX UINT64_MAX
|
||||||
|
|
||||||
|
// 7.18.2.3 Limits of fastest minimum-width integer types
|
||||||
|
#define INT_FAST8_MIN INT8_MIN
|
||||||
|
#define INT_FAST8_MAX INT8_MAX
|
||||||
|
#define INT_FAST16_MIN INT16_MIN
|
||||||
|
#define INT_FAST16_MAX INT16_MAX
|
||||||
|
#define INT_FAST32_MIN INT32_MIN
|
||||||
|
#define INT_FAST32_MAX INT32_MAX
|
||||||
|
#define INT_FAST64_MIN INT64_MIN
|
||||||
|
#define INT_FAST64_MAX INT64_MAX
|
||||||
|
#define UINT_FAST8_MAX UINT8_MAX
|
||||||
|
#define UINT_FAST16_MAX UINT16_MAX
|
||||||
|
#define UINT_FAST32_MAX UINT32_MAX
|
||||||
|
#define UINT_FAST64_MAX UINT64_MAX
|
||||||
|
|
||||||
|
// 7.18.2.4 Limits of integer types capable of holding object pointers
|
||||||
|
#ifdef _WIN64 // [
|
||||||
|
# define INTPTR_MIN INT64_MIN
|
||||||
|
# define INTPTR_MAX INT64_MAX
|
||||||
|
# define UINTPTR_MAX UINT64_MAX
|
||||||
|
#else // _WIN64 ][
|
||||||
|
# define INTPTR_MIN INT32_MIN
|
||||||
|
# define INTPTR_MAX INT32_MAX
|
||||||
|
# define UINTPTR_MAX UINT32_MAX
|
||||||
|
#endif // _WIN64 ]
|
||||||
|
|
||||||
|
// 7.18.2.5 Limits of greatest-width integer types
|
||||||
|
#define INTMAX_MIN INT64_MIN
|
||||||
|
#define INTMAX_MAX INT64_MAX
|
||||||
|
#define UINTMAX_MAX UINT64_MAX
|
||||||
|
|
||||||
|
// 7.18.3 Limits of other integer types
|
||||||
|
|
||||||
|
#ifdef _WIN64 // [
|
||||||
|
# define PTRDIFF_MIN _I64_MIN
|
||||||
|
# define PTRDIFF_MAX _I64_MAX
|
||||||
|
#else // _WIN64 ][
|
||||||
|
# define PTRDIFF_MIN _I32_MIN
|
||||||
|
# define PTRDIFF_MAX _I32_MAX
|
||||||
|
#endif // _WIN64 ]
|
||||||
|
|
||||||
|
#define SIG_ATOMIC_MIN INT_MIN
|
||||||
|
#define SIG_ATOMIC_MAX INT_MAX
|
||||||
|
|
||||||
|
#ifndef SIZE_MAX // [
|
||||||
|
# ifdef _WIN64 // [
|
||||||
|
# define SIZE_MAX _UI64_MAX
|
||||||
|
# else // _WIN64 ][
|
||||||
|
# define SIZE_MAX _UI32_MAX
|
||||||
|
# endif // _WIN64 ]
|
||||||
|
#endif // SIZE_MAX ]
|
||||||
|
|
||||||
|
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
|
||||||
|
#ifndef WCHAR_MIN // [
|
||||||
|
# define WCHAR_MIN 0
|
||||||
|
#endif // WCHAR_MIN ]
|
||||||
|
#ifndef WCHAR_MAX // [
|
||||||
|
# define WCHAR_MAX _UI16_MAX
|
||||||
|
#endif // WCHAR_MAX ]
|
||||||
|
|
||||||
|
#define WINT_MIN 0
|
||||||
|
#define WINT_MAX _UI16_MAX
|
||||||
|
|
||||||
|
#endif // __STDC_LIMIT_MACROS ]
|
||||||
|
|
||||||
|
|
||||||
|
// 7.18.4 Limits of other integer types
|
||||||
|
|
||||||
|
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
|
||||||
|
|
||||||
|
// 7.18.4.1 Macros for minimum-width integer constants
|
||||||
|
|
||||||
|
#define INT8_C(val) val##i8
|
||||||
|
#define INT16_C(val) val##i16
|
||||||
|
#define INT32_C(val) val##i32
|
||||||
|
#define INT64_C(val) val##i64
|
||||||
|
|
||||||
|
#define UINT8_C(val) val##ui8
|
||||||
|
#define UINT16_C(val) val##ui16
|
||||||
|
#define UINT32_C(val) val##ui32
|
||||||
|
#define UINT64_C(val) val##ui64
|
||||||
|
|
||||||
|
// 7.18.4.2 Macros for greatest-width integer constants
|
||||||
|
#define INTMAX_C INT64_C
|
||||||
|
#define UINTMAX_C UINT64_C
|
||||||
|
|
||||||
|
#endif // __STDC_CONSTANT_MACROS ]
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _MSC_STDINT_H_ ]
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
/*
|
||||||
|
* TIFF file IO, using CxFile.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_TIF
|
||||||
|
|
||||||
|
#include "../tiff/tiffiop.h"
|
||||||
|
#include "../tiff/tiffvers.h"
|
||||||
|
|
||||||
|
#include "xfile.h"
|
||||||
|
|
||||||
|
static tsize_t
|
||||||
|
_tiffReadProcEx(thandle_t fd, tdata_t buf, tsize_t size)
|
||||||
|
{
|
||||||
|
return (tsize_t)((CxFile*)fd)->Read(buf, 1, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static tsize_t
|
||||||
|
_tiffWriteProcEx(thandle_t fd, tdata_t buf, tsize_t size)
|
||||||
|
{
|
||||||
|
return (tsize_t)((CxFile*)fd)->Write(buf, 1, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static toff_t
|
||||||
|
_tiffSeekProcEx(thandle_t fd, toff_t off, int whence)
|
||||||
|
{
|
||||||
|
if ( off == 0xFFFFFFFF )
|
||||||
|
return 0xFFFFFFFF;
|
||||||
|
if (!((CxFile*)fd)->Seek(off, whence))
|
||||||
|
return 0xFFFFFFFF;
|
||||||
|
if (whence == SEEK_SET)
|
||||||
|
return off;
|
||||||
|
|
||||||
|
return (toff_t)((CxFile*)fd)->Tell();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return nonzero if error
|
||||||
|
static int
|
||||||
|
_tiffCloseProcEx(thandle_t /*fd*/)
|
||||||
|
{
|
||||||
|
// return !((CxFile*)fd)->Close(); // "//" needed for memory files <DP>
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
static toff_t
|
||||||
|
_tiffSizeProcEx(thandle_t fd)
|
||||||
|
{
|
||||||
|
return ((CxFile*)fd)->Size();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_tiffMapProcEx(thandle_t /*fd*/, tdata_t* /*pbase*/, toff_t* /*psize*/)
|
||||||
|
{
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_tiffUnmapProcEx(thandle_t /*fd*/, tdata_t /*base*/, toff_t /*size*/)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a TIFF file descriptor for read/writing.
|
||||||
|
/*
|
||||||
|
TIFF*
|
||||||
|
TIFFOpen(const char* name, const char* mode)
|
||||||
|
{
|
||||||
|
static const char module[] = "TIFFOpen";
|
||||||
|
FILE* stream = fopen(name, mode);
|
||||||
|
if (stream == NULL)
|
||||||
|
{
|
||||||
|
TIFFError(module, "%s: Cannot open", name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return (TIFFFdOpen((int)stream, name, mode));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
TIFF*
|
||||||
|
_TIFFFdOpen(void* fd, const char* name, const char* mode)
|
||||||
|
{
|
||||||
|
TIFF* tif;
|
||||||
|
|
||||||
|
tif = TIFFClientOpen(name, mode,
|
||||||
|
(thandle_t) fd,
|
||||||
|
_tiffReadProcEx, _tiffWriteProcEx, _tiffSeekProcEx, _tiffCloseProcEx,
|
||||||
|
_tiffSizeProcEx, _tiffMapProcEx, _tiffUnmapProcEx);
|
||||||
|
if (tif)
|
||||||
|
{
|
||||||
|
tif->tif_fd = (int)fd;
|
||||||
|
}
|
||||||
|
return (tif);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" TIFF* _TIFFOpenEx(CxFile* stream, const char* mode)
|
||||||
|
{
|
||||||
|
return (_TIFFFdOpen(stream, "TIFF IMAGE", mode));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
extern char* malloc();
|
||||||
|
extern char* realloc();
|
||||||
|
#else
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
tdata_t
|
||||||
|
_TIFFmalloc(tsize_t s)
|
||||||
|
{
|
||||||
|
return (malloc((size_t) s));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_TIFFfree(tdata_t p)
|
||||||
|
{
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
tdata_t
|
||||||
|
_TIFFrealloc(tdata_t p, tsize_t s)
|
||||||
|
{
|
||||||
|
return (realloc(p, (size_t) s));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_TIFFmemset(tdata_t p, int v, tsize_t c)
|
||||||
|
{
|
||||||
|
memset(p, v, (size_t) c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c)
|
||||||
|
{
|
||||||
|
memcpy(d, s, (size_t) c);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c)
|
||||||
|
{
|
||||||
|
return (memcmp(p1, p2, (size_t) c));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef UNICODE
|
||||||
|
#define DbgPrint wvsprintf
|
||||||
|
#define DbgPrint2 wsprintf
|
||||||
|
#define DbgMsgBox MessageBox
|
||||||
|
#else
|
||||||
|
#define DbgPrint wvsprintfA
|
||||||
|
#define DbgPrint2 wsprintfA
|
||||||
|
#define DbgMsgBox MessageBoxA
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
Win32WarningHandler(const char* module, const char* fmt, va_list ap)
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#if (!defined(_CONSOLE) && !defined(_WIN32_WCE) && defined(WIN32))
|
||||||
|
LPSTR szTitle;
|
||||||
|
LPSTR szTmp;
|
||||||
|
LPCSTR szTitleText = "%s Warning";
|
||||||
|
LPCSTR szDefaultModule = "TIFFLIB";
|
||||||
|
szTmp = (module == NULL) ? (LPSTR)szDefaultModule : (LPSTR)module;
|
||||||
|
if ((szTitle = (LPSTR)LocalAlloc(LMEM_FIXED, (strlen(szTmp) +
|
||||||
|
strlen(szTitleText) + strlen(fmt) + 128))) == NULL)
|
||||||
|
return;
|
||||||
|
DbgPrint2(szTitle, szTitleText, szTmp);
|
||||||
|
szTmp = szTitle + (strlen(szTitle)+2);
|
||||||
|
DbgPrint(szTmp, fmt, ap);
|
||||||
|
DbgMsgBox(GetFocus(), szTmp, szTitle, MB_OK | MB_ICONINFORMATION);
|
||||||
|
LocalFree(szTitle);
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
if (module != NULL)
|
||||||
|
fprintf(stderr, "%s: ", module);
|
||||||
|
fprintf(stderr, "Warning, ");
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
fprintf(stderr, ".\n");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
TIFFErrorHandler _TIFFwarningHandler = Win32WarningHandler;
|
||||||
|
|
||||||
|
static void
|
||||||
|
Win32ErrorHandler(const char* module, const char* fmt, va_list ap)
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#if (!defined(_CONSOLE) && !defined(_WIN32_WCE) && defined(WIN32))
|
||||||
|
LPSTR szTitle;
|
||||||
|
LPSTR szTmp;
|
||||||
|
LPCSTR szTitleText = "%s Error";
|
||||||
|
LPCSTR szDefaultModule = "TIFFLIB";
|
||||||
|
szTmp = (module == NULL) ? (LPSTR)szDefaultModule : (LPSTR)module;
|
||||||
|
if ((szTitle = (LPSTR)LocalAlloc(LMEM_FIXED, (strlen(szTmp) +
|
||||||
|
strlen(szTitleText) + strlen(fmt) + 128))) == NULL)
|
||||||
|
return;
|
||||||
|
DbgPrint2(szTitle, szTitleText, szTmp);
|
||||||
|
szTmp = szTitle + (strlen(szTitle)+2);
|
||||||
|
DbgPrint(szTmp, fmt, ap);
|
||||||
|
DbgMsgBox(GetFocus(), szTmp, szTitle, MB_OK | MB_ICONEXCLAMATION);
|
||||||
|
LocalFree(szTitle);
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
if (module != NULL)
|
||||||
|
fprintf(stderr, "%s: ", module);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
fprintf(stderr, ".\n");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
TIFFErrorHandler _TIFFerrorHandler = Win32ErrorHandler;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* File: xfile.h
|
||||||
|
* Purpose: General Purpose File Class
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
|
||||||
|
|
||||||
|
CxFile (c) 11/May/2002 Davide Pizzolato - www.xdp.it
|
||||||
|
CxFile version 2.00 23/Aug/2002
|
||||||
|
CxFile version 2.10 16/Dec/2007
|
||||||
|
|
||||||
|
Special thanks to Chris Shearer Cooper for new features, enhancements and bugfixes
|
||||||
|
|
||||||
|
Covered code is provided under this license on an "as is" basis, without warranty
|
||||||
|
of any kind, either expressed or implied, including, without limitation, warranties
|
||||||
|
that the covered code is free of defects, merchantable, fit for a particular purpose
|
||||||
|
or non-infringing. The entire risk as to the quality and performance of the covered
|
||||||
|
code is with you. Should any covered code prove defective in any respect, you (not
|
||||||
|
the initial developer or any other contributor) assume the cost of any necessary
|
||||||
|
servicing, repair or correction. This disclaimer of warranty constitutes an essential
|
||||||
|
part of this license. No use of any covered code is authorized hereunder except under
|
||||||
|
this disclaimer.
|
||||||
|
|
||||||
|
Permission is hereby granted to use, copy, modify, and distribute this
|
||||||
|
source code, or portions hereof, for any purpose, including commercial applications,
|
||||||
|
freely and without fee, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#if !defined(__xfile_h)
|
||||||
|
#define __xfile_h
|
||||||
|
|
||||||
|
#if defined (WIN32) || defined (_WIN32_WCE)
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "ximadef.h"
|
||||||
|
|
||||||
|
class DLL_EXP CxFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CxFile(void) { };
|
||||||
|
virtual ~CxFile() { };
|
||||||
|
|
||||||
|
virtual bool Close() = 0;
|
||||||
|
virtual size_t Read(void *buffer, size_t size, size_t count) = 0;
|
||||||
|
virtual size_t Write(const void *buffer, size_t size, size_t count) = 0;
|
||||||
|
virtual bool Seek(int32_t offset, int32_t origin) = 0;
|
||||||
|
virtual int32_t Tell() = 0;
|
||||||
|
virtual int32_t Size() = 0;
|
||||||
|
virtual bool Flush() = 0;
|
||||||
|
virtual bool Eof() = 0;
|
||||||
|
virtual int32_t Error() = 0;
|
||||||
|
virtual bool PutC(uint8_t c)
|
||||||
|
{
|
||||||
|
// Default implementation
|
||||||
|
size_t nWrote = Write(&c, 1, 1);
|
||||||
|
return (bool)(nWrote == 1);
|
||||||
|
}
|
||||||
|
virtual int32_t GetC() = 0;
|
||||||
|
virtual char * GetS(char *string, int32_t n) = 0;
|
||||||
|
virtual int32_t Scanf(const char *format, void* output) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //__xfile_h
|
||||||
@@ -0,0 +1,448 @@
|
|||||||
|
/*
|
||||||
|
* File: ximabmp.cpp
|
||||||
|
* Purpose: Platform Independent BMP Image Class Loader and Writer
|
||||||
|
* 07/Aug/2001 Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximabmp.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_BMP
|
||||||
|
|
||||||
|
#include "ximaiter.h"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageBMP::Encode(CxFile * hFile)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (EncodeSafeCheck(hFile)) return false;
|
||||||
|
|
||||||
|
BITMAPFILEHEADER hdr;
|
||||||
|
|
||||||
|
hdr.bfType = 0x4d42; // 'BM' WINDOWS_BITMAP_SIGNATURE
|
||||||
|
hdr.bfSize = GetSize() + 14 /*sizeof(BITMAPFILEHEADER)*/;
|
||||||
|
hdr.bfReserved1 = hdr.bfReserved2 = 0;
|
||||||
|
hdr.bfOffBits = 14 /*sizeof(BITMAPFILEHEADER)*/ + head.biSize + GetPaletteSize();
|
||||||
|
|
||||||
|
hdr.bfType = m_ntohs(hdr.bfType);
|
||||||
|
hdr.bfSize = m_ntohl(hdr.bfSize);
|
||||||
|
hdr.bfOffBits = m_ntohl(hdr.bfOffBits);
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (GetNumColors()==0 && AlphaIsValid()){
|
||||||
|
|
||||||
|
BITMAPINFOHEADER infohdr;
|
||||||
|
memcpy(&infohdr,&head,sizeof(BITMAPINFOHEADER));
|
||||||
|
infohdr.biCompression = BI_RGB;
|
||||||
|
infohdr.biBitCount = 32;
|
||||||
|
uint32_t dwEffWidth = ((((infohdr.biBitCount * infohdr.biWidth) + 31) / 32) * 4);
|
||||||
|
infohdr.biSizeImage = dwEffWidth * infohdr.biHeight;
|
||||||
|
|
||||||
|
hdr.bfSize = infohdr.biSize + infohdr.biSizeImage + 14 /*sizeof(BITMAPFILEHEADER)*/;
|
||||||
|
|
||||||
|
hdr.bfSize = m_ntohl(hdr.bfSize);
|
||||||
|
bihtoh(&infohdr);
|
||||||
|
|
||||||
|
// Write the file header
|
||||||
|
hFile->Write(&hdr,min(14,sizeof(BITMAPFILEHEADER)),1);
|
||||||
|
hFile->Write(&infohdr,sizeof(BITMAPINFOHEADER),1);
|
||||||
|
//and DIB+ALPHA interlaced
|
||||||
|
uint8_t *srcalpha = AlphaGetPointer();
|
||||||
|
for(int32_t y = 0; y < infohdr.biHeight; ++y){
|
||||||
|
uint8_t *srcdib = GetBits(y);
|
||||||
|
for(int32_t x = 0; x < infohdr.biWidth; ++x){
|
||||||
|
hFile->Write(srcdib,3,1);
|
||||||
|
hFile->Write(srcalpha,1,1);
|
||||||
|
srcdib += 3;
|
||||||
|
++srcalpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
{
|
||||||
|
// Write the file header
|
||||||
|
hFile->Write(&hdr,min(14,sizeof(BITMAPFILEHEADER)),1);
|
||||||
|
//copy attributes
|
||||||
|
memcpy(pDib,&head,sizeof(BITMAPINFOHEADER));
|
||||||
|
bihtoh((BITMAPINFOHEADER*)pDib);
|
||||||
|
// Write the DIB header and the pixels
|
||||||
|
hFile->Write(pDib,GetSize(),1);
|
||||||
|
bihtoh((BITMAPINFOHEADER*)pDib);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageBMP::Decode(CxFile * hFile)
|
||||||
|
{
|
||||||
|
if (hFile == NULL) return false;
|
||||||
|
|
||||||
|
BITMAPFILEHEADER bf;
|
||||||
|
uint32_t off = hFile->Tell(); //<CSC>
|
||||||
|
cx_try {
|
||||||
|
if (hFile->Read(&bf,min(14,sizeof(bf)),1)==0) cx_throw("Not a BMP");
|
||||||
|
|
||||||
|
bf.bfSize = m_ntohl(bf.bfSize);
|
||||||
|
bf.bfOffBits = m_ntohl(bf.bfOffBits);
|
||||||
|
|
||||||
|
if (m_ntohs(bf.bfType) != BFT_BITMAP) { //do we have a RC HEADER?
|
||||||
|
bf.bfOffBits = 0L;
|
||||||
|
hFile->Seek(off,SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
BITMAPINFOHEADER bmpHeader;
|
||||||
|
if (!DibReadBitmapInfo(hFile,&bmpHeader)) cx_throw("Error reading BMP info");
|
||||||
|
uint32_t dwCompression=bmpHeader.biCompression;
|
||||||
|
uint32_t dwBitCount=bmpHeader.biBitCount; //preserve for BI_BITFIELDS compression <Thomas Ernst>
|
||||||
|
bool bIsOldBmp = bmpHeader.biSize == sizeof(BITMAPCOREHEADER);
|
||||||
|
|
||||||
|
bool bTopDownDib = bmpHeader.biHeight<0; //<Flanders> check if it's a top-down bitmap
|
||||||
|
if (bTopDownDib) bmpHeader.biHeight=-bmpHeader.biHeight;
|
||||||
|
|
||||||
|
if (info.nEscape == -1) {
|
||||||
|
// Return output dimensions only
|
||||||
|
head.biWidth = bmpHeader.biWidth;
|
||||||
|
head.biHeight = bmpHeader.biHeight;
|
||||||
|
info.dwType = CXIMAGE_FORMAT_BMP;
|
||||||
|
cx_throw("output dimensions returned");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Create(bmpHeader.biWidth,bmpHeader.biHeight,bmpHeader.biBitCount,CXIMAGE_FORMAT_BMP))
|
||||||
|
cx_throw("");
|
||||||
|
|
||||||
|
SetXDPI((int32_t) floor(bmpHeader.biXPelsPerMeter * 254.0 / 10000.0 + 0.5));
|
||||||
|
SetYDPI((int32_t) floor(bmpHeader.biYPelsPerMeter * 254.0 / 10000.0 + 0.5));
|
||||||
|
|
||||||
|
if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding
|
||||||
|
|
||||||
|
RGBQUAD *pRgb = GetPalette();
|
||||||
|
if (pRgb){
|
||||||
|
if (bIsOldBmp){
|
||||||
|
// convert a old color table (3 byte entries) to a new
|
||||||
|
// color table (4 byte entries)
|
||||||
|
hFile->Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBTRIPLE),1);
|
||||||
|
for (int32_t i=DibNumColors(&head)-1; i>=0; i--){
|
||||||
|
pRgb[i].rgbRed = ((RGBTRIPLE *)pRgb)[i].rgbtRed;
|
||||||
|
pRgb[i].rgbBlue = ((RGBTRIPLE *)pRgb)[i].rgbtBlue;
|
||||||
|
pRgb[i].rgbGreen = ((RGBTRIPLE *)pRgb)[i].rgbtGreen;
|
||||||
|
pRgb[i].rgbReserved = (uint8_t)0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hFile->Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBQUAD),1);
|
||||||
|
//force rgbReserved=0, to avoid problems with some WinXp bitmaps
|
||||||
|
for (uint32_t i=0; i<head.biClrUsed; i++) pRgb[i].rgbReserved=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding
|
||||||
|
|
||||||
|
switch (dwBitCount) {
|
||||||
|
case 32 :
|
||||||
|
uint32_t bfmask[3];
|
||||||
|
if (dwCompression == BI_BITFIELDS)
|
||||||
|
{
|
||||||
|
hFile->Read(bfmask, 12, 1);
|
||||||
|
} else {
|
||||||
|
bfmask[0]=0x00FF0000;
|
||||||
|
bfmask[1]=0x0000FF00;
|
||||||
|
bfmask[2]=0x000000FF;
|
||||||
|
}
|
||||||
|
if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);
|
||||||
|
if (dwCompression == BI_BITFIELDS || dwCompression == BI_RGB){
|
||||||
|
int32_t imagesize=4*head.biHeight*head.biWidth;
|
||||||
|
uint8_t* buff32=(uint8_t*)malloc(imagesize);
|
||||||
|
if (buff32){
|
||||||
|
hFile->Read(buff32, imagesize,1); // read in the pixels
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (dwCompression == BI_RGB){
|
||||||
|
AlphaCreate();
|
||||||
|
if (AlphaIsValid()){
|
||||||
|
bool bAlphaOk = false;
|
||||||
|
uint8_t* p;
|
||||||
|
for (int32_t y=0; y<head.biHeight; y++){
|
||||||
|
p = buff32 + 3 + head.biWidth * 4 * y;
|
||||||
|
for (int32_t x=0; x<head.biWidth; x++){
|
||||||
|
if (*p) bAlphaOk = true;
|
||||||
|
AlphaSet(x,y,*p);
|
||||||
|
p+=4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fix if alpha pixels are all zero
|
||||||
|
if (!bAlphaOk) AlphaInvert();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
|
||||||
|
Bitfield2RGB(buff32,bfmask[0],bfmask[1],bfmask[2],32);
|
||||||
|
free(buff32);
|
||||||
|
} else cx_throw("can't allocate memory");
|
||||||
|
} else cx_throw("unknown compression");
|
||||||
|
break;
|
||||||
|
case 24 :
|
||||||
|
if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);
|
||||||
|
if (dwCompression == BI_RGB){
|
||||||
|
hFile->Read(info.pImage, head.biSizeImage,1); // read in the pixels
|
||||||
|
} else cx_throw("unknown compression");
|
||||||
|
break;
|
||||||
|
case 16 :
|
||||||
|
{
|
||||||
|
uint32_t bfmask[3];
|
||||||
|
if (dwCompression == BI_BITFIELDS)
|
||||||
|
{
|
||||||
|
hFile->Read(bfmask, 12, 1);
|
||||||
|
} else {
|
||||||
|
bfmask[0]=0x7C00; bfmask[1]=0x3E0; bfmask[2]=0x1F; //RGB555
|
||||||
|
}
|
||||||
|
// bf.bfOffBits required after the bitfield mask <Cui Ying Jie>
|
||||||
|
if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);
|
||||||
|
// read in the pixels
|
||||||
|
hFile->Read(info.pImage, head.biHeight*((head.biWidth+1)/2)*4,1);
|
||||||
|
// transform into RGB
|
||||||
|
Bitfield2RGB(info.pImage,bfmask[0],bfmask[1],bfmask[2],16);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 8 :
|
||||||
|
case 4 :
|
||||||
|
case 1 :
|
||||||
|
if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);
|
||||||
|
switch (dwCompression) {
|
||||||
|
case BI_RGB :
|
||||||
|
hFile->Read(info.pImage, head.biSizeImage,1); // read in the pixels
|
||||||
|
break;
|
||||||
|
case BI_RLE4 :
|
||||||
|
{
|
||||||
|
uint8_t status_byte = 0;
|
||||||
|
uint8_t second_byte = 0;
|
||||||
|
int32_t scanline = 0;
|
||||||
|
int32_t bits = 0;
|
||||||
|
BOOL low_nibble = FALSE;
|
||||||
|
CImageIterator iter(this);
|
||||||
|
|
||||||
|
for (BOOL bContinue = TRUE; bContinue && hFile->Read(&status_byte, sizeof(uint8_t), 1);) {
|
||||||
|
|
||||||
|
switch (status_byte) {
|
||||||
|
case RLE_COMMAND :
|
||||||
|
hFile->Read(&status_byte, sizeof(uint8_t), 1);
|
||||||
|
switch (status_byte) {
|
||||||
|
case RLE_ENDOFLINE :
|
||||||
|
bits = 0;
|
||||||
|
scanline++;
|
||||||
|
low_nibble = FALSE;
|
||||||
|
break;
|
||||||
|
case RLE_ENDOFBITMAP :
|
||||||
|
bContinue=FALSE;
|
||||||
|
break;
|
||||||
|
case RLE_DELTA :
|
||||||
|
{
|
||||||
|
// read the delta values
|
||||||
|
uint8_t delta_x;
|
||||||
|
uint8_t delta_y;
|
||||||
|
hFile->Read(&delta_x, sizeof(uint8_t), 1);
|
||||||
|
hFile->Read(&delta_y, sizeof(uint8_t), 1);
|
||||||
|
// apply them
|
||||||
|
bits += delta_x / 2;
|
||||||
|
scanline += delta_y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default :
|
||||||
|
hFile->Read(&second_byte, sizeof(uint8_t), 1);
|
||||||
|
uint8_t *sline = iter.GetRow(scanline);
|
||||||
|
for (int32_t i = 0; i < status_byte; i++) {
|
||||||
|
if ((uint8_t*)(sline+bits) < (uint8_t*)(info.pImage+head.biSizeImage)){
|
||||||
|
if (low_nibble) {
|
||||||
|
if (i&1)
|
||||||
|
*(sline + bits) |= (second_byte & 0x0f);
|
||||||
|
else
|
||||||
|
*(sline + bits) |= (second_byte & 0xf0)>>4;
|
||||||
|
bits++;
|
||||||
|
} else {
|
||||||
|
if (i&1)
|
||||||
|
*(sline + bits) = (uint8_t)(second_byte & 0x0f)<<4;
|
||||||
|
else
|
||||||
|
*(sline + bits) = (uint8_t)(second_byte & 0xf0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((i & 1) && (i != (status_byte - 1)))
|
||||||
|
hFile->Read(&second_byte, sizeof(uint8_t), 1);
|
||||||
|
|
||||||
|
low_nibble = !low_nibble;
|
||||||
|
}
|
||||||
|
if ((((status_byte+1) >> 1) & 1 ) == 1)
|
||||||
|
hFile->Read(&second_byte, sizeof(uint8_t), 1);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
{
|
||||||
|
uint8_t *sline = iter.GetRow(scanline);
|
||||||
|
hFile->Read(&second_byte, sizeof(uint8_t), 1);
|
||||||
|
for (unsigned i = 0; i < status_byte; i++) {
|
||||||
|
if ((uint8_t*)(sline+bits) < (uint8_t*)(info.pImage+head.biSizeImage)){
|
||||||
|
if (low_nibble) {
|
||||||
|
if (i&1)
|
||||||
|
*(sline + bits) |= (second_byte & 0x0f);
|
||||||
|
else
|
||||||
|
*(sline + bits) |= (second_byte & 0xf0)>>4;
|
||||||
|
bits++;
|
||||||
|
} else {
|
||||||
|
if (i&1)
|
||||||
|
*(sline + bits) = (uint8_t)(second_byte & 0x0f)<<4;
|
||||||
|
else
|
||||||
|
*(sline + bits) = (uint8_t)(second_byte & 0xf0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
low_nibble = !low_nibble;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BI_RLE8 :
|
||||||
|
{
|
||||||
|
uint8_t status_byte = 0;
|
||||||
|
uint8_t second_byte = 0;
|
||||||
|
int32_t scanline = 0;
|
||||||
|
int32_t bits = 0;
|
||||||
|
CImageIterator iter(this);
|
||||||
|
|
||||||
|
for (BOOL bContinue = TRUE; bContinue && hFile->Read(&status_byte, sizeof(uint8_t), 1);) {
|
||||||
|
switch (status_byte) {
|
||||||
|
case RLE_COMMAND :
|
||||||
|
hFile->Read(&status_byte, sizeof(uint8_t), 1);
|
||||||
|
switch (status_byte) {
|
||||||
|
case RLE_ENDOFLINE :
|
||||||
|
bits = 0;
|
||||||
|
scanline++;
|
||||||
|
break;
|
||||||
|
case RLE_ENDOFBITMAP :
|
||||||
|
bContinue=FALSE;
|
||||||
|
break;
|
||||||
|
case RLE_DELTA :
|
||||||
|
{
|
||||||
|
// read the delta values
|
||||||
|
uint8_t delta_x;
|
||||||
|
uint8_t delta_y;
|
||||||
|
hFile->Read(&delta_x, sizeof(uint8_t), 1);
|
||||||
|
hFile->Read(&delta_y, sizeof(uint8_t), 1);
|
||||||
|
// apply them
|
||||||
|
bits += delta_x;
|
||||||
|
scanline += delta_y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default :
|
||||||
|
hFile->Read((void *)(iter.GetRow(scanline) + bits), sizeof(uint8_t) * status_byte, 1);
|
||||||
|
// align run length to even number of bytes
|
||||||
|
if ((status_byte & 1) == 1)
|
||||||
|
hFile->Read(&second_byte, sizeof(uint8_t), 1);
|
||||||
|
bits += status_byte;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
uint8_t *sline = iter.GetRow(scanline);
|
||||||
|
hFile->Read(&second_byte, sizeof(uint8_t), 1);
|
||||||
|
for (unsigned i = 0; i < status_byte; i++) {
|
||||||
|
if ((uint8_t*)(sline+bits) < (uint8_t*)(info.pImage+head.biSizeImage)){
|
||||||
|
*(sline + bits) = second_byte;
|
||||||
|
bits++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default :
|
||||||
|
cx_throw("compression type not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bTopDownDib) Flip(); //<Flanders>
|
||||||
|
|
||||||
|
} cx_catch {
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_BMP) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/* ReadDibBitmapInfo()
|
||||||
|
*
|
||||||
|
* Will read a file in DIB format and return a global HANDLE to its
|
||||||
|
* BITMAPINFO. This function will work with both "old" and "new"
|
||||||
|
* bitmap formats, but will always return a "new" BITMAPINFO.
|
||||||
|
*/
|
||||||
|
bool CxImageBMP::DibReadBitmapInfo(CxFile* fh, BITMAPINFOHEADER *pdib)
|
||||||
|
{
|
||||||
|
if ((fh==NULL)||(pdib==NULL)) return false;
|
||||||
|
|
||||||
|
if (fh->Read(pdib,sizeof(BITMAPINFOHEADER),1)==0) return false;
|
||||||
|
|
||||||
|
bihtoh(pdib);
|
||||||
|
|
||||||
|
switch (pdib->biSize) // what type of bitmap info is this?
|
||||||
|
{
|
||||||
|
case sizeof(BITMAPINFOHEADER):
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 64: //sizeof(OS2_BMP_HEADER):
|
||||||
|
fh->Seek((int32_t)(64 - sizeof(BITMAPINFOHEADER)),SEEK_CUR);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 124: //sizeof(BITMAPV5HEADER):
|
||||||
|
fh->Seek((long)(124-sizeof(BITMAPINFOHEADER)), SEEK_CUR);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sizeof(BITMAPCOREHEADER):
|
||||||
|
{
|
||||||
|
BITMAPCOREHEADER bc = *(BITMAPCOREHEADER*)pdib;
|
||||||
|
pdib->biSize = bc.bcSize;
|
||||||
|
pdib->biWidth = (uint32_t)bc.bcWidth;
|
||||||
|
pdib->biHeight = (uint32_t)bc.bcHeight;
|
||||||
|
pdib->biPlanes = bc.bcPlanes;
|
||||||
|
pdib->biBitCount = bc.bcBitCount;
|
||||||
|
pdib->biCompression = BI_RGB;
|
||||||
|
pdib->biSizeImage = 0;
|
||||||
|
pdib->biXPelsPerMeter = 0;
|
||||||
|
pdib->biYPelsPerMeter = 0;
|
||||||
|
pdib->biClrUsed = 0;
|
||||||
|
pdib->biClrImportant = 0;
|
||||||
|
|
||||||
|
fh->Seek((int32_t)(sizeof(BITMAPCOREHEADER)-sizeof(BITMAPINFOHEADER)), SEEK_CUR);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//give a last chance
|
||||||
|
if (pdib->biSize>(sizeof(BITMAPINFOHEADER))&&
|
||||||
|
(pdib->biSizeImage>=(uint32_t)(pdib->biHeight*((((pdib->biBitCount*pdib->biWidth)+31)/32)*4)))&&
|
||||||
|
(pdib->biPlanes==1)&&(pdib->biClrUsed==0))
|
||||||
|
{
|
||||||
|
if (pdib->biCompression==BI_RGB)
|
||||||
|
fh->Seek((int32_t)(pdib->biSize - sizeof(BITMAPINFOHEADER)),SEEK_CUR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FixBitmapInfo(pdib);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_BMP
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* File: ximabmp.h
|
||||||
|
* Purpose: BMP Image Class Loader and Writer
|
||||||
|
*/
|
||||||
|
/* ==========================================================
|
||||||
|
* CxImageBMP (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it
|
||||||
|
* For conditions of distribution and use, see copyright notice in ximage.h
|
||||||
|
*
|
||||||
|
* Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes
|
||||||
|
*
|
||||||
|
* original CImageBMP and CImageIterator implementation are:
|
||||||
|
* Copyright: (c) 1995, Alejandro Aguilar Sierra <asierra(at)servidor(dot)unam(dot)mx>
|
||||||
|
*
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(__ximaBMP_h)
|
||||||
|
#define __ximaBMP_h
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
const int32_t RLE_COMMAND = 0;
|
||||||
|
const int32_t RLE_ENDOFLINE = 0;
|
||||||
|
const int32_t RLE_ENDOFBITMAP = 1;
|
||||||
|
const int32_t RLE_DELTA = 2;
|
||||||
|
|
||||||
|
#if !defined(BI_RLE8)
|
||||||
|
#define BI_RLE8 1L
|
||||||
|
#endif
|
||||||
|
#if !defined(BI_RLE4)
|
||||||
|
#define BI_RLE4 2L
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_BMP
|
||||||
|
|
||||||
|
class CxImageBMP: public CxImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CxImageBMP(): CxImage(CXIMAGE_FORMAT_BMP) {};
|
||||||
|
|
||||||
|
bool Decode(CxFile * hFile);
|
||||||
|
bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
bool Encode(CxFile * hFile);
|
||||||
|
bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool DibReadBitmapInfo(CxFile* fh, BITMAPINFOHEADER *pdib);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BFT_ICON 0x4349 /* 'IC' */
|
||||||
|
#define BFT_BITMAP 0x4d42 /* 'BM' */
|
||||||
|
#define BFT_CURSOR 0x5450 /* 'PT' */
|
||||||
|
|
||||||
|
#ifndef WIDTHBYTES
|
||||||
|
#define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DibWidthBytesN(lpbi, n) (uint32_t)WIDTHBYTES((uint32_t)(lpbi)->biWidth * (uint32_t)(n))
|
||||||
|
#define DibWidthBytes(lpbi) DibWidthBytesN(lpbi, (lpbi)->biBitCount)
|
||||||
|
|
||||||
|
#define DibSizeImage(lpbi) ((lpbi)->biSizeImage == 0 \
|
||||||
|
? ((uint32_t)(uint32_t)DibWidthBytes(lpbi) * (uint32_t)(uint32_t)(lpbi)->biHeight) \
|
||||||
|
: (lpbi)->biSizeImage)
|
||||||
|
|
||||||
|
#define DibNumColors(lpbi) ((lpbi)->biClrUsed == 0 && (lpbi)->biBitCount <= 8 \
|
||||||
|
? (int32_t)(1 << (int32_t)(lpbi)->biBitCount) \
|
||||||
|
: (int32_t)(lpbi)->biClrUsed)
|
||||||
|
|
||||||
|
#define FixBitmapInfo(lpbi) if ((lpbi)->biSizeImage == 0) \
|
||||||
|
(lpbi)->biSizeImage = DibSizeImage(lpbi); \
|
||||||
|
if ((lpbi)->biClrUsed == 0) \
|
||||||
|
(lpbi)->biClrUsed = DibNumColors(lpbi); \
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#if !defined(__ximaCFG_h)
|
||||||
|
#define __ximaCFG_h
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CxImage supported features
|
||||||
|
#define CXIMAGE_SUPPORT_ALPHA 1
|
||||||
|
#define CXIMAGE_SUPPORT_SELECTION 1
|
||||||
|
#define CXIMAGE_SUPPORT_TRANSFORMATION 1
|
||||||
|
#define CXIMAGE_SUPPORT_DSP 1
|
||||||
|
#define CXIMAGE_SUPPORT_LAYERS 1
|
||||||
|
#define CXIMAGE_SUPPORT_INTERPOLATION 1
|
||||||
|
|
||||||
|
#define CXIMAGE_SUPPORT_DECODE 1
|
||||||
|
#define CXIMAGE_SUPPORT_ENCODE 1 //<vho><T.Peck>
|
||||||
|
#define CXIMAGE_SUPPORT_WINDOWS 1
|
||||||
|
#define CXIMAGE_SUPPORT_EXIF 1
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CxImage supported formats
|
||||||
|
#define CXIMAGE_SUPPORT_BMP 1
|
||||||
|
#define CXIMAGE_SUPPORT_GIF 1
|
||||||
|
#define CXIMAGE_SUPPORT_JPG 1
|
||||||
|
#define CXIMAGE_SUPPORT_PNG 1
|
||||||
|
#define CXIMAGE_SUPPORT_ICO 1
|
||||||
|
#define CXIMAGE_SUPPORT_TIF 1
|
||||||
|
#define CXIMAGE_SUPPORT_TGA 1
|
||||||
|
#define CXIMAGE_SUPPORT_PCX 1
|
||||||
|
#define CXIMAGE_SUPPORT_WBMP 1
|
||||||
|
#define CXIMAGE_SUPPORT_WMF 1
|
||||||
|
|
||||||
|
#define CXIMAGE_SUPPORT_JP2 1
|
||||||
|
#define CXIMAGE_SUPPORT_JPC 1
|
||||||
|
#define CXIMAGE_SUPPORT_PGX 1
|
||||||
|
#define CXIMAGE_SUPPORT_PNM 1
|
||||||
|
#define CXIMAGE_SUPPORT_RAS 1
|
||||||
|
|
||||||
|
#define CXIMAGE_SUPPORT_JBG 0 // GPL'd see ../jbig/copying.txt & ../jbig/patents.htm
|
||||||
|
|
||||||
|
#define CXIMAGE_SUPPORT_MNG 1
|
||||||
|
#define CXIMAGE_SUPPORT_SKA 1
|
||||||
|
#define CXIMAGE_SUPPORT_RAW 1
|
||||||
|
#define CXIMAGE_SUPPORT_PSD 1
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
#define CXIMAGE_MAX_MEMORY 268435456
|
||||||
|
|
||||||
|
#define CXIMAGE_DEFAULT_DPI 96
|
||||||
|
|
||||||
|
#define CXIMAGE_ERR_NOFILE "null file handler"
|
||||||
|
#define CXIMAGE_ERR_NOIMAGE "null image!!!"
|
||||||
|
|
||||||
|
#define CXIMAGE_SUPPORT_EXCEPTION_HANDLING 1
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//color to grey mapping <H. Muelner> <jurgene>
|
||||||
|
//#define RGB2GRAY(r,g,b) (((b)*114 + (g)*587 + (r)*299)/1000)
|
||||||
|
#define RGB2GRAY(r,g,b) (((b)*117 + (g)*601 + (r)*306) >> 10)
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
#if !defined(__ximadefs_h)
|
||||||
|
#define __ximadefs_h
|
||||||
|
|
||||||
|
#include "ximacfg.h"
|
||||||
|
|
||||||
|
#if /*defined(_AFXDLL)||*/defined(_USRDLL)
|
||||||
|
#define DLL_EXP __declspec(dllexport)
|
||||||
|
#elif defined(_MSC_VER)&&(_MSC_VER<1200)
|
||||||
|
#define DLL_EXP __declspec(dllimport)
|
||||||
|
#else
|
||||||
|
#define DLL_EXP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_EXCEPTION_HANDLING
|
||||||
|
#define cx_try try
|
||||||
|
#define cx_throw(message) throw(message)
|
||||||
|
#define cx_catch catch (const char *message)
|
||||||
|
#else
|
||||||
|
#define cx_try bool cx_error=false;
|
||||||
|
#define cx_throw(message) {cx_error=true; if(strcmp(message,"")) strncpy(info.szLastError,message,255); goto cx_error_catch;}
|
||||||
|
#define cx_catch cx_error_catch: char message[]=""; if(cx_error)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_JP2 || CXIMAGE_SUPPORT_JPC || CXIMAGE_SUPPORT_PGX || CXIMAGE_SUPPORT_PNM || CXIMAGE_SUPPORT_RAS
|
||||||
|
#define CXIMAGE_SUPPORT_JASPER 1
|
||||||
|
#else
|
||||||
|
#define CXIMAGE_SUPPORT_JASPER 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_DSP
|
||||||
|
#undef CXIMAGE_SUPPORT_TRANSFORMATION
|
||||||
|
#define CXIMAGE_SUPPORT_TRANSFORMATION 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_TRANSFORMATION || CXIMAGE_SUPPORT_TIF || CXIMAGE_SUPPORT_TGA || CXIMAGE_SUPPORT_BMP || CXIMAGE_SUPPORT_WINDOWS
|
||||||
|
#define CXIMAGE_SUPPORT_BASICTRANSFORMATIONS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_DSP || CXIMAGE_SUPPORT_TRANSFORMATION
|
||||||
|
#undef CXIMAGE_SUPPORT_INTERPOLATION
|
||||||
|
#define CXIMAGE_SUPPORT_INTERPOLATION 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (CXIMAGE_SUPPORT_DECODE == 0)
|
||||||
|
#undef CXIMAGE_SUPPORT_EXIF
|
||||||
|
#define CXIMAGE_SUPPORT_EXIF 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (_WIN32_WCE)
|
||||||
|
#undef CXIMAGE_SUPPORT_WMF
|
||||||
|
#define CXIMAGE_SUPPORT_WMF 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(WIN32) && !defined(_WIN32_WCE)
|
||||||
|
#undef CXIMAGE_SUPPORT_WINDOWS
|
||||||
|
#define CXIMAGE_SUPPORT_WINDOWS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef min
|
||||||
|
#define min(a,b) (((a)<(b))?(a):(b))
|
||||||
|
#endif
|
||||||
|
#ifndef max
|
||||||
|
#define max(a,b) (((a)>(b))?(a):(b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PI
|
||||||
|
#define PI 3.141592653589793f
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN32_WCE)
|
||||||
|
#include <windows.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#ifdef __BORLANDC__
|
||||||
|
|
||||||
|
#ifndef _COMPLEX_DEFINED
|
||||||
|
|
||||||
|
typedef struct tagcomplex {
|
||||||
|
double x,y;
|
||||||
|
} _complex;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _cabs(c) sqrt(c.x*c.x+c.y*c.y)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN32_WCE)
|
||||||
|
#include "stdint.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(WIN32) && !defined(_WIN32_WCE)
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
typedef uint32_t COLORREF;
|
||||||
|
typedef void* HANDLE;
|
||||||
|
typedef void* HRGN;
|
||||||
|
|
||||||
|
#ifndef BOOL
|
||||||
|
#define BOOL bool
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TRUE
|
||||||
|
#define TRUE true
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FALSE
|
||||||
|
#define FALSE false
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TCHAR
|
||||||
|
#define TCHAR char
|
||||||
|
#define _T
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct tagRECT
|
||||||
|
{
|
||||||
|
int32_t left;
|
||||||
|
int32_t top;
|
||||||
|
int32_t right;
|
||||||
|
int32_t bottom;
|
||||||
|
} RECT;
|
||||||
|
|
||||||
|
typedef struct tagPOINT
|
||||||
|
{
|
||||||
|
int32_t x;
|
||||||
|
int32_t y;
|
||||||
|
} POINT;
|
||||||
|
|
||||||
|
typedef struct tagRGBQUAD {
|
||||||
|
uint8_t rgbBlue;
|
||||||
|
uint8_t rgbGreen;
|
||||||
|
uint8_t rgbRed;
|
||||||
|
uint8_t rgbReserved;
|
||||||
|
} RGBQUAD;
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
|
||||||
|
typedef struct tagBITMAPINFOHEADER{
|
||||||
|
uint32_t biSize;
|
||||||
|
int32_t biWidth;
|
||||||
|
int32_t biHeight;
|
||||||
|
uint16_t biPlanes;
|
||||||
|
uint16_t biBitCount;
|
||||||
|
uint32_t biCompression;
|
||||||
|
uint32_t biSizeImage;
|
||||||
|
int32_t biXPelsPerMeter;
|
||||||
|
int32_t biYPelsPerMeter;
|
||||||
|
uint32_t biClrUsed;
|
||||||
|
uint32_t biClrImportant;
|
||||||
|
} BITMAPINFOHEADER;
|
||||||
|
|
||||||
|
typedef struct tagBITMAPFILEHEADER {
|
||||||
|
uint16_t bfType;
|
||||||
|
uint32_t bfSize;
|
||||||
|
uint16_t bfReserved1;
|
||||||
|
uint16_t bfReserved2;
|
||||||
|
uint32_t bfOffBits;
|
||||||
|
} BITMAPFILEHEADER;
|
||||||
|
|
||||||
|
typedef struct tagBITMAPCOREHEADER {
|
||||||
|
uint32_t bcSize;
|
||||||
|
uint16_t bcWidth;
|
||||||
|
uint16_t bcHeight;
|
||||||
|
uint16_t bcPlanes;
|
||||||
|
uint16_t bcBitCount;
|
||||||
|
} BITMAPCOREHEADER;
|
||||||
|
|
||||||
|
typedef struct tagRGBTRIPLE {
|
||||||
|
uint8_t rgbtBlue;
|
||||||
|
uint8_t rgbtGreen;
|
||||||
|
uint8_t rgbtRed;
|
||||||
|
} RGBTRIPLE;
|
||||||
|
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
#define BI_RGB 0L
|
||||||
|
#define BI_RLE8 1L
|
||||||
|
#define BI_RLE4 2L
|
||||||
|
#define BI_BITFIELDS 3L
|
||||||
|
|
||||||
|
#define GetRValue(rgb) ((uint8_t)(rgb))
|
||||||
|
#define GetGValue(rgb) ((uint8_t)(((uint16_t)(rgb)) >> 8))
|
||||||
|
#define GetBValue(rgb) ((uint8_t)((rgb)>>16))
|
||||||
|
#define RGB(r,g,b) ((COLORREF)(((uint8_t)(r)|((uint16_t)((uint8_t)(g))<<8))|(((uint32_t)(uint8_t)(b))<<16)))
|
||||||
|
|
||||||
|
#ifndef _COMPLEX_DEFINED
|
||||||
|
|
||||||
|
typedef struct tagcomplex {
|
||||||
|
double x,y;
|
||||||
|
} _complex;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _cabs(c) sqrt(c.x*c.x+c.y*c.y)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //__ximadefs
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,877 @@
|
|||||||
|
/*
|
||||||
|
* File: ximaexif.cpp
|
||||||
|
* Purpose: EXIF reader
|
||||||
|
* 18/Aug/2002 Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
* based on jhead-1.8 by Matthias Wandel <mwandel(at)rim(dot)net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximajpg.h"
|
||||||
|
|
||||||
|
#if CXIMAGEJPG_SUPPORT_EXIF
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CxImageJPG::CxExifInfo::CxExifInfo(EXIFINFO* info)
|
||||||
|
{
|
||||||
|
if (info) {
|
||||||
|
m_exifinfo = info;
|
||||||
|
freeinfo = false;
|
||||||
|
} else {
|
||||||
|
m_exifinfo = new EXIFINFO;
|
||||||
|
memset(m_exifinfo,0,sizeof(EXIFINFO));
|
||||||
|
freeinfo = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_szLastError[0]='\0';
|
||||||
|
ExifImageWidth = MotorolaOrder = 0;
|
||||||
|
SectionsRead=0;
|
||||||
|
memset(&Sections, 0, MAX_SECTIONS * sizeof(Section_t));
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CxImageJPG::CxExifInfo::~CxExifInfo()
|
||||||
|
{
|
||||||
|
for(int32_t i=0;i<MAX_SECTIONS;i++) if(Sections[i].Data) free(Sections[i].Data);
|
||||||
|
if (freeinfo) delete m_exifinfo;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageJPG::CxExifInfo::DecodeExif(CxFile * hFile, int32_t nReadMode)
|
||||||
|
{
|
||||||
|
int32_t a;
|
||||||
|
int32_t HaveCom = FALSE;
|
||||||
|
|
||||||
|
a = hFile->GetC();
|
||||||
|
|
||||||
|
if (a != 0xff || hFile->GetC() != M_SOI){
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
int32_t itemlen;
|
||||||
|
int32_t marker = 0;
|
||||||
|
int32_t ll,lh, got;
|
||||||
|
uint8_t * Data;
|
||||||
|
|
||||||
|
if (SectionsRead >= MAX_SECTIONS){
|
||||||
|
strcpy(m_szLastError,"Too many sections in jpg file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (a=0;a<7;a++){
|
||||||
|
marker = hFile->GetC();
|
||||||
|
if (marker != 0xff) break;
|
||||||
|
|
||||||
|
if (a >= 6){
|
||||||
|
printf("too many padding bytes\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (marker == 0xff){
|
||||||
|
// 0xff is legal padding, but if we get that many, something's wrong.
|
||||||
|
strcpy(m_szLastError,"too many padding bytes!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sections[SectionsRead].Type = marker;
|
||||||
|
|
||||||
|
// Read the length of the section.
|
||||||
|
lh = hFile->GetC();
|
||||||
|
ll = hFile->GetC();
|
||||||
|
|
||||||
|
itemlen = (lh << 8) | ll;
|
||||||
|
|
||||||
|
if (itemlen < 2){
|
||||||
|
strcpy(m_szLastError,"invalid marker");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sections[SectionsRead].Size = itemlen;
|
||||||
|
|
||||||
|
Data = (uint8_t *)malloc(itemlen);
|
||||||
|
if (Data == NULL){
|
||||||
|
strcpy(m_szLastError,"Could not allocate memory");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Sections[SectionsRead].Data = Data;
|
||||||
|
|
||||||
|
// Store first two pre-read bytes.
|
||||||
|
Data[0] = (uint8_t)lh;
|
||||||
|
Data[1] = (uint8_t)ll;
|
||||||
|
|
||||||
|
got = hFile->Read(Data+2, 1, itemlen-2); // Read the whole section.
|
||||||
|
if (got != itemlen-2){
|
||||||
|
strcpy(m_szLastError,"Premature end of file?");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SectionsRead += 1;
|
||||||
|
|
||||||
|
switch(marker){
|
||||||
|
|
||||||
|
case M_SOS: // stop before hitting compressed data
|
||||||
|
// If reading entire image is requested, read the rest of the data.
|
||||||
|
if (nReadMode & EXIF_READ_IMAGE){
|
||||||
|
int32_t cp, ep, size;
|
||||||
|
// Determine how much file is left.
|
||||||
|
cp = hFile->Tell();
|
||||||
|
hFile->Seek(0, SEEK_END);
|
||||||
|
ep = hFile->Tell();
|
||||||
|
hFile->Seek(cp, SEEK_SET);
|
||||||
|
|
||||||
|
size = ep-cp;
|
||||||
|
Data = (uint8_t *)malloc(size);
|
||||||
|
if (Data == NULL){
|
||||||
|
strcpy(m_szLastError,"could not allocate data for entire image");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
got = hFile->Read(Data, 1, size);
|
||||||
|
if (got != size){
|
||||||
|
strcpy(m_szLastError,"could not read the rest of the image");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sections[SectionsRead].Data = Data;
|
||||||
|
Sections[SectionsRead].Size = size;
|
||||||
|
Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER;
|
||||||
|
SectionsRead ++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case M_EOI: // in case it's a tables-only JPEG stream
|
||||||
|
printf("No image in jpeg!\n");
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
case M_COM: // Comment section
|
||||||
|
if (HaveCom || ((nReadMode & EXIF_READ_EXIF) == 0)){
|
||||||
|
// Discard this section.
|
||||||
|
free(Sections[--SectionsRead].Data);
|
||||||
|
Sections[SectionsRead].Data=0;
|
||||||
|
}else{
|
||||||
|
process_COM(Data, itemlen);
|
||||||
|
HaveCom = TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case M_JFIF:
|
||||||
|
// Regular jpegs always have this tag, exif images have the exif
|
||||||
|
// marker instead, althogh ACDsee will write images with both markers.
|
||||||
|
// this program will re-create this marker on absence of exif marker.
|
||||||
|
// hence no need to keep the copy from the file.
|
||||||
|
free(Sections[--SectionsRead].Data);
|
||||||
|
Sections[SectionsRead].Data=0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case M_EXIF:
|
||||||
|
// Seen files from some 'U-lead' software with Vivitar scanner
|
||||||
|
// that uses marker 31 for non exif stuff. Thus make sure
|
||||||
|
// it says 'Exif' in the section before treating it as exif.
|
||||||
|
if ((nReadMode & EXIF_READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){
|
||||||
|
m_exifinfo->IsExif = process_EXIF((uint8_t *)Data+2, itemlen);
|
||||||
|
}else{
|
||||||
|
// Discard this section.
|
||||||
|
free(Sections[--SectionsRead].Data);
|
||||||
|
Sections[SectionsRead].Data=0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case M_SOF0:
|
||||||
|
case M_SOF1:
|
||||||
|
case M_SOF2:
|
||||||
|
case M_SOF3:
|
||||||
|
case M_SOF5:
|
||||||
|
case M_SOF6:
|
||||||
|
case M_SOF7:
|
||||||
|
case M_SOF9:
|
||||||
|
case M_SOF10:
|
||||||
|
case M_SOF11:
|
||||||
|
case M_SOF13:
|
||||||
|
case M_SOF14:
|
||||||
|
case M_SOF15:
|
||||||
|
process_SOFn(Data, marker);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Skip any other sections.
|
||||||
|
//if (ShowTags) printf("Jpeg section marker 0x%02x size %d\n",marker, itemlen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
Process a EXIF marker
|
||||||
|
Describes all the drivel that most digital cameras include...
|
||||||
|
--------------------------------------------------------------------------*/
|
||||||
|
bool CxImageJPG::CxExifInfo::process_EXIF(uint8_t * CharBuf, uint32_t length)
|
||||||
|
{
|
||||||
|
m_exifinfo->FlashUsed = 0;
|
||||||
|
/* If it's from a digicam, and it used flash, it says so. */
|
||||||
|
m_exifinfo->Comments[0] = '\0'; /* Initial value - null string */
|
||||||
|
|
||||||
|
ExifImageWidth = 0;
|
||||||
|
|
||||||
|
{ /* Check the EXIF header component */
|
||||||
|
static const uint8_t ExifHeader[] = "Exif\0\0";
|
||||||
|
if (memcmp(CharBuf+0, ExifHeader,6)){
|
||||||
|
strcpy(m_szLastError,"Incorrect Exif header");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(CharBuf+6,"II",2) == 0){
|
||||||
|
MotorolaOrder = 0;
|
||||||
|
}else{
|
||||||
|
if (memcmp(CharBuf+6,"MM",2) == 0){
|
||||||
|
MotorolaOrder = 1;
|
||||||
|
}else{
|
||||||
|
strcpy(m_szLastError,"Invalid Exif alignment marker.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the next two values for correctness. */
|
||||||
|
if (Get16u(CharBuf+8) != 0x2a){
|
||||||
|
strcpy(m_szLastError,"Invalid Exif start (1)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t FirstOffset = Get32u(CharBuf+10);
|
||||||
|
/* <Richard Collins>
|
||||||
|
if (FirstOffset < 8 || FirstOffset > 16){
|
||||||
|
// I used to ensure this was set to 8 (website I used indicated its 8)
|
||||||
|
// but PENTAX Optio 230 has it set differently, and uses it as offset. (Sept 11 2002)
|
||||||
|
strcpy(m_szLastError,"Suspicious offset of first IFD value");
|
||||||
|
return false;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
uint8_t * LastExifRefd = CharBuf;
|
||||||
|
|
||||||
|
/* First directory starts 16 bytes in. Offsets start at 8 bytes in. */
|
||||||
|
if (!ProcessExifDir(CharBuf+14, CharBuf+6, length-6, m_exifinfo, &LastExifRefd))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* <Richard Collins> give a chance for a second directory */
|
||||||
|
if (FirstOffset > 8) {
|
||||||
|
if (!ProcessExifDir(CharBuf+14+FirstOffset-8, CharBuf+6, length-6, m_exifinfo, &LastExifRefd))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is how far the interesting (non thumbnail) part of the exif went. */
|
||||||
|
// int32_t ExifSettingsLength = LastExifRefd - CharBuf;
|
||||||
|
|
||||||
|
/* Compute the CCD width, in milimeters. */
|
||||||
|
if (m_exifinfo->FocalplaneXRes != 0){
|
||||||
|
m_exifinfo->CCDWidth = (float)(ExifImageWidth * m_exifinfo->FocalplaneUnits / m_exifinfo->FocalplaneXRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Get 16 bits motorola order (always) for jpeg header stuff.
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
int32_t CxImageJPG::CxExifInfo::Get16m(void * Short)
|
||||||
|
{
|
||||||
|
return (((uint8_t *)Short)[0] << 8) | ((uint8_t *)Short)[1];
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
Convert a 16 bit unsigned value from file's native byte order
|
||||||
|
--------------------------------------------------------------------------*/
|
||||||
|
int32_t CxImageJPG::CxExifInfo::Get16u(void * Short)
|
||||||
|
{
|
||||||
|
if (MotorolaOrder){
|
||||||
|
return (((uint8_t *)Short)[0] << 8) | ((uint8_t *)Short)[1];
|
||||||
|
}else{
|
||||||
|
return (((uint8_t *)Short)[1] << 8) | ((uint8_t *)Short)[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
Convert a 32 bit signed value from file's native byte order
|
||||||
|
--------------------------------------------------------------------------*/
|
||||||
|
int32_t CxImageJPG::CxExifInfo::Get32s(void * Long)
|
||||||
|
{
|
||||||
|
if (MotorolaOrder){
|
||||||
|
return ((( char *)Long)[0] << 24) | (((uint8_t *)Long)[1] << 16)
|
||||||
|
| (((uint8_t *)Long)[2] << 8 ) | (((uint8_t *)Long)[3] << 0 );
|
||||||
|
}else{
|
||||||
|
return ((( char *)Long)[3] << 24) | (((uint8_t *)Long)[2] << 16)
|
||||||
|
| (((uint8_t *)Long)[1] << 8 ) | (((uint8_t *)Long)[0] << 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
Convert a 32 bit unsigned value from file's native byte order
|
||||||
|
--------------------------------------------------------------------------*/
|
||||||
|
uint32_t CxImageJPG::CxExifInfo::Get32u(void * Long)
|
||||||
|
{
|
||||||
|
return (uint32_t)Get32s(Long) & 0xffffffff;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/* Describes format descriptor */
|
||||||
|
static const int32_t BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
|
||||||
|
#define NUM_FORMATS 12
|
||||||
|
|
||||||
|
#define FMT_BYTE 1
|
||||||
|
#define FMT_STRING 2
|
||||||
|
#define FMT_USHORT 3
|
||||||
|
#define FMT_ULONG 4
|
||||||
|
#define FMT_URATIONAL 5
|
||||||
|
#define FMT_SBYTE 6
|
||||||
|
#define FMT_UNDEFINED 7
|
||||||
|
#define FMT_SSHORT 8
|
||||||
|
#define FMT_SLONG 9
|
||||||
|
#define FMT_SRATIONAL 10
|
||||||
|
#define FMT_SINGLE 11
|
||||||
|
#define FMT_DOUBLE 12
|
||||||
|
|
||||||
|
/* Describes tag values */
|
||||||
|
|
||||||
|
#define TAG_EXIF_VERSION 0x9000
|
||||||
|
#define TAG_EXIF_OFFSET 0x8769
|
||||||
|
#define TAG_INTEROP_OFFSET 0xa005
|
||||||
|
|
||||||
|
#define TAG_MAKE 0x010F
|
||||||
|
#define TAG_MODEL 0x0110
|
||||||
|
|
||||||
|
#define TAG_ORIENTATION 0x0112
|
||||||
|
#define TAG_XRESOLUTION 0x011A
|
||||||
|
#define TAG_YRESOLUTION 0x011B
|
||||||
|
#define TAG_RESOLUTIONUNIT 0x0128
|
||||||
|
|
||||||
|
#define TAG_EXPOSURETIME 0x829A
|
||||||
|
#define TAG_FNUMBER 0x829D
|
||||||
|
|
||||||
|
#define TAG_SHUTTERSPEED 0x9201
|
||||||
|
#define TAG_APERTURE 0x9202
|
||||||
|
#define TAG_BRIGHTNESS 0x9203
|
||||||
|
#define TAG_MAXAPERTURE 0x9205
|
||||||
|
#define TAG_FOCALLENGTH 0x920A
|
||||||
|
|
||||||
|
#define TAG_DATETIME_ORIGINAL 0x9003
|
||||||
|
#define TAG_USERCOMMENT 0x9286
|
||||||
|
|
||||||
|
#define TAG_SUBJECT_DISTANCE 0x9206
|
||||||
|
#define TAG_FLASH 0x9209
|
||||||
|
|
||||||
|
#define TAG_FOCALPLANEXRES 0xa20E
|
||||||
|
#define TAG_FOCALPLANEYRES 0xa20F
|
||||||
|
#define TAG_FOCALPLANEUNITS 0xa210
|
||||||
|
#define TAG_EXIF_IMAGEWIDTH 0xA002
|
||||||
|
#define TAG_EXIF_IMAGELENGTH 0xA003
|
||||||
|
|
||||||
|
/* the following is added 05-jan-2001 vcs */
|
||||||
|
#define TAG_EXPOSURE_BIAS 0x9204
|
||||||
|
#define TAG_WHITEBALANCE 0x9208
|
||||||
|
#define TAG_METERING_MODE 0x9207
|
||||||
|
#define TAG_EXPOSURE_PROGRAM 0x8822
|
||||||
|
#define TAG_ISO_EQUIVALENT 0x8827
|
||||||
|
#define TAG_COMPRESSION_LEVEL 0x9102
|
||||||
|
|
||||||
|
#define TAG_THUMBNAIL_OFFSET 0x0201
|
||||||
|
#define TAG_THUMBNAIL_LENGTH 0x0202
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
Process one of the nested EXIF directories.
|
||||||
|
--------------------------------------------------------------------------*/
|
||||||
|
bool CxImageJPG::CxExifInfo::ProcessExifDir(uint8_t * DirStart, uint8_t * OffsetBase, unsigned ExifLength,
|
||||||
|
EXIFINFO * const m_exifinfo, uint8_t ** const LastExifRefdP, int32_t NestingLevel)
|
||||||
|
{
|
||||||
|
int32_t de;
|
||||||
|
int32_t a;
|
||||||
|
int32_t NumDirEntries;
|
||||||
|
unsigned ThumbnailOffset = 0;
|
||||||
|
unsigned ThumbnailSize = 0;
|
||||||
|
|
||||||
|
if (NestingLevel > 4){
|
||||||
|
strcpy(m_szLastError,"Maximum directory nesting exceeded (corrupt exif header)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NumDirEntries = Get16u(DirStart);
|
||||||
|
|
||||||
|
if ((DirStart+2+NumDirEntries*12) > (OffsetBase+ExifLength)){
|
||||||
|
strcpy(m_szLastError,"Illegally sized directory");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (de=0;de<NumDirEntries;de++){
|
||||||
|
int32_t Tag, Format, Components;
|
||||||
|
uint8_t * ValuePtr;
|
||||||
|
/* This actually can point to a variety of things; it must be
|
||||||
|
cast to other types when used. But we use it as a byte-by-byte
|
||||||
|
cursor, so we declare it as a pointer to a generic byte here.
|
||||||
|
*/
|
||||||
|
int32_t ByteCount;
|
||||||
|
uint8_t * DirEntry;
|
||||||
|
DirEntry = DirStart+2+12*de;
|
||||||
|
|
||||||
|
Tag = Get16u(DirEntry);
|
||||||
|
Format = Get16u(DirEntry+2);
|
||||||
|
Components = Get32u(DirEntry+4);
|
||||||
|
|
||||||
|
if ((Format-1) >= NUM_FORMATS) {
|
||||||
|
/* (-1) catches illegal zero case as unsigned underflows to positive large */
|
||||||
|
strcpy(m_szLastError,"Illegal format code in EXIF dir");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteCount = Components * BytesPerFormat[Format];
|
||||||
|
|
||||||
|
if (ByteCount > 4){
|
||||||
|
unsigned OffsetVal;
|
||||||
|
OffsetVal = Get32u(DirEntry+8);
|
||||||
|
/* If its bigger than 4 bytes, the dir entry contains an offset.*/
|
||||||
|
if (OffsetVal+ByteCount > ExifLength){
|
||||||
|
/* Bogus pointer offset and / or bytecount value */
|
||||||
|
strcpy(m_szLastError,"Illegal pointer offset value in EXIF.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ValuePtr = OffsetBase+OffsetVal;
|
||||||
|
}else{
|
||||||
|
/* 4 bytes or less and value is in the dir entry itself */
|
||||||
|
ValuePtr = DirEntry+8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*LastExifRefdP < ValuePtr+ByteCount){
|
||||||
|
/* Keep track of last byte in the exif header that was
|
||||||
|
actually referenced. That way, we know where the
|
||||||
|
discardable thumbnail data begins.
|
||||||
|
*/
|
||||||
|
*LastExifRefdP = ValuePtr+ByteCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract useful components of tag */
|
||||||
|
switch(Tag){
|
||||||
|
|
||||||
|
case TAG_MAKE:
|
||||||
|
strncpy(m_exifinfo->CameraMake, (char*)ValuePtr, 31);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_MODEL:
|
||||||
|
strncpy(m_exifinfo->CameraModel, (char*)ValuePtr, 39);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_EXIF_VERSION:
|
||||||
|
strncpy(m_exifinfo->Version,(char*)ValuePtr, 4);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_DATETIME_ORIGINAL:
|
||||||
|
strncpy(m_exifinfo->DateTime, (char*)ValuePtr, 19);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_USERCOMMENT:
|
||||||
|
// Olympus has this padded with trailing spaces. Remove these first.
|
||||||
|
for (a=ByteCount;;){
|
||||||
|
a--;
|
||||||
|
if (((char*)ValuePtr)[a] == ' '){
|
||||||
|
((char*)ValuePtr)[a] = '\0';
|
||||||
|
}else{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (a == 0) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the comment */
|
||||||
|
if (memcmp(ValuePtr, "ASCII",5) == 0){
|
||||||
|
for (a=5;a<10;a++){
|
||||||
|
char c;
|
||||||
|
c = ((char*)ValuePtr)[a];
|
||||||
|
if (c != '\0' && c != ' '){
|
||||||
|
strncpy(m_exifinfo->Comments, (char*)ValuePtr+a, 199);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}else{
|
||||||
|
strncpy(m_exifinfo->Comments, (char*)ValuePtr, 199);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_FNUMBER:
|
||||||
|
/* Simplest way of expressing aperture, so I trust it the most.
|
||||||
|
(overwrite previously computd value if there is one)
|
||||||
|
*/
|
||||||
|
m_exifinfo->ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_APERTURE:
|
||||||
|
case TAG_MAXAPERTURE:
|
||||||
|
/* More relevant info always comes earlier, so only
|
||||||
|
use this field if we don't have appropriate aperture
|
||||||
|
information yet.
|
||||||
|
*/
|
||||||
|
if (m_exifinfo->ApertureFNumber == 0){
|
||||||
|
m_exifinfo->ApertureFNumber = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0f)*0.5);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_BRIGHTNESS:
|
||||||
|
m_exifinfo->Brightness = (float)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_FOCALLENGTH:
|
||||||
|
/* Nice digital cameras actually save the focal length
|
||||||
|
as a function of how farthey are zoomed in.
|
||||||
|
*/
|
||||||
|
|
||||||
|
m_exifinfo->FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_SUBJECT_DISTANCE:
|
||||||
|
/* Inidcates the distacne the autofocus camera is focused to.
|
||||||
|
Tends to be less accurate as distance increases.
|
||||||
|
*/
|
||||||
|
m_exifinfo->Distance = (float)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_EXPOSURETIME:
|
||||||
|
/* Simplest way of expressing exposure time, so I
|
||||||
|
trust it most. (overwrite previously computd value
|
||||||
|
if there is one)
|
||||||
|
*/
|
||||||
|
m_exifinfo->ExposureTime =
|
||||||
|
(float)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_SHUTTERSPEED:
|
||||||
|
/* More complicated way of expressing exposure time,
|
||||||
|
so only use this value if we don't already have it
|
||||||
|
from somewhere else.
|
||||||
|
*/
|
||||||
|
if (m_exifinfo->ExposureTime == 0){
|
||||||
|
m_exifinfo->ExposureTime = (float)
|
||||||
|
(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0f)));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_FLASH:
|
||||||
|
if ((int32_t)ConvertAnyFormat(ValuePtr, Format) & 7){
|
||||||
|
m_exifinfo->FlashUsed = 1;
|
||||||
|
}else{
|
||||||
|
m_exifinfo->FlashUsed = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_ORIENTATION:
|
||||||
|
m_exifinfo->Orientation = (int32_t)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
if (m_exifinfo->Orientation < 1 || m_exifinfo->Orientation > 8){
|
||||||
|
strcpy(m_szLastError,"Undefined rotation value");
|
||||||
|
m_exifinfo->Orientation = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_EXIF_IMAGELENGTH:
|
||||||
|
case TAG_EXIF_IMAGEWIDTH:
|
||||||
|
/* Use largest of height and width to deal with images
|
||||||
|
that have been rotated to portrait format.
|
||||||
|
*/
|
||||||
|
a = (int32_t)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
if (ExifImageWidth < a) ExifImageWidth = a;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_FOCALPLANEXRES:
|
||||||
|
m_exifinfo->FocalplaneXRes = (float)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_FOCALPLANEYRES:
|
||||||
|
m_exifinfo->FocalplaneYRes = (float)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_RESOLUTIONUNIT:
|
||||||
|
switch((int32_t)ConvertAnyFormat(ValuePtr, Format)){
|
||||||
|
case 1: m_exifinfo->ResolutionUnit = 1.0f; break; /* 1 inch */
|
||||||
|
case 2: m_exifinfo->ResolutionUnit = 1.0f; break;
|
||||||
|
case 3: m_exifinfo->ResolutionUnit = 0.3937007874f; break; /* 1 centimeter*/
|
||||||
|
case 4: m_exifinfo->ResolutionUnit = 0.03937007874f; break; /* 1 millimeter*/
|
||||||
|
case 5: m_exifinfo->ResolutionUnit = 0.00003937007874f; /* 1 micrometer*/
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_FOCALPLANEUNITS:
|
||||||
|
switch((int32_t)ConvertAnyFormat(ValuePtr, Format)){
|
||||||
|
case 1: m_exifinfo->FocalplaneUnits = 1.0f; break; /* 1 inch */
|
||||||
|
case 2: m_exifinfo->FocalplaneUnits = 1.0f; break;
|
||||||
|
case 3: m_exifinfo->FocalplaneUnits = 0.3937007874f; break; /* 1 centimeter*/
|
||||||
|
case 4: m_exifinfo->FocalplaneUnits = 0.03937007874f; break; /* 1 millimeter*/
|
||||||
|
case 5: m_exifinfo->FocalplaneUnits = 0.00003937007874f; /* 1 micrometer*/
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Remaining cases contributed by: Volker C. Schoech <schoech(at)gmx(dot)de>
|
||||||
|
|
||||||
|
case TAG_EXPOSURE_BIAS:
|
||||||
|
m_exifinfo->ExposureBias = (float) ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_WHITEBALANCE:
|
||||||
|
m_exifinfo->Whitebalance = (int32_t)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_METERING_MODE:
|
||||||
|
m_exifinfo->MeteringMode = (int32_t)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_EXPOSURE_PROGRAM:
|
||||||
|
m_exifinfo->ExposureProgram = (int32_t)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_ISO_EQUIVALENT:
|
||||||
|
m_exifinfo->ISOequivalent = (int32_t)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
if ( m_exifinfo->ISOequivalent < 50 ) m_exifinfo->ISOequivalent *= 200;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_COMPRESSION_LEVEL:
|
||||||
|
m_exifinfo->CompressionLevel = (int32_t)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_XRESOLUTION:
|
||||||
|
m_exifinfo->Xresolution = (float)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
break;
|
||||||
|
case TAG_YRESOLUTION:
|
||||||
|
m_exifinfo->Yresolution = (float)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_THUMBNAIL_OFFSET:
|
||||||
|
ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_THUMBNAIL_LENGTH:
|
||||||
|
ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET){
|
||||||
|
uint8_t * SubdirStart;
|
||||||
|
unsigned Offset = Get32u(ValuePtr);
|
||||||
|
if (Offset>8){
|
||||||
|
SubdirStart = OffsetBase + Offset;
|
||||||
|
if (SubdirStart < OffsetBase ||
|
||||||
|
SubdirStart > OffsetBase+ExifLength){
|
||||||
|
strcpy(m_szLastError,"Illegal subdirectory link");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ProcessExifDir(SubdirStart, OffsetBase, ExifLength, m_exifinfo, LastExifRefdP, NestingLevel+1);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
/* In addition to linking to subdirectories via exif tags,
|
||||||
|
there's also a potential link to another directory at the end
|
||||||
|
of each directory. This has got to be the result of a
|
||||||
|
committee!
|
||||||
|
*/
|
||||||
|
uint8_t * SubdirStart;
|
||||||
|
unsigned Offset;
|
||||||
|
Offset = Get16u(DirStart+2+12*NumDirEntries);
|
||||||
|
if (Offset){
|
||||||
|
SubdirStart = OffsetBase + Offset;
|
||||||
|
if (SubdirStart < OffsetBase
|
||||||
|
|| SubdirStart > OffsetBase+ExifLength){
|
||||||
|
strcpy(m_szLastError,"Illegal subdirectory link");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ProcessExifDir(SubdirStart, OffsetBase, ExifLength, m_exifinfo, LastExifRefdP, NestingLevel+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (ThumbnailSize && ThumbnailOffset){
|
||||||
|
if (ThumbnailSize + ThumbnailOffset <= ExifLength){
|
||||||
|
/* The thumbnail pointer appears to be valid. Store it. */
|
||||||
|
m_exifinfo->ThumbnailPointer = OffsetBase + ThumbnailOffset;
|
||||||
|
m_exifinfo->ThumbnailSize = ThumbnailSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
Evaluate number, be it int32_t, rational, or float from directory.
|
||||||
|
--------------------------------------------------------------------------*/
|
||||||
|
double CxImageJPG::CxExifInfo::ConvertAnyFormat(void * ValuePtr, int32_t Format)
|
||||||
|
{
|
||||||
|
double Value;
|
||||||
|
Value = 0;
|
||||||
|
|
||||||
|
switch(Format){
|
||||||
|
case FMT_SBYTE: Value = *(signed char *)ValuePtr; break;
|
||||||
|
case FMT_BYTE: Value = *(uint8_t *)ValuePtr; break;
|
||||||
|
|
||||||
|
case FMT_USHORT: Value = Get16u(ValuePtr); break;
|
||||||
|
case FMT_ULONG: Value = Get32u(ValuePtr); break;
|
||||||
|
|
||||||
|
case FMT_URATIONAL:
|
||||||
|
case FMT_SRATIONAL:
|
||||||
|
{
|
||||||
|
int32_t Num,Den;
|
||||||
|
Num = Get32s(ValuePtr);
|
||||||
|
Den = Get32s(4+(char *)ValuePtr);
|
||||||
|
if (Den == 0){
|
||||||
|
Value = 0;
|
||||||
|
}else{
|
||||||
|
Value = (double)Num/Den;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case FMT_SSHORT: Value = (int16_t)Get16u(ValuePtr); break;
|
||||||
|
case FMT_SLONG: Value = Get32s(ValuePtr); break;
|
||||||
|
|
||||||
|
/* Not sure if this is correct (never seen float used in Exif format)
|
||||||
|
*/
|
||||||
|
case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break;
|
||||||
|
case FMT_DOUBLE: Value = *(double *)ValuePtr; break;
|
||||||
|
}
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImageJPG::CxExifInfo::process_COM (const uint8_t * Data, int32_t length)
|
||||||
|
{
|
||||||
|
int32_t ch;
|
||||||
|
char Comment[MAX_COMMENT+1];
|
||||||
|
int32_t nch;
|
||||||
|
int32_t a;
|
||||||
|
|
||||||
|
nch = 0;
|
||||||
|
|
||||||
|
if (length > MAX_COMMENT) length = MAX_COMMENT; // Truncate if it won't fit in our structure.
|
||||||
|
|
||||||
|
for (a=2;a<length;a++){
|
||||||
|
ch = Data[a];
|
||||||
|
|
||||||
|
if (ch == '\r' && Data[a+1] == '\n') continue; // Remove cr followed by lf.
|
||||||
|
|
||||||
|
if (isprint(ch) || ch == '\n' || ch == '\t'){
|
||||||
|
Comment[nch++] = (char)ch;
|
||||||
|
}else{
|
||||||
|
Comment[nch++] = '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Comment[nch] = '\0'; // Null terminate
|
||||||
|
|
||||||
|
//if (ShowTags) printf("COM marker comment: %s\n",Comment);
|
||||||
|
|
||||||
|
strcpy(m_exifinfo->Comments,Comment);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImageJPG::CxExifInfo::process_SOFn (const uint8_t * Data, int32_t marker)
|
||||||
|
{
|
||||||
|
int32_t data_precision, num_components;
|
||||||
|
|
||||||
|
data_precision = Data[2];
|
||||||
|
m_exifinfo->Height = Get16m((void*)(Data+3));
|
||||||
|
m_exifinfo->Width = Get16m((void*)(Data+5));
|
||||||
|
num_components = Data[7];
|
||||||
|
|
||||||
|
if (num_components == 3){
|
||||||
|
m_exifinfo->IsColor = 1;
|
||||||
|
}else{
|
||||||
|
m_exifinfo->IsColor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_exifinfo->Process = marker;
|
||||||
|
|
||||||
|
//if (ShowTags) printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n",
|
||||||
|
// ImageInfo.Width, ImageInfo.Height, num_components, data_precision);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* this will work only on a CxImageJPG object, if the image originally has valid EXIF data
|
||||||
|
\verbatim
|
||||||
|
CxImageJPG jpg;
|
||||||
|
CxIOFile in,out;
|
||||||
|
in.Open("D:\\exif_in.jpg","rb");
|
||||||
|
out.Open("D:\\exif_out.jpg","w+b");
|
||||||
|
jpg.Decode(&in);
|
||||||
|
if (jpg.IsValid()){
|
||||||
|
jpg.RotateLeft();
|
||||||
|
jpg.Encode(&out);
|
||||||
|
}
|
||||||
|
\endverbatim
|
||||||
|
*/
|
||||||
|
bool CxImageJPG::CxExifInfo::EncodeExif(CxFile * hFile)
|
||||||
|
{
|
||||||
|
int32_t a;
|
||||||
|
|
||||||
|
if (FindSection(M_SOS)==NULL){
|
||||||
|
strcpy(m_szLastError,"Can't write exif : didn't read all");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial static jpeg marker.
|
||||||
|
hFile->PutC(0xff);
|
||||||
|
hFile->PutC(0xd8);
|
||||||
|
|
||||||
|
if (Sections[0].Type != M_EXIF && Sections[0].Type != M_JFIF){
|
||||||
|
// The image must start with an exif or jfif marker. If we threw those away, create one.
|
||||||
|
static uint8_t JfifHead[18] = {
|
||||||
|
0xff, M_JFIF,
|
||||||
|
0x00, 0x10, 'J' , 'F' , 'I' , 'F' , 0x00, 0x01,
|
||||||
|
0x01, 0x01, 0x01, 0x2C, 0x01, 0x2C, 0x00, 0x00
|
||||||
|
};
|
||||||
|
hFile->Write(JfifHead, 18, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write all the misc sections
|
||||||
|
for (a=0;a<SectionsRead-1;a++){
|
||||||
|
hFile->PutC(0xff);
|
||||||
|
hFile->PutC((uint8_t)(Sections[a].Type));
|
||||||
|
hFile->Write(Sections[a].Data, Sections[a].Size, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the remaining image data.
|
||||||
|
hFile->Write(Sections[a].Data, Sections[a].Size, 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImageJPG::CxExifInfo::DiscardAllButExif()
|
||||||
|
{
|
||||||
|
Section_t ExifKeeper;
|
||||||
|
Section_t CommentKeeper;
|
||||||
|
int32_t a;
|
||||||
|
|
||||||
|
memset(&ExifKeeper, 0, sizeof(ExifKeeper));
|
||||||
|
memset(&CommentKeeper, 0, sizeof(ExifKeeper));
|
||||||
|
|
||||||
|
for (a=0;a<SectionsRead;a++){
|
||||||
|
if (Sections[a].Type == M_EXIF && ExifKeeper.Type == 0){
|
||||||
|
ExifKeeper = Sections[a];
|
||||||
|
}else if (Sections[a].Type == M_COM && CommentKeeper.Type == 0){
|
||||||
|
CommentKeeper = Sections[a];
|
||||||
|
}else{
|
||||||
|
free(Sections[a].Data);
|
||||||
|
Sections[a].Data = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SectionsRead = 0;
|
||||||
|
if (ExifKeeper.Type){
|
||||||
|
Sections[SectionsRead++] = ExifKeeper;
|
||||||
|
}
|
||||||
|
if (CommentKeeper.Type){
|
||||||
|
Sections[SectionsRead++] = CommentKeeper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void* CxImageJPG::CxExifInfo::FindSection(int32_t SectionType)
|
||||||
|
{
|
||||||
|
int32_t a;
|
||||||
|
for (a=0;a<SectionsRead-1;a++){
|
||||||
|
if (Sections[a].Type == SectionType){
|
||||||
|
return &Sections[a];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Could not be found.
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGEJPG_SUPPORT_EXIF
|
||||||
@@ -0,0 +1,537 @@
|
|||||||
|
// ximage.cpp : main implementation file
|
||||||
|
/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CxImage
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Initialize the internal structures
|
||||||
|
*/
|
||||||
|
void CxImage::Startup(uint32_t imagetype)
|
||||||
|
{
|
||||||
|
//init pointers
|
||||||
|
pDib = pSelection = pAlpha = NULL;
|
||||||
|
ppLayers = ppFrames = NULL;
|
||||||
|
//init structures
|
||||||
|
memset(&head,0,sizeof(BITMAPINFOHEADER));
|
||||||
|
memset(&info,0,sizeof(CXIMAGEINFO));
|
||||||
|
//init default attributes
|
||||||
|
info.dwType = imagetype;
|
||||||
|
info.fQuality = 90.0f;
|
||||||
|
info.nAlphaMax = 255;
|
||||||
|
info.nBkgndIndex = -1;
|
||||||
|
info.bEnabled = true;
|
||||||
|
info.nJpegScale = 1;
|
||||||
|
SetXDPI(CXIMAGE_DEFAULT_DPI);
|
||||||
|
SetYDPI(CXIMAGE_DEFAULT_DPI);
|
||||||
|
|
||||||
|
int16_t test = 1;
|
||||||
|
info.bLittleEndianHost = (*((char *) &test) == 1);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Empty image constructor
|
||||||
|
* \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS
|
||||||
|
*/
|
||||||
|
CxImage::CxImage(uint32_t imagetype)
|
||||||
|
{
|
||||||
|
Startup(imagetype);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Call this function to destroy image pixels, alpha channel, selection and sub layers.
|
||||||
|
* - Attributes are not erased, but IsValid returns false.
|
||||||
|
*
|
||||||
|
* \return true if everything is freed, false if the image is a Ghost
|
||||||
|
*/
|
||||||
|
bool CxImage::Destroy()
|
||||||
|
{
|
||||||
|
//free this only if it's valid and it's not a ghost
|
||||||
|
if (info.pGhost==NULL){
|
||||||
|
if (ppLayers) {
|
||||||
|
for(int32_t n=0; n<info.nNumLayers;n++){ delete ppLayers[n]; }
|
||||||
|
delete [] ppLayers; ppLayers=0; info.nNumLayers = 0;
|
||||||
|
}
|
||||||
|
if (pSelection) {free(pSelection); pSelection=0;}
|
||||||
|
if (pAlpha) {free(pAlpha); pAlpha=0;}
|
||||||
|
if (pDib) {free(pDib); pDib=0;}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImage::DestroyFrames()
|
||||||
|
{
|
||||||
|
if (info.pGhost==NULL) {
|
||||||
|
if (ppFrames) {
|
||||||
|
for (int32_t n=0; n<info.nNumFrames; n++) { delete ppFrames[n]; }
|
||||||
|
delete [] ppFrames; ppFrames = NULL; info.nNumFrames = 0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Sized image constructor
|
||||||
|
* \param dwWidth: width
|
||||||
|
* \param dwHeight: height
|
||||||
|
* \param wBpp: bit per pixel, can be 1, 4, 8, 24
|
||||||
|
* \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS
|
||||||
|
*/
|
||||||
|
CxImage::CxImage(uint32_t dwWidth, uint32_t dwHeight, uint32_t wBpp, uint32_t imagetype)
|
||||||
|
{
|
||||||
|
Startup(imagetype);
|
||||||
|
Create(dwWidth,dwHeight,wBpp,imagetype);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* image constructor from existing source
|
||||||
|
* \param src: source image.
|
||||||
|
* \param copypixels: copy the pixels from the source image into the new image.
|
||||||
|
* \param copyselection: copy the selection from source
|
||||||
|
* \param copyalpha: copy the alpha channel from source
|
||||||
|
* \sa Copy
|
||||||
|
*/
|
||||||
|
CxImage::CxImage(const CxImage &src, bool copypixels, bool copyselection, bool copyalpha)
|
||||||
|
{
|
||||||
|
Startup(src.GetType());
|
||||||
|
Copy(src,copypixels,copyselection,copyalpha);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Copies the image from an exsisting source
|
||||||
|
* \param src: source image.
|
||||||
|
* \param copypixels: copy the pixels from the source image into the new image.
|
||||||
|
* \param copyselection: copy the selection from source
|
||||||
|
* \param copyalpha: copy the alpha channel from source
|
||||||
|
*/
|
||||||
|
void CxImage::Copy(const CxImage &src, bool copypixels, bool copyselection, bool copyalpha)
|
||||||
|
{
|
||||||
|
// if the source is a ghost, the copy is still a ghost
|
||||||
|
if (src.info.pGhost){
|
||||||
|
Ghost(&src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//copy the attributes
|
||||||
|
memcpy(&info,&src.info,sizeof(CXIMAGEINFO));
|
||||||
|
memcpy(&head,&src.head,sizeof(BITMAPINFOHEADER)); // [andy] - fix for bitmap header DPI
|
||||||
|
//rebuild the image
|
||||||
|
Create(src.GetWidth(),src.GetHeight(),src.GetBpp(),src.GetType());
|
||||||
|
//copy the pixels and the palette, or at least copy the palette only.
|
||||||
|
if (copypixels && pDib && src.pDib) memcpy(pDib,src.pDib,GetSize());
|
||||||
|
else SetPalette(src.GetPalette());
|
||||||
|
int32_t nSize = head.biWidth * head.biHeight;
|
||||||
|
//copy the selection
|
||||||
|
if (copyselection && src.pSelection){
|
||||||
|
if (pSelection) free(pSelection);
|
||||||
|
pSelection = (uint8_t*)malloc(nSize);
|
||||||
|
memcpy(pSelection,src.pSelection,nSize);
|
||||||
|
}
|
||||||
|
//copy the alpha channel
|
||||||
|
if (copyalpha && src.pAlpha){
|
||||||
|
if (pAlpha) free(pAlpha);
|
||||||
|
pAlpha = (uint8_t*)malloc(nSize);
|
||||||
|
memcpy(pAlpha,src.pAlpha,nSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Copies the image attributes from an existing image.
|
||||||
|
* - Works only on an empty image, and the image will be still empty.
|
||||||
|
* - <b> Use it before Create() </b>
|
||||||
|
*/
|
||||||
|
void CxImage::CopyInfo(const CxImage &src)
|
||||||
|
{
|
||||||
|
if (pDib==NULL) memcpy(&info,&src.info,sizeof(CXIMAGEINFO));
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \sa Copy
|
||||||
|
*/
|
||||||
|
CxImage& CxImage::operator = (const CxImage& isrc)
|
||||||
|
{
|
||||||
|
if (this != &isrc) Copy(isrc);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Initializes or rebuilds the image.
|
||||||
|
* \param dwWidth: width
|
||||||
|
* \param dwHeight: height
|
||||||
|
* \param wBpp: bit per pixel, can be 1, 4, 8, 24
|
||||||
|
* \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS
|
||||||
|
* \return pointer to the internal pDib object; NULL if an error occurs.
|
||||||
|
*/
|
||||||
|
void* CxImage::Create(uint32_t dwWidth, uint32_t dwHeight, uint32_t wBpp, uint32_t imagetype)
|
||||||
|
{
|
||||||
|
// destroy the existing image (if any)
|
||||||
|
if (!Destroy())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// prevent further actions if width or height are not vaild <Balabasnia>
|
||||||
|
if ((dwWidth == 0) || (dwHeight == 0)){
|
||||||
|
strcpy(info.szLastError,"CxImage::Create : width and height must be greater than zero");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure bits per pixel is valid
|
||||||
|
if (wBpp <= 1) wBpp = 1;
|
||||||
|
else if (wBpp <= 4) wBpp = 4;
|
||||||
|
else if (wBpp <= 8) wBpp = 8;
|
||||||
|
else wBpp = 24;
|
||||||
|
|
||||||
|
// limit memory requirements
|
||||||
|
if ((((float)dwWidth*(float)dwHeight*(float)wBpp)/8.0f) > (float)CXIMAGE_MAX_MEMORY)
|
||||||
|
{
|
||||||
|
strcpy(info.szLastError,"CXIMAGE_MAX_MEMORY exceeded");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the correct bpp value
|
||||||
|
switch (wBpp){
|
||||||
|
case 1:
|
||||||
|
head.biClrUsed = 2; break;
|
||||||
|
case 4:
|
||||||
|
head.biClrUsed = 16; break;
|
||||||
|
case 8:
|
||||||
|
head.biClrUsed = 256; break;
|
||||||
|
default:
|
||||||
|
head.biClrUsed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//set the common image informations
|
||||||
|
info.dwEffWidth = ((((wBpp * dwWidth) + 31) / 32) * 4);
|
||||||
|
info.dwType = imagetype;
|
||||||
|
|
||||||
|
// initialize BITMAPINFOHEADER
|
||||||
|
head.biSize = sizeof(BITMAPINFOHEADER); //<ralphw>
|
||||||
|
head.biWidth = dwWidth; // fill in width from parameter
|
||||||
|
head.biHeight = dwHeight; // fill in height from parameter
|
||||||
|
head.biPlanes = 1; // must be 1
|
||||||
|
head.biBitCount = (uint16_t)wBpp; // from parameter
|
||||||
|
head.biCompression = BI_RGB;
|
||||||
|
head.biSizeImage = info.dwEffWidth * dwHeight;
|
||||||
|
// head.biXPelsPerMeter = 0; See SetXDPI
|
||||||
|
// head.biYPelsPerMeter = 0; See SetYDPI
|
||||||
|
// head.biClrImportant = 0; See SetClrImportant
|
||||||
|
|
||||||
|
pDib = malloc(GetSize()); // alloc memory block to store our bitmap
|
||||||
|
if (!pDib){
|
||||||
|
strcpy(info.szLastError,"CxImage::Create can't allocate memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//clear the palette
|
||||||
|
RGBQUAD* pal=GetPalette();
|
||||||
|
if (pal) memset(pal,0,GetPaletteSize());
|
||||||
|
//Destroy the existing selection
|
||||||
|
#if CXIMAGE_SUPPORT_SELECTION
|
||||||
|
if (pSelection) SelectionDelete();
|
||||||
|
#endif //CXIMAGE_SUPPORT_SELECTION
|
||||||
|
//Destroy the existing alpha channel
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (pAlpha) AlphaDelete();
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
|
||||||
|
// use our bitmap info structure to fill in first part of
|
||||||
|
// our DIB with the BITMAPINFOHEADER
|
||||||
|
BITMAPINFOHEADER* lpbi;
|
||||||
|
lpbi = (BITMAPINFOHEADER*)(pDib);
|
||||||
|
*lpbi = head;
|
||||||
|
|
||||||
|
info.pImage=GetBits();
|
||||||
|
|
||||||
|
return pDib; //return handle to the DIB
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \return pointer to the image pixels. <b> USE CAREFULLY </b>
|
||||||
|
*/
|
||||||
|
uint8_t* CxImage::GetBits(uint32_t row)
|
||||||
|
{
|
||||||
|
if (pDib){
|
||||||
|
if (row) {
|
||||||
|
if (row<(uint32_t)head.biHeight){
|
||||||
|
return ((uint8_t*)pDib + *(uint32_t*)pDib + GetPaletteSize() + (info.dwEffWidth * row));
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ((uint8_t*)pDib + *(uint32_t*)pDib + GetPaletteSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \return the size in bytes of the internal pDib object
|
||||||
|
*/
|
||||||
|
int32_t CxImage::GetSize()
|
||||||
|
{
|
||||||
|
return head.biSize + head.biSizeImage + GetPaletteSize();
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Checks if the coordinates are inside the image
|
||||||
|
* \return true if x and y are both inside the image
|
||||||
|
*/
|
||||||
|
bool CxImage::IsInside(int32_t x, int32_t y)
|
||||||
|
{
|
||||||
|
return (0<=y && y<head.biHeight && 0<=x && x<head.biWidth);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Sets the image bits to the specified value
|
||||||
|
* - for indexed images, the output color is set by the palette entries.
|
||||||
|
* - for RGB images, the output color is a shade of gray.
|
||||||
|
*/
|
||||||
|
void CxImage::Clear(uint8_t bval)
|
||||||
|
{
|
||||||
|
if (pDib == 0) return;
|
||||||
|
|
||||||
|
if (GetBpp() == 1){
|
||||||
|
if (bval > 0) bval = 255;
|
||||||
|
}
|
||||||
|
if (GetBpp() == 4){
|
||||||
|
bval = (uint8_t)(17*(0x0F & bval));
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(info.pImage,bval,head.biSizeImage);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Transfers the image from an existing source image. The source becomes empty.
|
||||||
|
* \return true if everything is ok
|
||||||
|
*/
|
||||||
|
bool CxImage::Transfer(CxImage &from, bool bTransferFrames /*=true*/)
|
||||||
|
{
|
||||||
|
if (!Destroy())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
memcpy(&head,&from.head,sizeof(BITMAPINFOHEADER));
|
||||||
|
memcpy(&info,&from.info,sizeof(CXIMAGEINFO));
|
||||||
|
|
||||||
|
pDib = from.pDib;
|
||||||
|
pSelection = from.pSelection;
|
||||||
|
pAlpha = from.pAlpha;
|
||||||
|
ppLayers = from.ppLayers;
|
||||||
|
|
||||||
|
memset(&from.head,0,sizeof(BITMAPINFOHEADER));
|
||||||
|
memset(&from.info,0,sizeof(CXIMAGEINFO));
|
||||||
|
from.pDib = from.pSelection = from.pAlpha = NULL;
|
||||||
|
from.ppLayers = NULL;
|
||||||
|
|
||||||
|
if (bTransferFrames){
|
||||||
|
DestroyFrames();
|
||||||
|
ppFrames = from.ppFrames;
|
||||||
|
from.ppFrames = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* (this) points to the same pDib owned by (*from), the image remains in (*from)
|
||||||
|
* but (this) has the access to the pixels. <b>Use carefully !!!</b>
|
||||||
|
*/
|
||||||
|
void CxImage::Ghost(const CxImage *from)
|
||||||
|
{
|
||||||
|
if (from){
|
||||||
|
memcpy(&head,&from->head,sizeof(BITMAPINFOHEADER));
|
||||||
|
memcpy(&info,&from->info,sizeof(CXIMAGEINFO));
|
||||||
|
pDib = from->pDib;
|
||||||
|
pSelection = from->pSelection;
|
||||||
|
pAlpha = from->pAlpha;
|
||||||
|
ppLayers = from->ppLayers;
|
||||||
|
ppFrames = from->ppFrames;
|
||||||
|
info.pGhost=(CxImage *)from;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* turns a 16 or 32 bit bitfield image into a RGB image
|
||||||
|
*/
|
||||||
|
void CxImage::Bitfield2RGB(uint8_t *src, uint32_t redmask, uint32_t greenmask, uint32_t bluemask, uint8_t bpp)
|
||||||
|
{
|
||||||
|
switch (bpp){
|
||||||
|
case 16:
|
||||||
|
{
|
||||||
|
uint32_t ns[3]={0,0,0};
|
||||||
|
// compute the number of shift for each mask
|
||||||
|
for (int32_t i=0;i<16;i++){
|
||||||
|
if ((redmask>>i)&0x01) ns[0]++;
|
||||||
|
if ((greenmask>>i)&0x01) ns[1]++;
|
||||||
|
if ((bluemask>>i)&0x01) ns[2]++;
|
||||||
|
}
|
||||||
|
ns[1]+=ns[0]; ns[2]+=ns[1]; ns[0]=8-ns[0]; ns[1]-=8; ns[2]-=8;
|
||||||
|
// dword aligned width for 16 bit image
|
||||||
|
int32_t effwidth2=(((head.biWidth + 1) / 2) * 4);
|
||||||
|
uint16_t w;
|
||||||
|
int32_t y2,y3,x2,x3;
|
||||||
|
uint8_t *p=info.pImage;
|
||||||
|
// scan the buffer in reverse direction to avoid reallocations
|
||||||
|
for (int32_t y=head.biHeight-1; y>=0; y--){
|
||||||
|
y2=effwidth2*y;
|
||||||
|
y3=info.dwEffWidth*y;
|
||||||
|
for (int32_t x=head.biWidth-1; x>=0; x--){
|
||||||
|
x2 = 2*x+y2;
|
||||||
|
x3 = 3*x+y3;
|
||||||
|
w = (uint16_t)(src[x2]+256*src[1+x2]);
|
||||||
|
p[ x3]=(uint8_t)((w & bluemask)<<ns[0]);
|
||||||
|
p[1+x3]=(uint8_t)((w & greenmask)>>ns[1]);
|
||||||
|
p[2+x3]=(uint8_t)((w & redmask)>>ns[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 32:
|
||||||
|
{
|
||||||
|
uint32_t ns[3]={0,0,0};
|
||||||
|
// compute the number of shift for each mask
|
||||||
|
for (int32_t i=8;i<32;i+=8){
|
||||||
|
if (redmask>>i) ns[0]++;
|
||||||
|
if (greenmask>>i) ns[1]++;
|
||||||
|
if (bluemask>>i) ns[2]++;
|
||||||
|
}
|
||||||
|
// dword aligned width for 32 bit image
|
||||||
|
int32_t effwidth4 = head.biWidth * 4;
|
||||||
|
int32_t y4,y3,x4,x3;
|
||||||
|
uint8_t *p=info.pImage;
|
||||||
|
// scan the buffer in reverse direction to avoid reallocations
|
||||||
|
for (int32_t y=head.biHeight-1; y>=0; y--){
|
||||||
|
y4=effwidth4*y;
|
||||||
|
y3=info.dwEffWidth*y;
|
||||||
|
for (int32_t x=head.biWidth-1; x>=0; x--){
|
||||||
|
x4 = 4*x+y4;
|
||||||
|
x3 = 3*x+y3;
|
||||||
|
p[ x3]=src[ns[2]+x4];
|
||||||
|
p[1+x3]=src[ns[1]+x4];
|
||||||
|
p[2+x3]=src[ns[0]+x4];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Creates an image from a generic buffer
|
||||||
|
* \param pArray: source memory buffer
|
||||||
|
* \param dwWidth: image width
|
||||||
|
* \param dwHeight: image height
|
||||||
|
* \param dwBitsperpixel: can be 1,4,8,24,32
|
||||||
|
* \param dwBytesperline: line alignment, in bytes, for a single row stored in pArray
|
||||||
|
* \param bFlipImage: tune this parameter if the image is upsidedown
|
||||||
|
* \return true if everything is ok
|
||||||
|
*/
|
||||||
|
bool CxImage::CreateFromArray(uint8_t* pArray,uint32_t dwWidth,uint32_t dwHeight,uint32_t dwBitsperpixel, uint32_t dwBytesperline, bool bFlipImage)
|
||||||
|
{
|
||||||
|
if (pArray==NULL) return false;
|
||||||
|
if (!((dwBitsperpixel==1)||(dwBitsperpixel==4)||(dwBitsperpixel==8)||
|
||||||
|
(dwBitsperpixel==24)||(dwBitsperpixel==32))) return false;
|
||||||
|
|
||||||
|
if (!Create(dwWidth,dwHeight,dwBitsperpixel)) return false;
|
||||||
|
|
||||||
|
if (dwBitsperpixel<24) SetGrayPalette();
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (dwBitsperpixel==32) AlphaCreate();
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
|
||||||
|
uint8_t *dst,*src;
|
||||||
|
|
||||||
|
for (uint32_t y = 0; y<dwHeight; y++) {
|
||||||
|
dst = info.pImage + (bFlipImage?(dwHeight-1-y):y) * info.dwEffWidth;
|
||||||
|
src = pArray + y * dwBytesperline;
|
||||||
|
if (dwBitsperpixel==32){
|
||||||
|
for(uint32_t x=0;x<dwWidth;x++){
|
||||||
|
*dst++=src[0];
|
||||||
|
*dst++=src[1];
|
||||||
|
*dst++=src[2];
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
AlphaSet(x,(bFlipImage?(dwHeight-1-y):y),src[3]);
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
src+=4;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(dst,src,min(info.dwEffWidth,dwBytesperline));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \sa CreateFromArray
|
||||||
|
*/
|
||||||
|
bool CxImage::CreateFromMatrix(uint8_t** ppMatrix,uint32_t dwWidth,uint32_t dwHeight,uint32_t dwBitsperpixel, uint32_t dwBytesperline, bool bFlipImage)
|
||||||
|
{
|
||||||
|
if (ppMatrix==NULL) return false;
|
||||||
|
if (!((dwBitsperpixel==1)||(dwBitsperpixel==4)||(dwBitsperpixel==8)||
|
||||||
|
(dwBitsperpixel==24)||(dwBitsperpixel==32))) return false;
|
||||||
|
|
||||||
|
if (!Create(dwWidth,dwHeight,dwBitsperpixel)) return false;
|
||||||
|
|
||||||
|
if (dwBitsperpixel<24) SetGrayPalette();
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (dwBitsperpixel==32) AlphaCreate();
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
|
||||||
|
uint8_t *dst,*src;
|
||||||
|
|
||||||
|
for (uint32_t y = 0; y<dwHeight; y++) {
|
||||||
|
dst = info.pImage + (bFlipImage?(dwHeight-1-y):y) * info.dwEffWidth;
|
||||||
|
src = ppMatrix[y];
|
||||||
|
if (src){
|
||||||
|
if (dwBitsperpixel==32){
|
||||||
|
for(uint32_t x=0;x<dwWidth;x++){
|
||||||
|
*dst++=src[0];
|
||||||
|
*dst++=src[1];
|
||||||
|
*dst++=src[2];
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
AlphaSet(x,(bFlipImage?(dwHeight-1-y):y),src[3]);
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
src+=4;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(dst,src,min(info.dwEffWidth,dwBytesperline));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \return lightness difference between elem1 and elem2
|
||||||
|
*/
|
||||||
|
int32_t CxImage::CompareColors(const void *elem1, const void *elem2)
|
||||||
|
{
|
||||||
|
RGBQUAD* c1 = (RGBQUAD*)elem1;
|
||||||
|
RGBQUAD* c2 = (RGBQUAD*)elem2;
|
||||||
|
|
||||||
|
int32_t g1 = (int32_t)RGB2GRAY(c1->rgbRed,c1->rgbGreen,c1->rgbBlue);
|
||||||
|
int32_t g2 = (int32_t)RGB2GRAY(c2->rgbRed,c2->rgbGreen,c2->rgbBlue);
|
||||||
|
|
||||||
|
return (g1-g2);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* simply calls "if (memblock) free(memblock);".
|
||||||
|
* Useful when calling Encode for a memory buffer,
|
||||||
|
* from a DLL compiled with different memory management options.
|
||||||
|
* CxImage::FreeMemory will use the same memory environment used by Encode.
|
||||||
|
* \author [livecn]
|
||||||
|
*/
|
||||||
|
void CxImage::FreeMemory(void* memblock)
|
||||||
|
{
|
||||||
|
if (memblock)
|
||||||
|
free(memblock);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//EOF
|
||||||
@@ -0,0 +1,807 @@
|
|||||||
|
/*
|
||||||
|
* File: ximage.h
|
||||||
|
* Purpose: General Purpose Image Class
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
|
||||||
|
|
||||||
|
CxImage version 7.0.1 07/Jan/2011
|
||||||
|
|
||||||
|
CxImage : Copyright (C) 2001 - 2010, Davide Pizzolato
|
||||||
|
|
||||||
|
Original CImage and CImageIterator implementation are:
|
||||||
|
Copyright (C) 1995, Alejandro Aguilar Sierra (asierra(at)servidor(dot)unam(dot)mx)
|
||||||
|
|
||||||
|
Covered code is provided under this license on an "as is" basis, without warranty
|
||||||
|
of any kind, either expressed or implied, including, without limitation, warranties
|
||||||
|
that the covered code is free of defects, merchantable, fit for a particular purpose
|
||||||
|
or non-infringing. The entire risk as to the quality and performance of the covered
|
||||||
|
code is with you. Should any covered code prove defective in any respect, you (not
|
||||||
|
the initial developer or any other contributor) assume the cost of any necessary
|
||||||
|
servicing, repair or correction. This disclaimer of warranty constitutes an essential
|
||||||
|
part of this license. No use of any covered code is authorized hereunder except under
|
||||||
|
this disclaimer.
|
||||||
|
|
||||||
|
Permission is hereby granted to use, copy, modify, and distribute this
|
||||||
|
source code, or portions hereof, for any purpose, including commercial applications,
|
||||||
|
freely and without fee, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Other information about CxImage, and the latest version, can be found at the
|
||||||
|
CxImage home page: http://www.xdp.it/cximage/
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#if !defined(__CXIMAGE_H)
|
||||||
|
#define __CXIMAGE_H
|
||||||
|
|
||||||
|
#if _MSC_VER > 1000
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _LINUX
|
||||||
|
#define _XOPEN_SOURCE
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
#include "xfile.h"
|
||||||
|
#include "xiofile.h"
|
||||||
|
#include "xmemfile.h"
|
||||||
|
#include "ximadef.h" //<vho> adjust some #define
|
||||||
|
|
||||||
|
/* see "ximacfg.h" for CxImage configuration options */
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CxImage formats enumerator
|
||||||
|
enum ENUM_CXIMAGE_FORMATS{
|
||||||
|
CXIMAGE_FORMAT_UNKNOWN = 0,
|
||||||
|
#if CXIMAGE_SUPPORT_BMP
|
||||||
|
CXIMAGE_FORMAT_BMP = 1,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_GIF
|
||||||
|
CXIMAGE_FORMAT_GIF = 2,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JPG
|
||||||
|
CXIMAGE_FORMAT_JPG = 3,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PNG
|
||||||
|
CXIMAGE_FORMAT_PNG = 4,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_ICO
|
||||||
|
CXIMAGE_FORMAT_ICO = 5,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_TIF
|
||||||
|
CXIMAGE_FORMAT_TIF = 6,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_TGA
|
||||||
|
CXIMAGE_FORMAT_TGA = 7,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PCX
|
||||||
|
CXIMAGE_FORMAT_PCX = 8,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_WBMP
|
||||||
|
CXIMAGE_FORMAT_WBMP = 9,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_WMF
|
||||||
|
CXIMAGE_FORMAT_WMF = 10,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JP2
|
||||||
|
CXIMAGE_FORMAT_JP2 = 11,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JPC
|
||||||
|
CXIMAGE_FORMAT_JPC = 12,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PGX
|
||||||
|
CXIMAGE_FORMAT_PGX = 13,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PNM
|
||||||
|
CXIMAGE_FORMAT_PNM = 14,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_RAS
|
||||||
|
CXIMAGE_FORMAT_RAS = 15,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JBG
|
||||||
|
CXIMAGE_FORMAT_JBG = 16,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_MNG
|
||||||
|
CXIMAGE_FORMAT_MNG = 17,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_SKA
|
||||||
|
CXIMAGE_FORMAT_SKA = 18,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_RAW
|
||||||
|
CXIMAGE_FORMAT_RAW = 19,
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PSD
|
||||||
|
CXIMAGE_FORMAT_PSD = 20,
|
||||||
|
#endif
|
||||||
|
CMAX_IMAGE_FORMATS = CXIMAGE_SUPPORT_BMP + CXIMAGE_SUPPORT_GIF + CXIMAGE_SUPPORT_JPG +
|
||||||
|
CXIMAGE_SUPPORT_PNG + CXIMAGE_SUPPORT_MNG + CXIMAGE_SUPPORT_ICO +
|
||||||
|
CXIMAGE_SUPPORT_TIF + CXIMAGE_SUPPORT_TGA + CXIMAGE_SUPPORT_PCX +
|
||||||
|
CXIMAGE_SUPPORT_WBMP+ CXIMAGE_SUPPORT_WMF +
|
||||||
|
CXIMAGE_SUPPORT_JBG + CXIMAGE_SUPPORT_JP2 + CXIMAGE_SUPPORT_JPC +
|
||||||
|
CXIMAGE_SUPPORT_PGX + CXIMAGE_SUPPORT_PNM + CXIMAGE_SUPPORT_RAS +
|
||||||
|
CXIMAGE_SUPPORT_SKA + CXIMAGE_SUPPORT_RAW + CXIMAGE_SUPPORT_PSD + 1
|
||||||
|
};
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_EXIF
|
||||||
|
|
||||||
|
#define MAX_COMMENT 255
|
||||||
|
#define MAX_SECTIONS 20
|
||||||
|
|
||||||
|
typedef struct tag_ExifInfo {
|
||||||
|
char Version [5];
|
||||||
|
char CameraMake [32];
|
||||||
|
char CameraModel [40];
|
||||||
|
char DateTime [20];
|
||||||
|
int32_t Height, Width;
|
||||||
|
int32_t Orientation;
|
||||||
|
int32_t IsColor;
|
||||||
|
int32_t Process;
|
||||||
|
int32_t FlashUsed;
|
||||||
|
float FocalLength;
|
||||||
|
float ExposureTime;
|
||||||
|
float ApertureFNumber;
|
||||||
|
float Distance;
|
||||||
|
float CCDWidth;
|
||||||
|
float ExposureBias;
|
||||||
|
int32_t Whitebalance;
|
||||||
|
int32_t MeteringMode;
|
||||||
|
int32_t ExposureProgram;
|
||||||
|
int32_t ISOequivalent;
|
||||||
|
int32_t CompressionLevel;
|
||||||
|
float FocalplaneXRes;
|
||||||
|
float FocalplaneYRes;
|
||||||
|
float FocalplaneUnits;
|
||||||
|
float Xresolution;
|
||||||
|
float Yresolution;
|
||||||
|
float ResolutionUnit;
|
||||||
|
float Brightness;
|
||||||
|
char Comments[MAX_COMMENT+1];
|
||||||
|
|
||||||
|
uint8_t * ThumbnailPointer; /* Pointer at the thumbnail */
|
||||||
|
unsigned ThumbnailSize; /* Size of thumbnail. */
|
||||||
|
|
||||||
|
bool IsExif;
|
||||||
|
} EXIFINFO;
|
||||||
|
|
||||||
|
#endif //CXIMAGE_SUPPORT_EXIF
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CxImage class
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
class DLL_EXP CxImage
|
||||||
|
{
|
||||||
|
//extensible information collector
|
||||||
|
typedef struct tagCxImageInfo {
|
||||||
|
uint32_t dwEffWidth; ///< uint32_t aligned scan line width
|
||||||
|
uint8_t* pImage; ///< THE IMAGE BITS
|
||||||
|
CxImage* pGhost; ///< if this is a ghost, pGhost points to the body
|
||||||
|
CxImage* pParent; ///< if this is a layer, pParent points to the body
|
||||||
|
uint32_t dwType; ///< original image format
|
||||||
|
char szLastError[256]; ///< debugging
|
||||||
|
int32_t nProgress; ///< monitor
|
||||||
|
int32_t nEscape; ///< escape
|
||||||
|
int32_t nBkgndIndex; ///< used for GIF, PNG, MNG
|
||||||
|
RGBQUAD nBkgndColor; ///< used for RGB transparency
|
||||||
|
float fQuality; ///< used for JPEG, JPEG2000 (0.0f ... 100.0f)
|
||||||
|
uint8_t nJpegScale; ///< used for JPEG [ignacio]
|
||||||
|
int32_t nFrame; ///< used for TIF, GIF, MNG : actual frame
|
||||||
|
int32_t nNumFrames; ///< used for TIF, GIF, MNG : total number of frames
|
||||||
|
uint32_t dwFrameDelay; ///< used for GIF, MNG
|
||||||
|
int32_t xDPI; ///< horizontal resolution
|
||||||
|
int32_t yDPI; ///< vertical resolution
|
||||||
|
RECT rSelectionBox; ///< bounding rectangle
|
||||||
|
uint8_t nAlphaMax; ///< max opacity (fade)
|
||||||
|
bool bAlphaPaletteEnabled; ///< true if alpha values in the palette are enabled.
|
||||||
|
bool bEnabled; ///< enables the painting functions
|
||||||
|
int32_t xOffset;
|
||||||
|
int32_t yOffset;
|
||||||
|
uint32_t dwCodecOpt[CMAX_IMAGE_FORMATS]; ///< for GIF, TIF : 0=def.1=unc,2=fax3,3=fax4,4=pack,5=jpg
|
||||||
|
RGBQUAD last_c; ///< for GetNearestIndex optimization
|
||||||
|
uint8_t last_c_index;
|
||||||
|
bool last_c_isvalid;
|
||||||
|
int32_t nNumLayers;
|
||||||
|
uint32_t dwFlags; ///< 0x??00000 = reserved, 0x00??0000 = blend mode, 0x0000???? = layer id - user flags
|
||||||
|
uint8_t dispmeth;
|
||||||
|
bool bGetAllFrames;
|
||||||
|
bool bLittleEndianHost;
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_EXIF
|
||||||
|
EXIFINFO ExifInfo;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} CXIMAGEINFO;
|
||||||
|
|
||||||
|
public:
|
||||||
|
//public structures
|
||||||
|
struct rgb_color { uint8_t r,g,b; };
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_WINDOWS
|
||||||
|
// <VATI> text placement data
|
||||||
|
// members must be initialized with the InitTextInfo(&this) function.
|
||||||
|
typedef struct tagCxTextInfo
|
||||||
|
{
|
||||||
|
#if defined (_WIN32_WCE)
|
||||||
|
TCHAR text[256]; ///< text for windows CE
|
||||||
|
#else
|
||||||
|
TCHAR text[4096]; ///< text (char -> TCHAR for UNICODE [Cesar M])
|
||||||
|
#endif
|
||||||
|
LOGFONT lfont; ///< font and codepage data
|
||||||
|
COLORREF fcolor; ///< foreground color
|
||||||
|
int32_t align; ///< DT_CENTER, DT_RIGHT, DT_LEFT aligment for multiline text
|
||||||
|
uint8_t smooth; ///< text smoothing option. Default is false.
|
||||||
|
uint8_t opaque; ///< text has background or hasn't. Default is true.
|
||||||
|
///< data for background (ignored if .opaque==FALSE)
|
||||||
|
COLORREF bcolor; ///< background color
|
||||||
|
float b_opacity; ///< opacity value for background between 0.0-1.0 Default is 0. (opaque)
|
||||||
|
uint8_t b_outline; ///< outline width for background (zero: no outline)
|
||||||
|
uint8_t b_round; ///< rounding radius for background rectangle. % of the height, between 0-50. Default is 10.
|
||||||
|
///< (backgr. always has a frame: width = 3 pixel + 10% of height by default.)
|
||||||
|
} CXTEXTINFO;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** \addtogroup Constructors */ //@{
|
||||||
|
CxImage(uint32_t imagetype = 0);
|
||||||
|
CxImage(uint32_t dwWidth, uint32_t dwHeight, uint32_t wBpp, uint32_t imagetype = 0);
|
||||||
|
CxImage(const CxImage &src, bool copypixels = true, bool copyselection = true, bool copyalpha = true);
|
||||||
|
#if CXIMAGE_SUPPORT_DECODE
|
||||||
|
CxImage(const TCHAR * filename, uint32_t imagetype); // For UNICODE support: char -> TCHAR
|
||||||
|
CxImage(FILE * stream, uint32_t imagetype);
|
||||||
|
CxImage(CxFile * stream, uint32_t imagetype);
|
||||||
|
CxImage(uint8_t * buffer, uint32_t size, uint32_t imagetype);
|
||||||
|
#endif
|
||||||
|
virtual ~CxImage() { DestroyFrames(); Destroy(); };
|
||||||
|
CxImage& operator = (const CxImage&);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
/** \addtogroup Initialization */ //@{
|
||||||
|
void* Create(uint32_t dwWidth, uint32_t dwHeight, uint32_t wBpp, uint32_t imagetype = 0);
|
||||||
|
bool Destroy();
|
||||||
|
bool DestroyFrames();
|
||||||
|
void Clear(uint8_t bval=0);
|
||||||
|
void Copy(const CxImage &src, bool copypixels = true, bool copyselection = true, bool copyalpha = true);
|
||||||
|
bool Transfer(CxImage &from, bool bTransferFrames = true);
|
||||||
|
bool CreateFromArray(uint8_t* pArray,uint32_t dwWidth,uint32_t dwHeight,uint32_t dwBitsperpixel, uint32_t dwBytesperline, bool bFlipImage);
|
||||||
|
bool CreateFromMatrix(uint8_t** ppMatrix,uint32_t dwWidth,uint32_t dwHeight,uint32_t dwBitsperpixel, uint32_t dwBytesperline, bool bFlipImage);
|
||||||
|
void FreeMemory(void* memblock);
|
||||||
|
|
||||||
|
uint32_t Dump(uint8_t * dst);
|
||||||
|
uint32_t UnDump(const uint8_t * src);
|
||||||
|
uint32_t DumpSize();
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
/** \addtogroup Attributes */ //@{
|
||||||
|
int32_t GetSize();
|
||||||
|
uint8_t* GetBits(uint32_t row = 0);
|
||||||
|
uint8_t GetColorType();
|
||||||
|
void* GetDIB() const;
|
||||||
|
uint32_t GetHeight() const;
|
||||||
|
uint32_t GetWidth() const;
|
||||||
|
uint32_t GetEffWidth() const;
|
||||||
|
uint32_t GetNumColors() const;
|
||||||
|
uint16_t GetBpp() const;
|
||||||
|
uint32_t GetType() const;
|
||||||
|
const char* GetLastError();
|
||||||
|
static const TCHAR* GetVersion();
|
||||||
|
static const float GetVersionNumber();
|
||||||
|
|
||||||
|
uint32_t GetFrameDelay() const;
|
||||||
|
void SetFrameDelay(uint32_t d);
|
||||||
|
|
||||||
|
void GetOffset(int32_t *x,int32_t *y);
|
||||||
|
void SetOffset(int32_t x,int32_t y);
|
||||||
|
|
||||||
|
uint8_t GetJpegQuality() const;
|
||||||
|
void SetJpegQuality(uint8_t q);
|
||||||
|
float GetJpegQualityF() const;
|
||||||
|
void SetJpegQualityF(float q);
|
||||||
|
|
||||||
|
uint8_t GetJpegScale() const;
|
||||||
|
void SetJpegScale(uint8_t q);
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_EXIF
|
||||||
|
EXIFINFO *GetExifInfo() {return &info.ExifInfo;};
|
||||||
|
bool GetExifThumbnail(const TCHAR *filename, const TCHAR *outname, int32_t imageType);
|
||||||
|
#if CXIMAGE_SUPPORT_TRANSFORMATION
|
||||||
|
bool RotateExif(int32_t orientation = 0);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int32_t GetXDPI() const;
|
||||||
|
int32_t GetYDPI() const;
|
||||||
|
void SetXDPI(int32_t dpi);
|
||||||
|
void SetYDPI(int32_t dpi);
|
||||||
|
|
||||||
|
uint32_t GetClrImportant() const;
|
||||||
|
void SetClrImportant(uint32_t ncolors = 0);
|
||||||
|
|
||||||
|
int32_t GetProgress() const;
|
||||||
|
int32_t GetEscape() const;
|
||||||
|
void SetProgress(int32_t p);
|
||||||
|
void SetEscape(int32_t i);
|
||||||
|
|
||||||
|
int32_t GetTransIndex() const;
|
||||||
|
RGBQUAD GetTransColor();
|
||||||
|
void SetTransIndex(int32_t idx);
|
||||||
|
void SetTransColor(RGBQUAD rgb);
|
||||||
|
bool IsTransparent() const;
|
||||||
|
|
||||||
|
uint32_t GetCodecOption(uint32_t imagetype = 0);
|
||||||
|
bool SetCodecOption(uint32_t opt, uint32_t imagetype = 0);
|
||||||
|
|
||||||
|
uint32_t GetFlags() const;
|
||||||
|
void SetFlags(uint32_t flags, bool bLockReservedFlags = true);
|
||||||
|
|
||||||
|
uint8_t GetDisposalMethod() const;
|
||||||
|
void SetDisposalMethod(uint8_t dm);
|
||||||
|
|
||||||
|
bool SetType(uint32_t type);
|
||||||
|
|
||||||
|
static uint32_t GetNumTypes();
|
||||||
|
static uint32_t GetTypeIdFromName(const TCHAR* ext);
|
||||||
|
static uint32_t GetTypeIdFromIndex(const uint32_t index);
|
||||||
|
static uint32_t GetTypeIndexFromId(const uint32_t id);
|
||||||
|
|
||||||
|
bool GetRetreiveAllFrames() const;
|
||||||
|
void SetRetreiveAllFrames(bool flag);
|
||||||
|
CxImage * GetFrame(int32_t nFrame) const;
|
||||||
|
|
||||||
|
//void* GetUserData() const {return info.pUserData;}
|
||||||
|
//void SetUserData(void* pUserData) {info.pUserData = pUserData;}
|
||||||
|
//@}
|
||||||
|
|
||||||
|
/** \addtogroup Palette
|
||||||
|
* These functions have no effects on RGB images and in this case the returned value is always 0.
|
||||||
|
* @{ */
|
||||||
|
bool IsGrayScale();
|
||||||
|
bool IsIndexed() const;
|
||||||
|
bool IsSamePalette(CxImage &img, bool bCheckAlpha = true);
|
||||||
|
uint32_t GetPaletteSize();
|
||||||
|
RGBQUAD* GetPalette() const;
|
||||||
|
RGBQUAD GetPaletteColor(uint8_t idx);
|
||||||
|
bool GetPaletteColor(uint8_t i, uint8_t* r, uint8_t* g, uint8_t* b);
|
||||||
|
uint8_t GetNearestIndex(RGBQUAD c);
|
||||||
|
void BlendPalette(COLORREF cr,int32_t perc);
|
||||||
|
void SetGrayPalette();
|
||||||
|
void SetPalette(uint32_t n, uint8_t *r, uint8_t *g, uint8_t *b);
|
||||||
|
void SetPalette(RGBQUAD* pPal,uint32_t nColors=256);
|
||||||
|
void SetPalette(rgb_color *rgb,uint32_t nColors=256);
|
||||||
|
void SetPaletteColor(uint8_t idx, uint8_t r, uint8_t g, uint8_t b, uint8_t alpha=0);
|
||||||
|
void SetPaletteColor(uint8_t idx, RGBQUAD c);
|
||||||
|
void SetPaletteColor(uint8_t idx, COLORREF cr);
|
||||||
|
void SwapIndex(uint8_t idx1, uint8_t idx2);
|
||||||
|
void SwapRGB2BGR();
|
||||||
|
void SetStdPalette();
|
||||||
|
//@}
|
||||||
|
|
||||||
|
/** \addtogroup Pixel */ //@{
|
||||||
|
bool IsInside(int32_t x, int32_t y);
|
||||||
|
bool IsTransparent(int32_t x,int32_t y);
|
||||||
|
bool GetTransparentMask(CxImage* iDst = 0);
|
||||||
|
RGBQUAD GetPixelColor(int32_t x,int32_t y, bool bGetAlpha = true);
|
||||||
|
uint8_t GetPixelIndex(int32_t x,int32_t y);
|
||||||
|
uint8_t GetPixelGray(int32_t x, int32_t y);
|
||||||
|
void SetPixelColor(int32_t x,int32_t y,RGBQUAD c, bool bSetAlpha = false);
|
||||||
|
void SetPixelColor(int32_t x,int32_t y,COLORREF cr);
|
||||||
|
void SetPixelIndex(int32_t x,int32_t y,uint8_t i);
|
||||||
|
void DrawLine(int32_t StartX, int32_t EndX, int32_t StartY, int32_t EndY, RGBQUAD color, bool bSetAlpha=false);
|
||||||
|
void DrawLine(int32_t StartX, int32_t EndX, int32_t StartY, int32_t EndY, COLORREF cr);
|
||||||
|
void BlendPixelColor(int32_t x,int32_t y,RGBQUAD c, float blend, bool bSetAlpha = false);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** \addtogroup Protected */ //@{
|
||||||
|
uint8_t BlindGetPixelIndex(const int32_t x,const int32_t y);
|
||||||
|
RGBQUAD BlindGetPixelColor(const int32_t x,const int32_t y, bool bGetAlpha = true);
|
||||||
|
void *BlindGetPixelPointer(const int32_t x,const int32_t y);
|
||||||
|
void BlindSetPixelColor(int32_t x,int32_t y,RGBQUAD c, bool bSetAlpha = false);
|
||||||
|
void BlindSetPixelIndex(int32_t x,int32_t y,uint8_t i);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_INTERPOLATION
|
||||||
|
/** \addtogroup Interpolation */ //@{
|
||||||
|
//overflow methods:
|
||||||
|
enum OverflowMethod {
|
||||||
|
OM_COLOR=1,
|
||||||
|
OM_BACKGROUND=2,
|
||||||
|
OM_TRANSPARENT=3,
|
||||||
|
OM_WRAP=4,
|
||||||
|
OM_REPEAT=5,
|
||||||
|
OM_MIRROR=6
|
||||||
|
};
|
||||||
|
void OverflowCoordinates(float &x, float &y, OverflowMethod const ofMethod);
|
||||||
|
void OverflowCoordinates(int32_t &x, int32_t &y, OverflowMethod const ofMethod);
|
||||||
|
RGBQUAD GetPixelColorWithOverflow(int32_t x, int32_t y, OverflowMethod const ofMethod=OM_BACKGROUND, RGBQUAD* const rplColor=0);
|
||||||
|
//interpolation methods:
|
||||||
|
enum InterpolationMethod {
|
||||||
|
IM_NEAREST_NEIGHBOUR=1,
|
||||||
|
IM_BILINEAR =2,
|
||||||
|
IM_BSPLINE =3,
|
||||||
|
IM_BICUBIC =4,
|
||||||
|
IM_BICUBIC2 =5,
|
||||||
|
IM_LANCZOS =6,
|
||||||
|
IM_BOX =7,
|
||||||
|
IM_HERMITE =8,
|
||||||
|
IM_HAMMING =9,
|
||||||
|
IM_SINC =10,
|
||||||
|
IM_BLACKMAN =11,
|
||||||
|
IM_BESSEL =12,
|
||||||
|
IM_GAUSSIAN =13,
|
||||||
|
IM_QUADRATIC =14,
|
||||||
|
IM_MITCHELL =15,
|
||||||
|
IM_CATROM =16,
|
||||||
|
IM_HANNING =17,
|
||||||
|
IM_POWER =18
|
||||||
|
};
|
||||||
|
RGBQUAD GetPixelColorInterpolated(float x,float y, InterpolationMethod const inMethod=IM_BILINEAR, OverflowMethod const ofMethod=OM_BACKGROUND, RGBQUAD* const rplColor=0);
|
||||||
|
RGBQUAD GetAreaColorInterpolated(float const xc, float const yc, float const w, float const h, InterpolationMethod const inMethod, OverflowMethod const ofMethod=OM_BACKGROUND, RGBQUAD* const rplColor=0);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** \addtogroup Protected */ //@{
|
||||||
|
void AddAveragingCont(RGBQUAD const &color, float const surf, float &rr, float &gg, float &bb, float &aa);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
/** \addtogroup Kernels */ //@{
|
||||||
|
public:
|
||||||
|
static float KernelBSpline(const float x);
|
||||||
|
static float KernelLinear(const float t);
|
||||||
|
static float KernelCubic(const float t);
|
||||||
|
static float KernelGeneralizedCubic(const float t, const float a=-1);
|
||||||
|
static float KernelLanczosSinc(const float t, const float r = 3);
|
||||||
|
static float KernelBox(const float x);
|
||||||
|
static float KernelHermite(const float x);
|
||||||
|
static float KernelHamming(const float x);
|
||||||
|
static float KernelSinc(const float x);
|
||||||
|
static float KernelBlackman(const float x);
|
||||||
|
static float KernelBessel_J1(const float x);
|
||||||
|
static float KernelBessel_P1(const float x);
|
||||||
|
static float KernelBessel_Q1(const float x);
|
||||||
|
static float KernelBessel_Order1(float x);
|
||||||
|
static float KernelBessel(const float x);
|
||||||
|
static float KernelGaussian(const float x);
|
||||||
|
static float KernelQuadratic(const float x);
|
||||||
|
static float KernelMitchell(const float x);
|
||||||
|
static float KernelCatrom(const float x);
|
||||||
|
static float KernelHanning(const float x);
|
||||||
|
static float KernelPower(const float x, const float a = 2);
|
||||||
|
//@}
|
||||||
|
#endif //CXIMAGE_SUPPORT_INTERPOLATION
|
||||||
|
|
||||||
|
/** \addtogroup Painting */ //@{
|
||||||
|
#if CXIMAGE_SUPPORT_WINDOWS
|
||||||
|
int32_t Blt(HDC pDC, int32_t x=0, int32_t y=0);
|
||||||
|
HBITMAP Draw2HBITMAP(HDC hdc, int32_t x, int32_t y, int32_t cx, int32_t cy, RECT* pClipRect, bool bSmooth);
|
||||||
|
HBITMAP MakeBitmap(HDC hdc = NULL, bool bTransparency = false);
|
||||||
|
HICON MakeIcon(HDC hdc = NULL, bool bTransparency = false);
|
||||||
|
HANDLE CopyToHandle();
|
||||||
|
bool CreateFromHANDLE(HANDLE hMem); //Windows objects (clipboard)
|
||||||
|
bool CreateFromHBITMAP(HBITMAP hbmp, HPALETTE hpal=0, bool bTransparency = false); //Windows resource
|
||||||
|
bool CreateFromHICON(HICON hico, bool bTransparency = false);
|
||||||
|
int32_t Draw(HDC hdc, int32_t x=0, int32_t y=0, int32_t cx = -1, int32_t cy = -1, RECT* pClipRect = 0, bool bSmooth = false, bool bFlipY = false);
|
||||||
|
int32_t Draw(HDC hdc, const RECT& rect, RECT* pClipRect=NULL, bool bSmooth = false, bool bFlipY = false);
|
||||||
|
int32_t Stretch(HDC hdc, int32_t xoffset, int32_t yoffset, int32_t xsize, int32_t ysize, uint32_t dwRop = SRCCOPY);
|
||||||
|
int32_t Stretch(HDC hdc, const RECT& rect, uint32_t dwRop = SRCCOPY);
|
||||||
|
int32_t Tile(HDC hdc, RECT *rc);
|
||||||
|
int32_t Draw2(HDC hdc, int32_t x=0, int32_t y=0, int32_t cx = -1, int32_t cy = -1);
|
||||||
|
int32_t Draw2(HDC hdc, const RECT& rect);
|
||||||
|
//int32_t DrawString(HDC hdc, int32_t x, int32_t y, const char* text, RGBQUAD color, const char* font, int32_t lSize=0, int32_t lWeight=400, uint8_t bItalic=0, uint8_t bUnderline=0, bool bSetAlpha=false);
|
||||||
|
int32_t DrawString(HDC hdc, int32_t x, int32_t y, const TCHAR* text, RGBQUAD color, const TCHAR* font, int32_t lSize=0, int32_t lWeight=400, uint8_t bItalic=0, uint8_t bUnderline=0, bool bSetAlpha=false);
|
||||||
|
// <VATI> extensions
|
||||||
|
int32_t DrawStringEx(HDC hdc, int32_t x, int32_t y, CXTEXTINFO *pTextType, bool bSetAlpha=false );
|
||||||
|
void InitTextInfo( CXTEXTINFO *txt );
|
||||||
|
protected:
|
||||||
|
bool IsHBITMAPAlphaValid( HBITMAP hbmp );
|
||||||
|
public:
|
||||||
|
#endif //CXIMAGE_SUPPORT_WINDOWS
|
||||||
|
//@}
|
||||||
|
|
||||||
|
// file operations
|
||||||
|
#if CXIMAGE_SUPPORT_DECODE
|
||||||
|
/** \addtogroup Decode */ //@{
|
||||||
|
#ifdef WIN32
|
||||||
|
//bool Load(LPCWSTR filename, uint32_t imagetype=0);
|
||||||
|
bool LoadResource(HRSRC hRes, uint32_t imagetype, HMODULE hModule=NULL);
|
||||||
|
#endif
|
||||||
|
// For UNICODE support: char -> TCHAR
|
||||||
|
bool Load(const TCHAR* filename, uint32_t imagetype=0);
|
||||||
|
//bool Load(const char * filename, uint32_t imagetype=0);
|
||||||
|
bool Decode(FILE * hFile, uint32_t imagetype);
|
||||||
|
bool Decode(CxFile * hFile, uint32_t imagetype);
|
||||||
|
bool Decode(uint8_t * buffer, uint32_t size, uint32_t imagetype);
|
||||||
|
|
||||||
|
bool CheckFormat(CxFile * hFile, uint32_t imagetype = 0);
|
||||||
|
bool CheckFormat(uint8_t * buffer, uint32_t size, uint32_t imagetype = 0);
|
||||||
|
//@}
|
||||||
|
#endif //CXIMAGE_SUPPORT_DECODE
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
protected:
|
||||||
|
/** \addtogroup Protected */ //@{
|
||||||
|
bool EncodeSafeCheck(CxFile *hFile);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** \addtogroup Encode */ //@{
|
||||||
|
#ifdef WIN32
|
||||||
|
//bool Save(LPCWSTR filename, uint32_t imagetype=0);
|
||||||
|
#endif
|
||||||
|
// For UNICODE support: char -> TCHAR
|
||||||
|
bool Save(const TCHAR* filename, uint32_t imagetype);
|
||||||
|
//bool Save(const char * filename, uint32_t imagetype=0);
|
||||||
|
bool Encode(FILE * hFile, uint32_t imagetype);
|
||||||
|
bool Encode(CxFile * hFile, uint32_t imagetype);
|
||||||
|
bool Encode(CxFile * hFile, CxImage ** pImages, int32_t pagecount, uint32_t imagetype);
|
||||||
|
bool Encode(FILE *hFile, CxImage ** pImages, int32_t pagecount, uint32_t imagetype);
|
||||||
|
bool Encode(uint8_t * &buffer, int32_t &size, uint32_t imagetype);
|
||||||
|
|
||||||
|
bool Encode2RGBA(CxFile *hFile, bool bFlipY = false);
|
||||||
|
bool Encode2RGBA(uint8_t * &buffer, int32_t &size, bool bFlipY = false);
|
||||||
|
//@}
|
||||||
|
#endif //CXIMAGE_SUPPORT_ENCODE
|
||||||
|
|
||||||
|
/** \addtogroup Attributes */ //@{
|
||||||
|
//misc.
|
||||||
|
bool IsValid() const;
|
||||||
|
bool IsEnabled() const;
|
||||||
|
void Enable(bool enable=true);
|
||||||
|
|
||||||
|
// frame operations
|
||||||
|
int32_t GetNumFrames() const;
|
||||||
|
int32_t GetFrame() const;
|
||||||
|
void SetFrame(int32_t nFrame);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_BASICTRANSFORMATIONS
|
||||||
|
/** \addtogroup BasicTransformations */ //@{
|
||||||
|
bool GrayScale();
|
||||||
|
bool Flip(bool bFlipSelection = false, bool bFlipAlpha = true);
|
||||||
|
bool Mirror(bool bMirrorSelection = false, bool bMirrorAlpha = true);
|
||||||
|
bool Negative();
|
||||||
|
bool RotateLeft(CxImage* iDst = NULL);
|
||||||
|
bool RotateRight(CxImage* iDst = NULL);
|
||||||
|
bool IncreaseBpp(uint32_t nbit);
|
||||||
|
//@}
|
||||||
|
#endif //CXIMAGE_SUPPORT_BASICTRANSFORMATIONS
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_TRANSFORMATION
|
||||||
|
/** \addtogroup Transformations */ //@{
|
||||||
|
// image operations
|
||||||
|
bool Rotate(float angle, CxImage* iDst = NULL);
|
||||||
|
bool Rotate2(float angle, CxImage *iDst = NULL, InterpolationMethod inMethod=IM_BILINEAR,
|
||||||
|
OverflowMethod ofMethod=OM_BACKGROUND, RGBQUAD *replColor=0,
|
||||||
|
bool const optimizeRightAngles=true, bool const bKeepOriginalSize=false);
|
||||||
|
bool Rotate180(CxImage* iDst = NULL);
|
||||||
|
bool Resample(int32_t newx, int32_t newy, int32_t mode = 1, CxImage* iDst = NULL);
|
||||||
|
bool Resample2(int32_t newx, int32_t newy, InterpolationMethod const inMethod=IM_BICUBIC2,
|
||||||
|
OverflowMethod const ofMethod=OM_REPEAT, CxImage* const iDst = NULL,
|
||||||
|
bool const disableAveraging=false);
|
||||||
|
bool DecreaseBpp(uint32_t nbit, bool errordiffusion, RGBQUAD* ppal = 0, uint32_t clrimportant = 0);
|
||||||
|
bool Dither(int32_t method = 0);
|
||||||
|
bool Crop(int32_t left, int32_t top, int32_t right, int32_t bottom, CxImage* iDst = NULL);
|
||||||
|
bool Crop(const RECT& rect, CxImage* iDst = NULL);
|
||||||
|
bool CropRotatedRectangle( int32_t topx, int32_t topy, int32_t width, int32_t height, float angle, CxImage* iDst = NULL);
|
||||||
|
bool Skew(float xgain, float ygain, int32_t xpivot=0, int32_t ypivot=0, bool bEnableInterpolation = false);
|
||||||
|
bool Expand(int32_t left, int32_t top, int32_t right, int32_t bottom, RGBQUAD canvascolor, CxImage* iDst = 0);
|
||||||
|
bool Expand(int32_t newx, int32_t newy, RGBQUAD canvascolor, CxImage* iDst = 0);
|
||||||
|
bool Thumbnail(int32_t newx, int32_t newy, RGBQUAD canvascolor, CxImage* iDst = 0);
|
||||||
|
bool CircleTransform(int32_t type,int32_t rmax=0,float Koeff=1.0f);
|
||||||
|
bool QIShrink(int32_t newx, int32_t newy, CxImage* const iDst = NULL, bool bChangeBpp = false);
|
||||||
|
|
||||||
|
//@}
|
||||||
|
#endif //CXIMAGE_SUPPORT_TRANSFORMATION
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_DSP
|
||||||
|
/** \addtogroup DSP */ //@{
|
||||||
|
bool Contour();
|
||||||
|
bool HistogramStretch(int32_t method = 0, double threshold = 0);
|
||||||
|
bool HistogramEqualize();
|
||||||
|
bool HistogramNormalize();
|
||||||
|
bool HistogramRoot();
|
||||||
|
bool HistogramLog();
|
||||||
|
int32_t Histogram(int32_t* red, int32_t* green = 0, int32_t* blue = 0, int32_t* gray = 0, int32_t colorspace = 0);
|
||||||
|
bool Jitter(int32_t radius=2);
|
||||||
|
bool Repair(float radius = 0.25f, int32_t niterations = 1, int32_t colorspace = 0);
|
||||||
|
bool Combine(CxImage* r,CxImage* g,CxImage* b,CxImage* a, int32_t colorspace = 0);
|
||||||
|
bool FFT2(CxImage* srcReal, CxImage* srcImag, CxImage* dstReal, CxImage* dstImag, int32_t direction = 1, bool bForceFFT = true, bool bMagnitude = true);
|
||||||
|
bool Noise(int32_t level);
|
||||||
|
bool Median(int32_t Ksize=3);
|
||||||
|
bool Gamma(float gamma);
|
||||||
|
bool GammaRGB(float gammaR, float gammaG, float gammaB);
|
||||||
|
bool ShiftRGB(int32_t r, int32_t g, int32_t b);
|
||||||
|
bool Threshold(uint8_t level);
|
||||||
|
bool Threshold(CxImage* pThresholdMask);
|
||||||
|
bool Threshold2(uint8_t level, bool bDirection, RGBQUAD nBkgndColor, bool bSetAlpha = false);
|
||||||
|
bool Colorize(uint8_t hue, uint8_t sat, float blend = 1.0f);
|
||||||
|
bool Light(int32_t brightness, int32_t contrast = 0);
|
||||||
|
float Mean();
|
||||||
|
bool Filter(int32_t* kernel, int32_t Ksize, int32_t Kfactor, int32_t Koffset);
|
||||||
|
bool Erode(int32_t Ksize=2);
|
||||||
|
bool Dilate(int32_t Ksize=2);
|
||||||
|
bool Edge(int32_t Ksize=2);
|
||||||
|
void HuePalette(float correction=1);
|
||||||
|
enum ImageOpType { OpAdd, OpAnd, OpXor, OpOr, OpMask, OpSrcCopy, OpDstCopy, OpSub, OpSrcBlend, OpScreen, OpAvg, OpBlendAlpha };
|
||||||
|
void Mix(CxImage & imgsrc2, ImageOpType op, int32_t lXOffset = 0, int32_t lYOffset = 0, bool bMixAlpha = false);
|
||||||
|
void MixFrom(CxImage & imagesrc2, int32_t lXOffset, int32_t lYOffset);
|
||||||
|
bool UnsharpMask(float radius = 5.0f, float amount = 0.5f, int32_t threshold = 0);
|
||||||
|
bool Lut(uint8_t* pLut);
|
||||||
|
bool Lut(uint8_t* pLutR, uint8_t* pLutG, uint8_t* pLutB, uint8_t* pLutA = 0);
|
||||||
|
bool GaussianBlur(float radius = 1.0f, CxImage* iDst = 0);
|
||||||
|
bool TextBlur(uint8_t threshold = 100, uint8_t decay = 2, uint8_t max_depth = 5, bool bBlurHorizontal = true, bool bBlurVertical = true, CxImage* iDst = 0);
|
||||||
|
bool SelectiveBlur(float radius = 1.0f, uint8_t threshold = 25, CxImage* iDst = 0);
|
||||||
|
bool Solarize(uint8_t level = 128, bool bLinkedChannels = true);
|
||||||
|
bool FloodFill(const int32_t xStart, const int32_t yStart, const RGBQUAD cFillColor, const uint8_t tolerance = 0,
|
||||||
|
uint8_t nOpacity = 255, const bool bSelectFilledArea = false, const uint8_t nSelectionLevel = 255);
|
||||||
|
bool Saturate(const int32_t saturation, const int32_t colorspace = 1);
|
||||||
|
bool ConvertColorSpace(const int32_t dstColorSpace, const int32_t srcColorSpace);
|
||||||
|
int32_t OptimalThreshold(int32_t method = 0, RECT * pBox = 0, CxImage* pContrastMask = 0);
|
||||||
|
bool AdaptiveThreshold(int32_t method = 0, int32_t nBoxSize = 64, CxImage* pContrastMask = 0, int32_t nBias = 0, float fGlobalLocalBalance = 0.5f);
|
||||||
|
bool RedEyeRemove(float strength = 0.8f);
|
||||||
|
bool Trace(RGBQUAD color_target, RGBQUAD color_trace);
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** \addtogroup Protected */ //@{
|
||||||
|
bool IsPowerof2(int32_t x);
|
||||||
|
bool FFT(int32_t dir,int32_t m,double *x,double *y);
|
||||||
|
bool DFT(int32_t dir,int32_t m,double *x1,double *y1,double *x2,double *y2);
|
||||||
|
bool RepairChannel(CxImage *ch, float radius);
|
||||||
|
// <nipper>
|
||||||
|
int32_t gen_convolve_matrix (float radius, float **cmatrix_p);
|
||||||
|
float* gen_lookup_table (float *cmatrix, int32_t cmatrix_length);
|
||||||
|
void blur_line (float *ctable, float *cmatrix, int32_t cmatrix_length, uint8_t* cur_col, uint8_t* dest_col, int32_t y, int32_t bytes);
|
||||||
|
void blur_text (uint8_t threshold, uint8_t decay, uint8_t max_depth, CxImage* iSrc, CxImage* iDst, uint8_t bytes);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** \addtogroup ColorSpace */ //@{
|
||||||
|
bool SplitRGB(CxImage* r,CxImage* g,CxImage* b);
|
||||||
|
bool SplitYUV(CxImage* y,CxImage* u,CxImage* v);
|
||||||
|
bool SplitHSL(CxImage* h,CxImage* s,CxImage* l);
|
||||||
|
bool SplitYIQ(CxImage* y,CxImage* i,CxImage* q);
|
||||||
|
bool SplitXYZ(CxImage* x,CxImage* y,CxImage* z);
|
||||||
|
bool SplitCMYK(CxImage* c,CxImage* m,CxImage* y,CxImage* k);
|
||||||
|
static RGBQUAD HSLtoRGB(COLORREF cHSLColor);
|
||||||
|
static RGBQUAD RGBtoHSL(RGBQUAD lRGBColor);
|
||||||
|
static RGBQUAD HSLtoRGB(RGBQUAD lHSLColor);
|
||||||
|
static RGBQUAD YUVtoRGB(RGBQUAD lYUVColor);
|
||||||
|
static RGBQUAD RGBtoYUV(RGBQUAD lRGBColor);
|
||||||
|
static RGBQUAD YIQtoRGB(RGBQUAD lYIQColor);
|
||||||
|
static RGBQUAD RGBtoYIQ(RGBQUAD lRGBColor);
|
||||||
|
static RGBQUAD XYZtoRGB(RGBQUAD lXYZColor);
|
||||||
|
static RGBQUAD RGBtoXYZ(RGBQUAD lRGBColor);
|
||||||
|
#endif //CXIMAGE_SUPPORT_DSP
|
||||||
|
static RGBQUAD RGBtoRGBQUAD(COLORREF cr);
|
||||||
|
static COLORREF RGBQUADtoRGB (RGBQUAD c);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
/** \addtogroup Selection */ //@{
|
||||||
|
bool SelectionIsValid();
|
||||||
|
#if CXIMAGE_SUPPORT_SELECTION
|
||||||
|
bool SelectionClear(uint8_t level = 0);
|
||||||
|
bool SelectionCreate();
|
||||||
|
bool SelectionDelete();
|
||||||
|
bool SelectionInvert();
|
||||||
|
bool SelectionMirror();
|
||||||
|
bool SelectionFlip();
|
||||||
|
bool SelectionAddRect(RECT r, uint8_t level = 255);
|
||||||
|
bool SelectionAddEllipse(RECT r, uint8_t level = 255);
|
||||||
|
bool SelectionAddPolygon(POINT *points, int32_t npoints, uint8_t level = 255);
|
||||||
|
bool SelectionAddColor(RGBQUAD c, uint8_t level = 255);
|
||||||
|
bool SelectionAddPixel(int32_t x, int32_t y, uint8_t level = 255);
|
||||||
|
bool SelectionCopy(CxImage &from);
|
||||||
|
bool SelectionIsInside(int32_t x, int32_t y);
|
||||||
|
void SelectionGetBox(RECT& r);
|
||||||
|
bool SelectionToHRGN(HRGN& region);
|
||||||
|
bool SelectionSplit(CxImage *dest);
|
||||||
|
uint8_t SelectionGet(const int32_t x,const int32_t y);
|
||||||
|
bool SelectionSet(CxImage &from);
|
||||||
|
void SelectionRebuildBox();
|
||||||
|
uint8_t* SelectionGetPointer(const int32_t x = 0,const int32_t y = 0);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** \addtogroup Protected */ //@{
|
||||||
|
bool BlindSelectionIsInside(int32_t x, int32_t y);
|
||||||
|
uint8_t BlindSelectionGet(const int32_t x,const int32_t y);
|
||||||
|
void SelectionSet(const int32_t x,const int32_t y,const uint8_t level);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
#endif //CXIMAGE_SUPPORT_SELECTION
|
||||||
|
//@}
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
/** \addtogroup Alpha */ //@{
|
||||||
|
void AlphaClear();
|
||||||
|
bool AlphaCreate();
|
||||||
|
void AlphaDelete();
|
||||||
|
void AlphaInvert();
|
||||||
|
bool AlphaMirror();
|
||||||
|
bool AlphaFlip();
|
||||||
|
bool AlphaCopy(CxImage &from);
|
||||||
|
bool AlphaSplit(CxImage *dest);
|
||||||
|
void AlphaStrip();
|
||||||
|
void AlphaSet(uint8_t level);
|
||||||
|
bool AlphaSet(CxImage &from);
|
||||||
|
void AlphaSet(const int32_t x,const int32_t y,const uint8_t level);
|
||||||
|
uint8_t AlphaGet(const int32_t x,const int32_t y);
|
||||||
|
uint8_t AlphaGetMax() const;
|
||||||
|
void AlphaSetMax(uint8_t nAlphaMax);
|
||||||
|
bool AlphaIsValid();
|
||||||
|
uint8_t* AlphaGetPointer(const int32_t x = 0,const int32_t y = 0);
|
||||||
|
bool AlphaFromTransparency();
|
||||||
|
|
||||||
|
void AlphaPaletteClear();
|
||||||
|
void AlphaPaletteEnable(bool enable=true);
|
||||||
|
bool AlphaPaletteIsEnabled();
|
||||||
|
bool AlphaPaletteIsValid();
|
||||||
|
bool AlphaPaletteSplit(CxImage *dest);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** \addtogroup Protected */ //@{
|
||||||
|
uint8_t BlindAlphaGet(const int32_t x,const int32_t y);
|
||||||
|
//@}
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
|
||||||
|
public:
|
||||||
|
#if CXIMAGE_SUPPORT_LAYERS
|
||||||
|
/** \addtogroup Layers */ //@{
|
||||||
|
bool LayerCreate(int32_t position = -1);
|
||||||
|
bool LayerDelete(int32_t position = -1);
|
||||||
|
void LayerDeleteAll();
|
||||||
|
CxImage* GetLayer(int32_t position);
|
||||||
|
CxImage* GetParent() const;
|
||||||
|
int32_t GetNumLayers() const;
|
||||||
|
int32_t LayerDrawAll(HDC hdc, int32_t x=0, int32_t y=0, int32_t cx = -1, int32_t cy = -1, RECT* pClipRect = 0, bool bSmooth = false);
|
||||||
|
int32_t LayerDrawAll(HDC hdc, const RECT& rect, RECT* pClipRect=NULL, bool bSmooth = false);
|
||||||
|
//@}
|
||||||
|
#endif //CXIMAGE_SUPPORT_LAYERS
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** \addtogroup Protected */ //@{
|
||||||
|
void Startup(uint32_t imagetype = 0);
|
||||||
|
void CopyInfo(const CxImage &src);
|
||||||
|
void Ghost(const CxImage *src);
|
||||||
|
void RGBtoBGR(uint8_t *buffer, int32_t length);
|
||||||
|
static float HueToRGB(float n1,float n2, float hue);
|
||||||
|
void Bitfield2RGB(uint8_t *src, uint32_t redmask, uint32_t greenmask, uint32_t bluemask, uint8_t bpp);
|
||||||
|
static int32_t CompareColors(const void *elem1, const void *elem2);
|
||||||
|
int16_t m_ntohs(const int16_t word);
|
||||||
|
int32_t m_ntohl(const int32_t dword);
|
||||||
|
void bihtoh(BITMAPINFOHEADER* bih);
|
||||||
|
|
||||||
|
void* pDib; //contains the header, the palette, the pixels
|
||||||
|
BITMAPINFOHEADER head; //standard header
|
||||||
|
CXIMAGEINFO info; //extended information
|
||||||
|
uint8_t* pSelection; //selected region
|
||||||
|
uint8_t* pAlpha; //alpha channel
|
||||||
|
CxImage** ppLayers; //generic layers
|
||||||
|
CxImage** ppFrames;
|
||||||
|
//@}
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // !defined(__CXIMAGE_H)
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,244 @@
|
|||||||
|
/*
|
||||||
|
* File: ximagif.h
|
||||||
|
* Purpose: GIF Image Class Loader and Writer
|
||||||
|
*/
|
||||||
|
/* ==========================================================
|
||||||
|
* CxImageGIF (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it
|
||||||
|
* For conditions of distribution and use, see copyright notice in ximage.h
|
||||||
|
*
|
||||||
|
* Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes
|
||||||
|
*
|
||||||
|
* original CImageGIF and CImageIterator implementation are:
|
||||||
|
* Copyright: (c) 1995, Alejandro Aguilar Sierra <asierra(at)servidor(dot)unam(dot)mx>
|
||||||
|
*
|
||||||
|
* 6/15/97 Randy Spann: Added GIF87a writing support
|
||||||
|
* R.Spann@ConnRiver.net
|
||||||
|
*
|
||||||
|
* DECODE.C - An LZW decoder for GIF
|
||||||
|
* Copyright (C) 1987, by Steven A. Bennett
|
||||||
|
* Copyright (C) 1994, C++ version by Alejandro Aguilar Sierra
|
||||||
|
*
|
||||||
|
* In accordance with the above, I want to credit Steve Wilhite who wrote
|
||||||
|
* the code which this is heavily inspired by...
|
||||||
|
*
|
||||||
|
* GIF and 'Graphics Interchange Format' are trademarks (tm) of
|
||||||
|
* Compuserve, Incorporated, an H&R Block Company.
|
||||||
|
*
|
||||||
|
* Release Notes: This file contains a decoder routine for GIF images
|
||||||
|
* which is similar, structurally, to the original routine by Steve Wilhite.
|
||||||
|
* It is, however, somewhat noticably faster in most cases.
|
||||||
|
*
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(__ximaGIF_h)
|
||||||
|
#define __ximaGIF_h
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_GIF
|
||||||
|
|
||||||
|
typedef int16_t code_int;
|
||||||
|
|
||||||
|
/* Various error codes used by decoder */
|
||||||
|
#define OUT_OF_MEMORY -10
|
||||||
|
#define BAD_CODE_SIZE -20
|
||||||
|
#define READ_ERROR -1
|
||||||
|
#define WRITE_ERROR -2
|
||||||
|
#define OPEN_ERROR -3
|
||||||
|
#define CREATE_ERROR -4
|
||||||
|
#define BAD_LINE_WIDTH -5
|
||||||
|
#define MAX_CODES 4095
|
||||||
|
#define GIFBUFTAM 16383
|
||||||
|
#define TRANSPARENCY_CODE 0xF9
|
||||||
|
|
||||||
|
//LZW GIF Image compression
|
||||||
|
#define MAXBITSCODES 12
|
||||||
|
#define HSIZE 5003 /* 80% occupancy */
|
||||||
|
#define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1)
|
||||||
|
#define HashTabOf(i) htab[i]
|
||||||
|
#define CodeTabOf(i) codetab[i]
|
||||||
|
|
||||||
|
|
||||||
|
class CImageIterator;
|
||||||
|
class DLL_EXP CxImageGIF: public CxImage
|
||||||
|
{
|
||||||
|
#pragma pack(1)
|
||||||
|
|
||||||
|
typedef struct tag_gifgce{
|
||||||
|
uint8_t flags; /*res:3|dispmeth:3|userinputflag:1|transpcolflag:1*/
|
||||||
|
uint16_t delaytime;
|
||||||
|
uint8_t transpcolindex;
|
||||||
|
} struct_gifgce;
|
||||||
|
|
||||||
|
typedef struct tag_dscgif{ /* Logic Screen Descriptor */
|
||||||
|
char header[6]; /* Firma and version */
|
||||||
|
uint16_t scrwidth;
|
||||||
|
uint16_t scrheight;
|
||||||
|
char pflds;
|
||||||
|
char bcindx;
|
||||||
|
char pxasrat;
|
||||||
|
} struct_dscgif;
|
||||||
|
|
||||||
|
typedef struct tag_image{ /* Image Descriptor */
|
||||||
|
uint16_t l;
|
||||||
|
uint16_t t;
|
||||||
|
uint16_t w;
|
||||||
|
uint16_t h;
|
||||||
|
uint8_t pf;
|
||||||
|
} struct_image;
|
||||||
|
|
||||||
|
typedef struct tag_TabCol{ /* Tabla de colores */
|
||||||
|
int16_t colres; /* color resolution */
|
||||||
|
int16_t sogct; /* size of global color table */
|
||||||
|
rgb_color paleta[256]; /* paleta */
|
||||||
|
} struct_TabCol;
|
||||||
|
|
||||||
|
typedef struct tag_RLE{
|
||||||
|
int32_t rl_pixel;
|
||||||
|
int32_t rl_basecode;
|
||||||
|
int32_t rl_count;
|
||||||
|
int32_t rl_table_pixel;
|
||||||
|
int32_t rl_table_max;
|
||||||
|
int32_t just_cleared;
|
||||||
|
int32_t out_bits;
|
||||||
|
int32_t out_bits_init;
|
||||||
|
int32_t out_count;
|
||||||
|
int32_t out_bump;
|
||||||
|
int32_t out_bump_init;
|
||||||
|
int32_t out_clear;
|
||||||
|
int32_t out_clear_init;
|
||||||
|
int32_t max_ocodes;
|
||||||
|
int32_t code_clear;
|
||||||
|
int32_t code_eof;
|
||||||
|
uint32_t obuf;
|
||||||
|
int32_t obits;
|
||||||
|
uint8_t oblock[256];
|
||||||
|
int32_t oblen;
|
||||||
|
} struct_RLE;
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
public:
|
||||||
|
CxImageGIF();
|
||||||
|
~CxImageGIF();
|
||||||
|
|
||||||
|
// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_GIF);}
|
||||||
|
// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_GIF);}
|
||||||
|
|
||||||
|
bool Decode(CxFile * fp);
|
||||||
|
bool Decode(FILE *fp) { CxIOFile file(fp); return Decode(&file); }
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
bool Encode(CxFile * fp);
|
||||||
|
bool Encode(CxFile * fp, CxImage ** pImages, int32_t pagecount, bool bLocalColorMap = false, bool bLocalDispMeth = false);
|
||||||
|
bool Encode(FILE *fp) { CxIOFile file(fp); return Encode(&file); }
|
||||||
|
bool Encode(FILE *fp, CxImage ** pImages, int32_t pagecount, bool bLocalColorMap = false)
|
||||||
|
{ CxIOFile file(fp); return Encode(&file, pImages, pagecount, bLocalColorMap); }
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
|
||||||
|
void SetLoops(int32_t loops);
|
||||||
|
int32_t GetLoops();
|
||||||
|
void SetComment(const char* sz_comment_in);
|
||||||
|
void GetComment(char* sz_comment_out);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool DecodeExtension(CxFile *fp);
|
||||||
|
void EncodeHeader(CxFile *fp);
|
||||||
|
void EncodeLoopExtension(CxFile *fp);
|
||||||
|
void EncodeExtension(CxFile *fp);
|
||||||
|
void EncodeBody(CxFile *fp, bool bLocalColorMap = false);
|
||||||
|
void EncodeComment(CxFile *fp);
|
||||||
|
bool EncodeRGB(CxFile *fp);
|
||||||
|
void GifMix(CxImage & imgsrc2, struct_image & imgdesc);
|
||||||
|
|
||||||
|
struct_gifgce gifgce;
|
||||||
|
|
||||||
|
int32_t curx, cury;
|
||||||
|
int32_t CountDown;
|
||||||
|
uint32_t cur_accum;
|
||||||
|
int32_t cur_bits;
|
||||||
|
int32_t interlaced, iypos, istep, iheight, ipass;
|
||||||
|
int32_t ibf;
|
||||||
|
int32_t ibfmax;
|
||||||
|
uint8_t * buf;
|
||||||
|
// Implementation
|
||||||
|
int32_t GifNextPixel ();
|
||||||
|
void Putword (int32_t w, CxFile* fp );
|
||||||
|
void compressNONE (int32_t init_bits, CxFile* outfile);
|
||||||
|
void compressLZW (int32_t init_bits, CxFile* outfile);
|
||||||
|
void output (code_int code );
|
||||||
|
void cl_hash (int32_t hsize);
|
||||||
|
void char_out (int32_t c);
|
||||||
|
void flush_char ();
|
||||||
|
int16_t init_exp(int16_t size);
|
||||||
|
int16_t get_next_code(CxFile*);
|
||||||
|
int16_t decoder(CxFile*, CImageIterator* iter, int16_t linewidth, int32_t &bad_code_count);
|
||||||
|
int32_t get_byte(CxFile*);
|
||||||
|
int32_t out_line(CImageIterator* iter, uint8_t *pixels, int32_t linelen);
|
||||||
|
int32_t get_num_frames(CxFile *f,struct_TabCol* TabColSrc,struct_dscgif* dscgif);
|
||||||
|
int32_t seek_next_image(CxFile* fp, int32_t position);
|
||||||
|
|
||||||
|
int16_t curr_size; /* The current code size */
|
||||||
|
int16_t clear; /* Value for a clear code */
|
||||||
|
int16_t ending; /* Value for a ending code */
|
||||||
|
int16_t newcodes; /* First available code */
|
||||||
|
int16_t top_slot; /* Highest code for current size */
|
||||||
|
int16_t slot; /* Last read code */
|
||||||
|
|
||||||
|
/* The following static variables are used
|
||||||
|
* for seperating out codes */
|
||||||
|
int16_t navail_bytes; /* # bytes left in block */
|
||||||
|
int16_t nbits_left; /* # bits left in current uint8_t */
|
||||||
|
uint8_t b1; /* Current uint8_t */
|
||||||
|
uint8_t * byte_buff; /* Current block */
|
||||||
|
uint8_t *pbytes; /* Pointer to next uint8_t in block */
|
||||||
|
/* The reason we have these seperated like this instead of using
|
||||||
|
* a structure like the original Wilhite code did, is because this
|
||||||
|
* stuff generally produces significantly faster code when compiled...
|
||||||
|
* This code is full of similar speedups... (For a good book on writing
|
||||||
|
* C for speed or for space optomisation, see Efficient C by Tom Plum,
|
||||||
|
* published by Plum-Hall Associates...)
|
||||||
|
*/
|
||||||
|
uint8_t * stack; /* Stack for storing pixels */
|
||||||
|
uint8_t * suffix; /* Suffix table */
|
||||||
|
uint16_t * prefix; /* Prefix linked list */
|
||||||
|
|
||||||
|
//LZW GIF Image compression routines
|
||||||
|
int32_t * htab;
|
||||||
|
uint16_t * codetab;
|
||||||
|
int32_t n_bits; /* number of bits/code */
|
||||||
|
code_int maxcode; /* maximum code, given n_bits */
|
||||||
|
code_int free_ent; /* first unused entry */
|
||||||
|
int32_t clear_flg;
|
||||||
|
int32_t g_init_bits;
|
||||||
|
CxFile* g_outfile;
|
||||||
|
int32_t ClearCode;
|
||||||
|
int32_t EOFCode;
|
||||||
|
|
||||||
|
int32_t a_count;
|
||||||
|
char * accum;
|
||||||
|
|
||||||
|
char * m_comment;
|
||||||
|
int32_t m_loops;
|
||||||
|
|
||||||
|
//RLE compression routines
|
||||||
|
void compressRLE( int32_t init_bits, CxFile* outfile);
|
||||||
|
void rle_clear(struct_RLE* rle);
|
||||||
|
void rle_flush(struct_RLE* rle);
|
||||||
|
void rle_flush_withtable(int32_t count, struct_RLE* rle);
|
||||||
|
void rle_flush_clearorrep(int32_t count, struct_RLE* rle);
|
||||||
|
void rle_flush_fromclear(int32_t count,struct_RLE* rle);
|
||||||
|
void rle_output_plain(int32_t c,struct_RLE* rle);
|
||||||
|
void rle_reset_out_clear(struct_RLE* rle);
|
||||||
|
uint32_t rle_compute_triangle_count(uint32_t count, uint32_t nrepcodes);
|
||||||
|
uint32_t rle_isqrt(uint32_t x);
|
||||||
|
void rle_write_block(struct_RLE* rle);
|
||||||
|
void rle_block_out(uint8_t c, struct_RLE* rle);
|
||||||
|
void rle_block_flush(struct_RLE* rle);
|
||||||
|
void rle_output(int32_t val, struct_RLE* rle);
|
||||||
|
void rle_output_flush(struct_RLE* rle);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,627 @@
|
|||||||
|
// xImaHist.cpp : histogram functions
|
||||||
|
/* 28/01/2004 v1.00 - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_DSP
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int32_t CxImage::Histogram(int32_t* red, int32_t* green, int32_t* blue, int32_t* gray, int32_t colorspace)
|
||||||
|
{
|
||||||
|
if (!pDib) return 0;
|
||||||
|
RGBQUAD color;
|
||||||
|
|
||||||
|
if (red) memset(red,0,256*sizeof(int32_t));
|
||||||
|
if (green) memset(green,0,256*sizeof(int32_t));
|
||||||
|
if (blue) memset(blue,0,256*sizeof(int32_t));
|
||||||
|
if (gray) memset(gray,0,256*sizeof(int32_t));
|
||||||
|
|
||||||
|
int32_t xmin,xmax,ymin,ymax;
|
||||||
|
if (pSelection){
|
||||||
|
xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;
|
||||||
|
ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;
|
||||||
|
} else {
|
||||||
|
xmin = ymin = 0;
|
||||||
|
xmax = head.biWidth; ymax=head.biHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int32_t y=ymin; y<ymax; y++){
|
||||||
|
for(int32_t x=xmin; x<xmax; x++){
|
||||||
|
#if CXIMAGE_SUPPORT_SELECTION
|
||||||
|
if (BlindSelectionIsInside(x,y))
|
||||||
|
#endif //CXIMAGE_SUPPORT_SELECTION
|
||||||
|
{
|
||||||
|
switch (colorspace){
|
||||||
|
case 1:
|
||||||
|
color = HSLtoRGB(BlindGetPixelColor(x,y));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
color = YUVtoRGB(BlindGetPixelColor(x,y));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
color = YIQtoRGB(BlindGetPixelColor(x,y));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
color = XYZtoRGB(BlindGetPixelColor(x,y));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
color = BlindGetPixelColor(x,y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (red) red[color.rgbRed]++;
|
||||||
|
if (green) green[color.rgbGreen]++;
|
||||||
|
if (blue) blue[color.rgbBlue]++;
|
||||||
|
if (gray) gray[(uint8_t)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue)]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t n=0;
|
||||||
|
for (int32_t i=0; i<256; i++){
|
||||||
|
if (red && red[i]>n) n=red[i];
|
||||||
|
if (green && green[i]>n) n=green[i];
|
||||||
|
if (blue && blue[i]>n) n=blue[i];
|
||||||
|
if (gray && gray[i]>n) n=gray[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* HistogramStretch
|
||||||
|
* \param method: 0 = luminance (default), 1 = linked channels , 2 = independent channels.
|
||||||
|
* \param threshold: minimum percentage level in the histogram to recognize it as meaningful. Range: 0.0 to 1.0; default = 0; typical = 0.005 (0.5%);
|
||||||
|
* \return true if everything is ok
|
||||||
|
* \author [dave] and [nipper]; changes [DP]
|
||||||
|
*/
|
||||||
|
bool CxImage::HistogramStretch(int32_t method, double threshold)
|
||||||
|
{
|
||||||
|
if (!pDib) return false;
|
||||||
|
|
||||||
|
double dbScaler = 50.0/head.biHeight;
|
||||||
|
int32_t x,y;
|
||||||
|
|
||||||
|
if ((head.biBitCount==8) && IsGrayScale()){
|
||||||
|
|
||||||
|
double p[256];
|
||||||
|
memset(p, 0, 256*sizeof(double));
|
||||||
|
for (y=0; y<head.biHeight; y++)
|
||||||
|
{
|
||||||
|
info.nProgress = (int32_t)(y*dbScaler);
|
||||||
|
if (info.nEscape) break;
|
||||||
|
for (x=0; x<head.biWidth; x++) {
|
||||||
|
p[BlindGetPixelIndex(x, y)]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double maxh = 0;
|
||||||
|
for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];
|
||||||
|
threshold *= maxh;
|
||||||
|
int32_t minc = 0;
|
||||||
|
while (minc<255 && p[minc]<=threshold) minc++;
|
||||||
|
int32_t maxc = 255;
|
||||||
|
while (maxc>0 && p[maxc]<=threshold) maxc--;
|
||||||
|
|
||||||
|
if (minc == 0 && maxc == 255) return true;
|
||||||
|
if (minc >= maxc) return true;
|
||||||
|
|
||||||
|
// calculate LUT
|
||||||
|
uint8_t lut[256];
|
||||||
|
for (x = 0; x <256; x++){
|
||||||
|
lut[x] = (uint8_t)max(0,min(255,(255 * (x - minc) / (maxc - minc))));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (y=0; y<head.biHeight; y++) {
|
||||||
|
if (info.nEscape) break;
|
||||||
|
info.nProgress = (int32_t)(50.0+y*dbScaler);
|
||||||
|
for (x=0; x<head.biWidth; x++)
|
||||||
|
{
|
||||||
|
BlindSetPixelIndex(x, y, lut[BlindGetPixelIndex(x, y)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch(method){
|
||||||
|
case 1:
|
||||||
|
{ // <nipper>
|
||||||
|
double p[256];
|
||||||
|
memset(p, 0, 256*sizeof(double));
|
||||||
|
for (y=0; y<head.biHeight; y++)
|
||||||
|
{
|
||||||
|
info.nProgress = (int32_t)(y*dbScaler);
|
||||||
|
if (info.nEscape) break;
|
||||||
|
for (x=0; x<head.biWidth; x++) {
|
||||||
|
RGBQUAD color = BlindGetPixelColor(x, y);
|
||||||
|
p[color.rgbRed]++;
|
||||||
|
p[color.rgbBlue]++;
|
||||||
|
p[color.rgbGreen]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
double maxh = 0;
|
||||||
|
for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];
|
||||||
|
threshold *= maxh;
|
||||||
|
int32_t minc = 0;
|
||||||
|
while (minc<255 && p[minc]<=threshold) minc++;
|
||||||
|
int32_t maxc = 255;
|
||||||
|
while (maxc>0 && p[maxc]<=threshold) maxc--;
|
||||||
|
|
||||||
|
if (minc == 0 && maxc == 255) return true;
|
||||||
|
if (minc >= maxc) return true;
|
||||||
|
|
||||||
|
// calculate LUT
|
||||||
|
uint8_t lut[256];
|
||||||
|
for (x = 0; x <256; x++){
|
||||||
|
lut[x] = (uint8_t)max(0,min(255,(255 * (x - minc) / (maxc - minc))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalize image
|
||||||
|
for (y=0; y<head.biHeight; y++) {
|
||||||
|
if (info.nEscape) break;
|
||||||
|
info.nProgress = (int32_t)(50.0+y*dbScaler);
|
||||||
|
|
||||||
|
for (x=0; x<head.biWidth; x++)
|
||||||
|
{
|
||||||
|
RGBQUAD color = BlindGetPixelColor(x, y);
|
||||||
|
|
||||||
|
color.rgbRed = lut[color.rgbRed];
|
||||||
|
color.rgbBlue = lut[color.rgbBlue];
|
||||||
|
color.rgbGreen = lut[color.rgbGreen];
|
||||||
|
|
||||||
|
BlindSetPixelColor(x, y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
{ // <nipper>
|
||||||
|
double pR[256];
|
||||||
|
memset(pR, 0, 256*sizeof(double));
|
||||||
|
double pG[256];
|
||||||
|
memset(pG, 0, 256*sizeof(double));
|
||||||
|
double pB[256];
|
||||||
|
memset(pB, 0, 256*sizeof(double));
|
||||||
|
for (y=0; y<head.biHeight; y++)
|
||||||
|
{
|
||||||
|
info.nProgress = (int32_t)(y*dbScaler);
|
||||||
|
if (info.nEscape) break;
|
||||||
|
for (int32_t x=0; x<head.biWidth; x++) {
|
||||||
|
RGBQUAD color = BlindGetPixelColor(x, y);
|
||||||
|
pR[color.rgbRed]++;
|
||||||
|
pB[color.rgbBlue]++;
|
||||||
|
pG[color.rgbGreen]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double maxh = 0;
|
||||||
|
for (y=0; y<255; y++) if (maxh < pR[y]) maxh = pR[y];
|
||||||
|
double threshold2 = threshold*maxh;
|
||||||
|
int32_t minR = 0;
|
||||||
|
while (minR<255 && pR[minR]<=threshold2) minR++;
|
||||||
|
int32_t maxR = 255;
|
||||||
|
while (maxR>0 && pR[maxR]<=threshold2) maxR--;
|
||||||
|
|
||||||
|
maxh = 0;
|
||||||
|
for (y=0; y<255; y++) if (maxh < pG[y]) maxh = pG[y];
|
||||||
|
threshold2 = threshold*maxh;
|
||||||
|
int32_t minG = 0;
|
||||||
|
while (minG<255 && pG[minG]<=threshold2) minG++;
|
||||||
|
int32_t maxG = 255;
|
||||||
|
while (maxG>0 && pG[maxG]<=threshold2) maxG--;
|
||||||
|
|
||||||
|
maxh = 0;
|
||||||
|
for (y=0; y<255; y++) if (maxh < pB[y]) maxh = pB[y];
|
||||||
|
threshold2 = threshold*maxh;
|
||||||
|
int32_t minB = 0;
|
||||||
|
while (minB<255 && pB[minB]<=threshold2) minB++;
|
||||||
|
int32_t maxB = 255;
|
||||||
|
while (maxB>0 && pB[maxB]<=threshold2) maxB--;
|
||||||
|
|
||||||
|
if (minR == 0 && maxR == 255 && minG == 0 && maxG == 255 && minB == 0 && maxB == 255)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// calculate LUT
|
||||||
|
uint8_t lutR[256];
|
||||||
|
uint8_t range = maxR - minR;
|
||||||
|
if (range != 0) {
|
||||||
|
for (x = 0; x <256; x++){
|
||||||
|
lutR[x] = (uint8_t)max(0,min(255,(255 * (x - minR) / range)));
|
||||||
|
}
|
||||||
|
} else lutR[minR] = minR;
|
||||||
|
|
||||||
|
uint8_t lutG[256];
|
||||||
|
range = maxG - minG;
|
||||||
|
if (range != 0) {
|
||||||
|
for (x = 0; x <256; x++){
|
||||||
|
lutG[x] = (uint8_t)max(0,min(255,(255 * (x - minG) / range)));
|
||||||
|
}
|
||||||
|
} else lutG[minG] = minG;
|
||||||
|
|
||||||
|
uint8_t lutB[256];
|
||||||
|
range = maxB - minB;
|
||||||
|
if (range != 0) {
|
||||||
|
for (x = 0; x <256; x++){
|
||||||
|
lutB[x] = (uint8_t)max(0,min(255,(255 * (x - minB) / range)));
|
||||||
|
}
|
||||||
|
} else lutB[minB] = minB;
|
||||||
|
|
||||||
|
// normalize image
|
||||||
|
for (y=0; y<head.biHeight; y++)
|
||||||
|
{
|
||||||
|
info.nProgress = (int32_t)(50.0+y*dbScaler);
|
||||||
|
if (info.nEscape) break;
|
||||||
|
|
||||||
|
for (x=0; x<head.biWidth; x++)
|
||||||
|
{
|
||||||
|
RGBQUAD color = BlindGetPixelColor(x, y);
|
||||||
|
|
||||||
|
color.rgbRed = lutR[color.rgbRed];
|
||||||
|
color.rgbBlue = lutB[color.rgbBlue];
|
||||||
|
color.rgbGreen = lutG[color.rgbGreen];
|
||||||
|
|
||||||
|
BlindSetPixelColor(x, y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{ // <dave>
|
||||||
|
double p[256];
|
||||||
|
memset(p, 0, 256*sizeof(double));
|
||||||
|
for (y=0; y<head.biHeight; y++)
|
||||||
|
{
|
||||||
|
info.nProgress = (int32_t)(y*dbScaler);
|
||||||
|
if (info.nEscape) break;
|
||||||
|
for (x=0; x<head.biWidth; x++) {
|
||||||
|
RGBQUAD color = BlindGetPixelColor(x, y);
|
||||||
|
p[RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue)]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double maxh = 0;
|
||||||
|
for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];
|
||||||
|
threshold *= maxh;
|
||||||
|
int32_t minc = 0;
|
||||||
|
while (minc<255 && p[minc]<=threshold) minc++;
|
||||||
|
int32_t maxc = 255;
|
||||||
|
while (maxc>0 && p[maxc]<=threshold) maxc--;
|
||||||
|
|
||||||
|
if (minc == 0 && maxc == 255) return true;
|
||||||
|
if (minc >= maxc) return true;
|
||||||
|
|
||||||
|
// calculate LUT
|
||||||
|
uint8_t lut[256];
|
||||||
|
for (x = 0; x <256; x++){
|
||||||
|
lut[x] = (uint8_t)max(0,min(255,(255 * (x - minc) / (maxc - minc))));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(y=0; y<head.biHeight; y++){
|
||||||
|
info.nProgress = (int32_t)(50.0+y*dbScaler);
|
||||||
|
if (info.nEscape) break;
|
||||||
|
for(x=0; x<head.biWidth; x++){
|
||||||
|
|
||||||
|
RGBQUAD color = BlindGetPixelColor( x, y );
|
||||||
|
RGBQUAD yuvClr = RGBtoYUV(color);
|
||||||
|
yuvClr.rgbRed = lut[yuvClr.rgbRed];
|
||||||
|
color = YUVtoRGB(yuvClr);
|
||||||
|
BlindSetPixelColor( x, y, color );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// HistogramEqualize function by <dave> : dave(at)posortho(dot)com
|
||||||
|
bool CxImage::HistogramEqualize()
|
||||||
|
{
|
||||||
|
if (!pDib) return false;
|
||||||
|
|
||||||
|
int32_t histogram[256];
|
||||||
|
int32_t map[256];
|
||||||
|
int32_t equalize_map[256];
|
||||||
|
int32_t x, y, i, j;
|
||||||
|
RGBQUAD color;
|
||||||
|
RGBQUAD yuvClr;
|
||||||
|
uint32_t YVal, high, low;
|
||||||
|
|
||||||
|
memset( &histogram, 0, sizeof(int32_t) * 256 );
|
||||||
|
memset( &map, 0, sizeof(int32_t) * 256 );
|
||||||
|
memset( &equalize_map, 0, sizeof(int32_t) * 256 );
|
||||||
|
|
||||||
|
// form histogram
|
||||||
|
for(y=0; y < head.biHeight; y++){
|
||||||
|
info.nProgress = (int32_t)(50*y/head.biHeight);
|
||||||
|
if (info.nEscape) break;
|
||||||
|
for(x=0; x < head.biWidth; x++){
|
||||||
|
color = BlindGetPixelColor( x, y );
|
||||||
|
YVal = (uint32_t)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
|
||||||
|
histogram[YVal]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// integrate the histogram to get the equalization map.
|
||||||
|
j = 0;
|
||||||
|
for(i=0; i <= 255; i++){
|
||||||
|
j += histogram[i];
|
||||||
|
map[i] = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
// equalize
|
||||||
|
low = map[0];
|
||||||
|
high = map[255];
|
||||||
|
if (low == high) return false;
|
||||||
|
for( i = 0; i <= 255; i++ ){
|
||||||
|
equalize_map[i] = (uint32_t)((((double)( map[i] - low ) ) * 255) / ( high - low ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// stretch the histogram
|
||||||
|
if(head.biClrUsed == 0){ // No Palette
|
||||||
|
for( y = 0; y < head.biHeight; y++ ){
|
||||||
|
info.nProgress = (int32_t)(50+50*y/head.biHeight);
|
||||||
|
if (info.nEscape) break;
|
||||||
|
for( x = 0; x < head.biWidth; x++ ){
|
||||||
|
|
||||||
|
color = BlindGetPixelColor( x, y );
|
||||||
|
yuvClr = RGBtoYUV(color);
|
||||||
|
|
||||||
|
yuvClr.rgbRed = (uint8_t)equalize_map[yuvClr.rgbRed];
|
||||||
|
|
||||||
|
color = YUVtoRGB(yuvClr);
|
||||||
|
BlindSetPixelColor( x, y, color );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // Palette
|
||||||
|
for( i = 0; i < (int32_t)head.biClrUsed; i++ ){
|
||||||
|
|
||||||
|
color = GetPaletteColor((uint8_t)i);
|
||||||
|
yuvClr = RGBtoYUV(color);
|
||||||
|
|
||||||
|
yuvClr.rgbRed = (uint8_t)equalize_map[yuvClr.rgbRed];
|
||||||
|
|
||||||
|
color = YUVtoRGB(yuvClr);
|
||||||
|
SetPaletteColor( (uint8_t)i, color );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// HistogramNormalize function by <dave> : dave(at)posortho(dot)com
|
||||||
|
bool CxImage::HistogramNormalize()
|
||||||
|
{
|
||||||
|
if (!pDib) return false;
|
||||||
|
|
||||||
|
int32_t histogram[256];
|
||||||
|
int32_t threshold_intensity, intense;
|
||||||
|
int32_t x, y, i;
|
||||||
|
uint32_t normalize_map[256];
|
||||||
|
uint32_t high, low, YVal;
|
||||||
|
|
||||||
|
RGBQUAD color;
|
||||||
|
RGBQUAD yuvClr;
|
||||||
|
|
||||||
|
memset( &histogram, 0, sizeof( int32_t ) * 256 );
|
||||||
|
memset( &normalize_map, 0, sizeof( uint32_t ) * 256 );
|
||||||
|
|
||||||
|
// form histogram
|
||||||
|
for(y=0; y < head.biHeight; y++){
|
||||||
|
info.nProgress = (int32_t)(50*y/head.biHeight);
|
||||||
|
if (info.nEscape) break;
|
||||||
|
for(x=0; x < head.biWidth; x++){
|
||||||
|
color = BlindGetPixelColor( x, y );
|
||||||
|
YVal = (uint32_t)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
|
||||||
|
histogram[YVal]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// find histogram boundaries by locating the 1 percent levels
|
||||||
|
threshold_intensity = ( head.biWidth * head.biHeight) / 100;
|
||||||
|
|
||||||
|
intense = 0;
|
||||||
|
for( low = 0; low < 255; low++ ){
|
||||||
|
intense += histogram[low];
|
||||||
|
if( intense > threshold_intensity ) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
intense = 0;
|
||||||
|
for( high = 255; high != 0; high--){
|
||||||
|
intense += histogram[ high ];
|
||||||
|
if( intense > threshold_intensity ) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( low == high ){
|
||||||
|
// Unreasonable contrast; use zero threshold to determine boundaries.
|
||||||
|
threshold_intensity = 0;
|
||||||
|
intense = 0;
|
||||||
|
for( low = 0; low < 255; low++){
|
||||||
|
intense += histogram[low];
|
||||||
|
if( intense > threshold_intensity ) break;
|
||||||
|
}
|
||||||
|
intense = 0;
|
||||||
|
for( high = 255; high != 0; high-- ){
|
||||||
|
intense += histogram [high ];
|
||||||
|
if( intense > threshold_intensity ) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( low == high ) return false; // zero span bound
|
||||||
|
|
||||||
|
// Stretch the histogram to create the normalized image mapping.
|
||||||
|
for(i = 0; i <= 255; i++){
|
||||||
|
if ( i < (int32_t) low ){
|
||||||
|
normalize_map[i] = 0;
|
||||||
|
} else {
|
||||||
|
if(i > (int32_t) high)
|
||||||
|
normalize_map[i] = 255;
|
||||||
|
else
|
||||||
|
normalize_map[i] = ( 255 - 1) * ( i - low) / ( high - low );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize
|
||||||
|
if( head.biClrUsed == 0 ){
|
||||||
|
for( y = 0; y < head.biHeight; y++ ){
|
||||||
|
info.nProgress = (int32_t)(50+50*y/head.biHeight);
|
||||||
|
if (info.nEscape) break;
|
||||||
|
for( x = 0; x < head.biWidth; x++ ){
|
||||||
|
|
||||||
|
color = BlindGetPixelColor( x, y );
|
||||||
|
yuvClr = RGBtoYUV( color );
|
||||||
|
|
||||||
|
yuvClr.rgbRed = (uint8_t)normalize_map[yuvClr.rgbRed];
|
||||||
|
|
||||||
|
color = YUVtoRGB( yuvClr );
|
||||||
|
BlindSetPixelColor( x, y, color );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(i = 0; i < (int32_t)head.biClrUsed; i++){
|
||||||
|
|
||||||
|
color = GetPaletteColor( (uint8_t)i );
|
||||||
|
yuvClr = RGBtoYUV( color );
|
||||||
|
|
||||||
|
yuvClr.rgbRed = (uint8_t)normalize_map[yuvClr.rgbRed];
|
||||||
|
|
||||||
|
color = YUVtoRGB( yuvClr );
|
||||||
|
SetPaletteColor( (uint8_t)i, color );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// HistogramLog function by <dave> : dave(at)posortho(dot)com
|
||||||
|
bool CxImage::HistogramLog()
|
||||||
|
{
|
||||||
|
if (!pDib) return false;
|
||||||
|
|
||||||
|
//q(i,j) = 255/log(1 + |high|) * log(1 + |p(i,j)|);
|
||||||
|
int32_t x, y, i;
|
||||||
|
RGBQUAD color;
|
||||||
|
RGBQUAD yuvClr;
|
||||||
|
|
||||||
|
uint32_t YVal, high = 1;
|
||||||
|
|
||||||
|
// Find Highest Luminance Value in the Image
|
||||||
|
if( head.biClrUsed == 0 ){ // No Palette
|
||||||
|
for(y=0; y < head.biHeight; y++){
|
||||||
|
info.nProgress = (int32_t)(50*y/head.biHeight);
|
||||||
|
if (info.nEscape) break;
|
||||||
|
for(x=0; x < head.biWidth; x++){
|
||||||
|
color = BlindGetPixelColor( x, y );
|
||||||
|
YVal = (uint32_t)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
|
||||||
|
if (YVal > high ) high = YVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // Palette
|
||||||
|
for(i = 0; i < (int32_t)head.biClrUsed; i++){
|
||||||
|
color = GetPaletteColor((uint8_t)i);
|
||||||
|
YVal = (uint32_t)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
|
||||||
|
if (YVal > high ) high = YVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logarithm Operator
|
||||||
|
double k = 255.0 / ::log( 1.0 + (double)high );
|
||||||
|
if( head.biClrUsed == 0 ){
|
||||||
|
for( y = 0; y < head.biHeight; y++ ){
|
||||||
|
info.nProgress = (int32_t)(50+50*y/head.biHeight);
|
||||||
|
if (info.nEscape) break;
|
||||||
|
for( x = 0; x < head.biWidth; x++ ){
|
||||||
|
|
||||||
|
color = BlindGetPixelColor( x, y );
|
||||||
|
yuvClr = RGBtoYUV( color );
|
||||||
|
|
||||||
|
yuvClr.rgbRed = (uint8_t)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) );
|
||||||
|
|
||||||
|
color = YUVtoRGB( yuvClr );
|
||||||
|
BlindSetPixelColor( x, y, color );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(i = 0; i < (int32_t)head.biClrUsed; i++){
|
||||||
|
|
||||||
|
color = GetPaletteColor( (uint8_t)i );
|
||||||
|
yuvClr = RGBtoYUV( color );
|
||||||
|
|
||||||
|
yuvClr.rgbRed = (uint8_t)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) );
|
||||||
|
|
||||||
|
color = YUVtoRGB( yuvClr );
|
||||||
|
SetPaletteColor( (uint8_t)i, color );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// HistogramRoot function by <dave> : dave(at)posortho(dot)com
|
||||||
|
bool CxImage::HistogramRoot()
|
||||||
|
{
|
||||||
|
if (!pDib) return false;
|
||||||
|
//q(i,j) = sqrt(|p(i,j)|);
|
||||||
|
|
||||||
|
int32_t x, y, i;
|
||||||
|
RGBQUAD color;
|
||||||
|
RGBQUAD yuvClr;
|
||||||
|
double dtmp;
|
||||||
|
uint32_t YVal, high = 1;
|
||||||
|
|
||||||
|
// Find Highest Luminance Value in the Image
|
||||||
|
if( head.biClrUsed == 0 ){ // No Palette
|
||||||
|
for(y=0; y < head.biHeight; y++){
|
||||||
|
info.nProgress = (int32_t)(50*y/head.biHeight);
|
||||||
|
if (info.nEscape) break;
|
||||||
|
for(x=0; x < head.biWidth; x++){
|
||||||
|
color = BlindGetPixelColor( x, y );
|
||||||
|
YVal = (uint32_t)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
|
||||||
|
if (YVal > high ) high = YVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // Palette
|
||||||
|
for(i = 0; i < (int32_t)head.biClrUsed; i++){
|
||||||
|
color = GetPaletteColor((uint8_t)i);
|
||||||
|
YVal = (uint32_t)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
|
||||||
|
if (YVal > high ) high = YVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Root Operator
|
||||||
|
double k = 256.0 / ::sqrt( 1.0 + (double)high );
|
||||||
|
if( head.biClrUsed == 0 ){
|
||||||
|
for( y = 0; y < head.biHeight; y++ ){
|
||||||
|
info.nProgress = (int32_t)(50+50*y/head.biHeight);
|
||||||
|
if (info.nEscape) break;
|
||||||
|
for( x = 0; x < head.biWidth; x++ ){
|
||||||
|
|
||||||
|
color = BlindGetPixelColor( x, y );
|
||||||
|
yuvClr = RGBtoYUV( color );
|
||||||
|
|
||||||
|
dtmp = k * ::sqrt( (double)yuvClr.rgbRed );
|
||||||
|
if ( dtmp > 255.0 ) dtmp = 255.0;
|
||||||
|
if ( dtmp < 0 ) dtmp = 0;
|
||||||
|
yuvClr.rgbRed = (uint8_t)dtmp;
|
||||||
|
|
||||||
|
color = YUVtoRGB( yuvClr );
|
||||||
|
BlindSetPixelColor( x, y, color );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(i = 0; i < (int32_t)head.biClrUsed; i++){
|
||||||
|
|
||||||
|
color = GetPaletteColor( (uint8_t)i );
|
||||||
|
yuvClr = RGBtoYUV( color );
|
||||||
|
|
||||||
|
dtmp = k * ::sqrt( (double)yuvClr.rgbRed );
|
||||||
|
if ( dtmp > 255.0 ) dtmp = 255.0;
|
||||||
|
if ( dtmp < 0 ) dtmp = 0;
|
||||||
|
yuvClr.rgbRed = (uint8_t)dtmp;
|
||||||
|
|
||||||
|
color = YUVtoRGB( yuvClr );
|
||||||
|
SetPaletteColor( (uint8_t)i, color );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,470 @@
|
|||||||
|
/*
|
||||||
|
* File: ximaico.cpp
|
||||||
|
* Purpose: Platform Independent ICON Image Class Loader and Writer (MS version)
|
||||||
|
* 07/Aug/2001 Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximaico.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ICO
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageICO::Decode(CxFile *hFile)
|
||||||
|
{
|
||||||
|
if (hFile==NULL) return false;
|
||||||
|
|
||||||
|
uint32_t off = hFile->Tell(); //<yuandi>
|
||||||
|
int32_t page=info.nFrame; //internal icon structure indexes
|
||||||
|
|
||||||
|
// read the first part of the header
|
||||||
|
ICONHEADER icon_header;
|
||||||
|
hFile->Read(&icon_header,sizeof(ICONHEADER),1);
|
||||||
|
|
||||||
|
icon_header.idType = m_ntohs(icon_header.idType);
|
||||||
|
icon_header.idCount = m_ntohs(icon_header.idCount);
|
||||||
|
|
||||||
|
// check if it's an icon or a cursor
|
||||||
|
if ((icon_header.idReserved == 0) && ((icon_header.idType == 1)||(icon_header.idType == 2))) {
|
||||||
|
|
||||||
|
info.nNumFrames = icon_header.idCount;
|
||||||
|
|
||||||
|
// load the icon descriptions
|
||||||
|
ICONDIRENTRY *icon_list = (ICONDIRENTRY *)malloc(icon_header.idCount * sizeof(ICONDIRENTRY));
|
||||||
|
int32_t c;
|
||||||
|
for (c = 0; c < icon_header.idCount; c++) {
|
||||||
|
hFile->Read(icon_list + c, sizeof(ICONDIRENTRY), 1);
|
||||||
|
|
||||||
|
icon_list[c].wPlanes = m_ntohs(icon_list[c].wPlanes);
|
||||||
|
icon_list[c].wBitCount = m_ntohs(icon_list[c].wBitCount);
|
||||||
|
icon_list[c].dwBytesInRes = m_ntohl(icon_list[c].dwBytesInRes);
|
||||||
|
icon_list[c].dwImageOffset = m_ntohl(icon_list[c].dwImageOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((page>=0)&&(page<icon_header.idCount)){
|
||||||
|
|
||||||
|
if (info.nEscape == -1) {
|
||||||
|
// Return output dimensions only
|
||||||
|
head.biWidth = icon_list[page].bWidth;
|
||||||
|
head.biHeight = icon_list[page].bHeight;
|
||||||
|
#if CXIMAGE_SUPPORT_PNG
|
||||||
|
if (head.biWidth==0 && head.biHeight==0)
|
||||||
|
{ // Vista icon support
|
||||||
|
hFile->Seek(off + icon_list[page].dwImageOffset, SEEK_SET);
|
||||||
|
CxImage png;
|
||||||
|
png.SetEscape(-1);
|
||||||
|
if (png.Decode(hFile,CXIMAGE_FORMAT_PNG)){
|
||||||
|
Transfer(png);
|
||||||
|
info.nNumFrames = icon_header.idCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif //CXIMAGE_SUPPORT_PNG
|
||||||
|
free(icon_list);
|
||||||
|
info.dwType = CXIMAGE_FORMAT_ICO;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the bit count for the colors in the icon <CoreyRLucier>
|
||||||
|
BITMAPINFOHEADER bih;
|
||||||
|
hFile->Seek(off + icon_list[page].dwImageOffset, SEEK_SET);
|
||||||
|
|
||||||
|
if (icon_list[page].bWidth==0 && icon_list[page].bHeight==0)
|
||||||
|
{ // Vista icon support
|
||||||
|
#if CXIMAGE_SUPPORT_PNG
|
||||||
|
CxImage png;
|
||||||
|
if (png.Decode(hFile,CXIMAGE_FORMAT_PNG)){
|
||||||
|
Transfer(png);
|
||||||
|
info.nNumFrames = icon_header.idCount;
|
||||||
|
}
|
||||||
|
SetType(CXIMAGE_FORMAT_ICO);
|
||||||
|
#endif //CXIMAGE_SUPPORT_PNG
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // standard icon
|
||||||
|
hFile->Read(&bih,sizeof(BITMAPINFOHEADER),1);
|
||||||
|
|
||||||
|
bihtoh(&bih);
|
||||||
|
|
||||||
|
c = bih.biBitCount;
|
||||||
|
|
||||||
|
// allocate memory for one icon
|
||||||
|
Create(icon_list[page].bWidth,icon_list[page].bHeight, c, CXIMAGE_FORMAT_ICO); //image creation
|
||||||
|
|
||||||
|
// read the palette
|
||||||
|
RGBQUAD pal[256];
|
||||||
|
if (bih.biClrUsed)
|
||||||
|
hFile->Read(pal,bih.biClrUsed*sizeof(RGBQUAD), 1);
|
||||||
|
else
|
||||||
|
hFile->Read(pal,head.biClrUsed*sizeof(RGBQUAD), 1);
|
||||||
|
|
||||||
|
SetPalette(pal,head.biClrUsed); //palette assign
|
||||||
|
|
||||||
|
//read the icon
|
||||||
|
if (c<=24){
|
||||||
|
hFile->Read(info.pImage, head.biSizeImage, 1);
|
||||||
|
} else { // 32 bit icon
|
||||||
|
uint8_t* buf=(uint8_t*)malloc(4*head.biHeight*head.biWidth);
|
||||||
|
uint8_t* src = buf;
|
||||||
|
hFile->Read(buf, 4*head.biHeight*head.biWidth, 1);
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (!AlphaIsValid()) AlphaCreate();
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
for (int32_t y = 0; y < head.biHeight; y++) {
|
||||||
|
uint8_t* dst = GetBits(y);
|
||||||
|
for(int32_t x=0;x<head.biWidth;x++){
|
||||||
|
*dst++=src[0];
|
||||||
|
*dst++=src[1];
|
||||||
|
*dst++=src[2];
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
AlphaSet(x,y,src[3]);
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
src+=4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
// apply the AND and XOR masks
|
||||||
|
int32_t maskwdt = ((head.biWidth+31) / 32) * 4; //line width of AND mask (always 1 Bpp)
|
||||||
|
int32_t masksize = head.biHeight * maskwdt; //size of mask
|
||||||
|
uint8_t *mask = (uint8_t *)malloc(masksize);
|
||||||
|
if (hFile->Read(mask, masksize, 1)){
|
||||||
|
|
||||||
|
bool bGoodMask=false;
|
||||||
|
for (int32_t im=0;im<masksize;im++){
|
||||||
|
if (mask[im]!=255){
|
||||||
|
bGoodMask=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bGoodMask){
|
||||||
|
int32_t x,y;
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
bool bNeedAlpha = false;
|
||||||
|
if (!AlphaIsValid()){
|
||||||
|
AlphaCreate();
|
||||||
|
} else {
|
||||||
|
bNeedAlpha=true; //32bit icon
|
||||||
|
}
|
||||||
|
for (y = 0; y < head.biHeight; y++) {
|
||||||
|
for (x = 0; x < head.biWidth; x++) {
|
||||||
|
if (((mask[y*maskwdt+(x>>3)]>>(7-x%8))&0x01)){
|
||||||
|
AlphaSet(x,y,0);
|
||||||
|
bNeedAlpha=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!bNeedAlpha) AlphaDelete();
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
|
||||||
|
//check if there is only one transparent color
|
||||||
|
RGBQUAD cc,ct;
|
||||||
|
int32_t nTransColors=0;
|
||||||
|
int32_t nTransIndex=0;
|
||||||
|
for (y = 0; y < head.biHeight; y++){
|
||||||
|
for (x = 0; x < head.biWidth; x++){
|
||||||
|
if (((mask[y*maskwdt+(x>>3)] >> (7-x%8)) & 0x01)){
|
||||||
|
cc = GetPixelColor(x,y,false);
|
||||||
|
if (nTransColors==0){
|
||||||
|
nTransIndex = GetPixelIndex(x,y);
|
||||||
|
nTransColors++;
|
||||||
|
ct = cc;
|
||||||
|
} else {
|
||||||
|
if (memcmp(&cc, &ct, sizeof(RGBQUAD)) != 0){
|
||||||
|
nTransColors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nTransColors==1 && c<=8){
|
||||||
|
SetTransColor(ct);
|
||||||
|
SetTransIndex(nTransIndex);
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
AlphaDelete(); //because we have a unique transparent color in the image
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
}
|
||||||
|
|
||||||
|
// <vho> - Transparency support w/o Alpha support
|
||||||
|
if (c <= 8){ // only for icons with less than 256 colors (XP icons need alpha).
|
||||||
|
|
||||||
|
// find a color index, which is not used in the image
|
||||||
|
// it is almost sure to find one, bcs. nobody uses all possible colors for an icon
|
||||||
|
|
||||||
|
uint8_t colorsUsed[256];
|
||||||
|
memset(colorsUsed, 0, sizeof(colorsUsed));
|
||||||
|
|
||||||
|
for (y = 0; y < head.biHeight; y++){
|
||||||
|
for (x = 0; x < head.biWidth; x++){
|
||||||
|
colorsUsed[BlindGetPixelIndex(x,y)] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t iTransIdx = -1;
|
||||||
|
for (x = (int32_t)(head.biClrUsed-1); x>=0 ; x--){
|
||||||
|
if (colorsUsed[x] == 0){
|
||||||
|
iTransIdx = x; // this one is not in use. we may use it as transparent color
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go thru image and set unused color as transparent index if needed
|
||||||
|
if (iTransIdx >= 0){
|
||||||
|
bool bNeedTrans = false;
|
||||||
|
for (y = 0; y < head.biHeight; y++){
|
||||||
|
for (x = 0; x < head.biWidth; x++){
|
||||||
|
// AND mask (Each Byte represents 8 Pixels)
|
||||||
|
if (((mask[y*maskwdt+(x>>3)] >> (7-x%8)) & 0x01)){
|
||||||
|
// AND mask is set (!=0). This is a transparent part
|
||||||
|
SetPixelIndex(x, y, (uint8_t)iTransIdx);
|
||||||
|
bNeedTrans = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// set transparent index if needed
|
||||||
|
if (bNeedTrans) SetTransIndex(iTransIdx);
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
AlphaDelete(); //because we have a transparent color in the palette
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SetTransIndex(0); //empty mask, set black as transparent color
|
||||||
|
Negative();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(mask);
|
||||||
|
}
|
||||||
|
free(icon_list);
|
||||||
|
// icon has been loaded successfully!
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
free(icon_list);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Thanks to <Alas>
|
||||||
|
bool CxImageICO::Encode(CxFile * hFile, CxImage ** pImages, int32_t nPageCount)
|
||||||
|
{
|
||||||
|
cx_try
|
||||||
|
{
|
||||||
|
if (hFile==NULL) cx_throw("invalid file pointer");
|
||||||
|
if (pImages==NULL || nPageCount<=0) cx_throw("multipage ICO, no images!");
|
||||||
|
|
||||||
|
int32_t i;
|
||||||
|
for (i=0; i<nPageCount; i++){
|
||||||
|
if (pImages[i]==NULL)
|
||||||
|
cx_throw("Bad image pointer");
|
||||||
|
if (!(pImages[i]->IsValid()))
|
||||||
|
cx_throw("Empty image");
|
||||||
|
}
|
||||||
|
|
||||||
|
CxImageICO ghost;
|
||||||
|
for (i=0; i<nPageCount; i++){ //write headers
|
||||||
|
ghost.Ghost(pImages[i]);
|
||||||
|
ghost.info.nNumFrames = nPageCount;
|
||||||
|
if (i==0) {
|
||||||
|
if (!ghost.Encode(hFile,false,nPageCount))
|
||||||
|
cx_throw("Error writing ICO file header");
|
||||||
|
}
|
||||||
|
if (!ghost.Encode(hFile,true,nPageCount))
|
||||||
|
cx_throw("Error saving ICO image header");
|
||||||
|
}
|
||||||
|
for (i=0; i<nPageCount; i++){ //write bodies
|
||||||
|
ghost.Ghost(pImages[i]);
|
||||||
|
ghost.info.nNumFrames = nPageCount;
|
||||||
|
if (!ghost.Encode(hFile,true,i))
|
||||||
|
cx_throw("Error saving ICO body");
|
||||||
|
}
|
||||||
|
|
||||||
|
} cx_catch {
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageICO::Encode(CxFile * hFile, bool bAppend, int32_t nPageCount)
|
||||||
|
{
|
||||||
|
if (EncodeSafeCheck(hFile)) return false;
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_PNG == 0
|
||||||
|
//check format limits
|
||||||
|
if ((head.biWidth>255)||(head.biHeight>255)){
|
||||||
|
strcpy(info.szLastError,"Can't save this image as icon");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//prepare the palette struct
|
||||||
|
RGBQUAD* pal=GetPalette();
|
||||||
|
if (head.biBitCount<=8 && pal==NULL) return false;
|
||||||
|
|
||||||
|
int32_t maskwdt=((head.biWidth+31)/32)*4; //mask line width
|
||||||
|
int32_t masksize=head.biHeight * maskwdt; //size of mask
|
||||||
|
int32_t bitcount=head.biBitCount;
|
||||||
|
int32_t imagesize=head.biSizeImage;
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (AlphaIsValid() && head.biClrUsed==0){
|
||||||
|
bitcount=32;
|
||||||
|
imagesize=4*head.biHeight*head.biWidth;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//fill the icon headers
|
||||||
|
int32_t nPages = nPageCount;
|
||||||
|
if (nPages<1) nPages = 1;
|
||||||
|
|
||||||
|
ICONHEADER icon_header={0,1,nPages};
|
||||||
|
|
||||||
|
if (!bAppend)
|
||||||
|
m_dwImageOffset = sizeof(ICONHEADER) + nPages * sizeof(ICONDIRENTRY);
|
||||||
|
|
||||||
|
uint32_t dwBytesInRes = sizeof(BITMAPINFOHEADER)+head.biClrUsed*sizeof(RGBQUAD)+imagesize+masksize;
|
||||||
|
|
||||||
|
ICONDIRENTRY icon_list={
|
||||||
|
(uint8_t)head.biWidth,
|
||||||
|
(uint8_t)head.biHeight,
|
||||||
|
(uint8_t)head.biClrUsed,
|
||||||
|
0, 0,
|
||||||
|
(uint16_t)bitcount,
|
||||||
|
dwBytesInRes,
|
||||||
|
m_dwImageOffset
|
||||||
|
};
|
||||||
|
|
||||||
|
BITMAPINFOHEADER bi={
|
||||||
|
sizeof(BITMAPINFOHEADER),
|
||||||
|
head.biWidth,
|
||||||
|
2*head.biHeight,
|
||||||
|
1,
|
||||||
|
(uint16_t)bitcount,
|
||||||
|
0, imagesize,
|
||||||
|
0, 0, 0, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_PNG // Vista icon support
|
||||||
|
CxImage png(*this);
|
||||||
|
CxMemFile memfile;
|
||||||
|
if (head.biWidth>255 || head.biHeight>255){
|
||||||
|
icon_list.bWidth = icon_list.bHeight = 0;
|
||||||
|
memfile.Open();
|
||||||
|
png.Encode(&memfile,CXIMAGE_FORMAT_PNG);
|
||||||
|
icon_list.dwBytesInRes = dwBytesInRes = memfile.Size();
|
||||||
|
}
|
||||||
|
#endif //CXIMAGE_SUPPORT_PNG
|
||||||
|
|
||||||
|
if (!bAppend){
|
||||||
|
icon_header.idType = m_ntohs(icon_header.idType);
|
||||||
|
icon_header.idCount = m_ntohs(icon_header.idCount);
|
||||||
|
hFile->Write(&icon_header,sizeof(ICONHEADER),1); //write the file header
|
||||||
|
icon_header.idType = m_ntohs(icon_header.idType);
|
||||||
|
icon_header.idCount = m_ntohs(icon_header.idCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ((bAppend && nPageCount==info.nNumFrames) || (!bAppend && nPageCount==0)){
|
||||||
|
icon_list.wPlanes = m_ntohs(icon_list.wPlanes);
|
||||||
|
icon_list.wBitCount = m_ntohs(icon_list.wBitCount);
|
||||||
|
icon_list.dwBytesInRes = m_ntohl(icon_list.dwBytesInRes);
|
||||||
|
icon_list.dwImageOffset = m_ntohl(icon_list.dwImageOffset);
|
||||||
|
hFile->Write(&icon_list,sizeof(ICONDIRENTRY),1); //write the image entry
|
||||||
|
icon_list.wPlanes = m_ntohs(icon_list.wPlanes);
|
||||||
|
icon_list.wBitCount = m_ntohs(icon_list.wBitCount);
|
||||||
|
icon_list.dwBytesInRes = m_ntohl(icon_list.dwBytesInRes);
|
||||||
|
icon_list.dwImageOffset = m_ntohl(icon_list.dwImageOffset);
|
||||||
|
|
||||||
|
m_dwImageOffset += dwBytesInRes; //update offset for next header
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((bAppend && nPageCount<info.nNumFrames) || (!bAppend && nPageCount==0))
|
||||||
|
{
|
||||||
|
#if CXIMAGE_SUPPORT_PNG
|
||||||
|
if (icon_list.bWidth==0 && icon_list.bHeight==0) { // Vista icon support
|
||||||
|
hFile->Write(memfile.GetBuffer(false),dwBytesInRes,1);
|
||||||
|
} else
|
||||||
|
#endif //CXIMAGE_SUPPORT_PNG
|
||||||
|
{ // standard icon
|
||||||
|
bihtoh(&bi);
|
||||||
|
hFile->Write(&bi,sizeof(BITMAPINFOHEADER),1); //write the image header
|
||||||
|
bihtoh(&bi);
|
||||||
|
|
||||||
|
bool bTransparent = info.nBkgndIndex >= 0;
|
||||||
|
RGBQUAD ct = GetTransColor();
|
||||||
|
if (pal){
|
||||||
|
if (bTransparent) SetPaletteColor((uint8_t)info.nBkgndIndex,0,0,0,0);
|
||||||
|
hFile->Write(pal,head.biClrUsed*sizeof(RGBQUAD),1); //write palette
|
||||||
|
if (bTransparent) SetPaletteColor((uint8_t)info.nBkgndIndex,ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (AlphaIsValid() && head.biClrUsed==0){
|
||||||
|
uint8_t* buf=(uint8_t*)malloc(imagesize);
|
||||||
|
uint8_t* dst = buf;
|
||||||
|
for (int32_t y = 0; y < head.biHeight; y++) {
|
||||||
|
uint8_t* src = GetBits(y);
|
||||||
|
for(int32_t x=0;x<head.biWidth;x++){
|
||||||
|
*dst++=*src++;
|
||||||
|
*dst++=*src++;
|
||||||
|
*dst++=*src++;
|
||||||
|
*dst++=AlphaGet(x,y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hFile->Write(buf,imagesize, 1);
|
||||||
|
free(buf);
|
||||||
|
} else {
|
||||||
|
hFile->Write(info.pImage,imagesize,1); //write image
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
hFile->Write(info.pImage,imagesize,1); //write image
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//save transparency mask
|
||||||
|
uint8_t* mask=(uint8_t*)calloc(masksize,1); //create empty AND/XOR masks
|
||||||
|
if (!mask) return false;
|
||||||
|
|
||||||
|
//prepare the variables to build the mask
|
||||||
|
uint8_t* iDst;
|
||||||
|
int32_t pos,i;
|
||||||
|
RGBQUAD c={0,0,0,0};
|
||||||
|
int32_t* pc = (int32_t*)&c;
|
||||||
|
int32_t* pct= (int32_t*)&ct;
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
bool bAlphaPaletteIsValid = AlphaPaletteIsValid();
|
||||||
|
bool bAlphaIsValid = AlphaIsValid();
|
||||||
|
#endif
|
||||||
|
//build the mask
|
||||||
|
for (int32_t y = 0; y < head.biHeight; y++) {
|
||||||
|
for (int32_t x = 0; x < head.biWidth; x++) {
|
||||||
|
i=0;
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (bAlphaIsValid && AlphaGet(x,y)==0) i=1;
|
||||||
|
if (bAlphaPaletteIsValid && BlindGetPixelColor(x,y).rgbReserved==0) i=1;
|
||||||
|
#endif
|
||||||
|
c=GetPixelColor(x,y,false);
|
||||||
|
if (bTransparent && *pc==*pct) i=1;
|
||||||
|
iDst = mask + y*maskwdt + (x>>3);
|
||||||
|
pos = 7-x%8;
|
||||||
|
*iDst &= ~(0x01<<pos);
|
||||||
|
*iDst |= ((i & 0x01)<<pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//write AND/XOR masks
|
||||||
|
hFile->Write(mask,masksize,1);
|
||||||
|
free(mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_ICO
|
||||||
|
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* File: ximaico.h
|
||||||
|
* Purpose: ICON Image Class Loader and Writer
|
||||||
|
*/
|
||||||
|
/* ==========================================================
|
||||||
|
* CxImageICO (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it
|
||||||
|
* For conditions of distribution and use, see copyright notice in ximage.h
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
#if !defined(__ximaICO_h)
|
||||||
|
#define __ximaICO_h
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ICO
|
||||||
|
|
||||||
|
class CxImageICO: public CxImage
|
||||||
|
{
|
||||||
|
typedef struct tagIconDirectoryEntry {
|
||||||
|
uint8_t bWidth;
|
||||||
|
uint8_t bHeight;
|
||||||
|
uint8_t bColorCount;
|
||||||
|
uint8_t bReserved;
|
||||||
|
uint16_t wPlanes;
|
||||||
|
uint16_t wBitCount;
|
||||||
|
uint32_t dwBytesInRes;
|
||||||
|
uint32_t dwImageOffset;
|
||||||
|
} ICONDIRENTRY;
|
||||||
|
|
||||||
|
typedef struct tagIconDir {
|
||||||
|
uint16_t idReserved;
|
||||||
|
uint16_t idType;
|
||||||
|
uint16_t idCount;
|
||||||
|
} ICONHEADER;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CxImageICO(): CxImage(CXIMAGE_FORMAT_ICO) {m_dwImageOffset=0;}
|
||||||
|
|
||||||
|
// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_ICO);}
|
||||||
|
// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_ICO);}
|
||||||
|
bool Decode(CxFile * hFile);
|
||||||
|
bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
bool Encode(CxFile * hFile, bool bAppend=false, int32_t nPageCount=0);
|
||||||
|
bool Encode(CxFile * hFile, CxImage ** pImages, int32_t nPageCount);
|
||||||
|
bool Encode(FILE *hFile, bool bAppend=false, int32_t nPageCount=0)
|
||||||
|
{ CxIOFile file(hFile); return Encode(&file,bAppend,nPageCount); }
|
||||||
|
bool Encode(FILE *hFile, CxImage ** pImages, int32_t nPageCount)
|
||||||
|
{ CxIOFile file(hFile); return Encode(&file, pImages, nPageCount); }
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
protected:
|
||||||
|
uint32_t m_dwImageOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,958 @@
|
|||||||
|
// ximainfo.cpp : main attributes
|
||||||
|
/* 03/10/2004 v1.00 - Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if defined(_LINUX) || defined(__APPLE__)
|
||||||
|
#define _tcsnicmp(a,b,c) strcasecmp(a,b)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \return the color used for transparency, and/or for background color
|
||||||
|
*/
|
||||||
|
RGBQUAD CxImage::GetTransColor()
|
||||||
|
{
|
||||||
|
if (head.biBitCount<24 && info.nBkgndIndex>=0) return GetPaletteColor((uint8_t)info.nBkgndIndex);
|
||||||
|
return info.nBkgndColor;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Gets the index used for transparency. Returns -1 for no transparancy.
|
||||||
|
*/
|
||||||
|
int32_t CxImage::GetTransIndex() const
|
||||||
|
{
|
||||||
|
return info.nBkgndIndex;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Sets the index used for transparency with 1, 4 and 8 bpp images. Set to -1 to remove the effect.
|
||||||
|
*/
|
||||||
|
void CxImage::SetTransIndex(int32_t idx)
|
||||||
|
{
|
||||||
|
if (idx<(int32_t)head.biClrUsed)
|
||||||
|
info.nBkgndIndex = idx;
|
||||||
|
else
|
||||||
|
info.nBkgndIndex = 0;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Sets the color used for transparency with 24 bpp images.
|
||||||
|
* You must call SetTransIndex(0) to enable the effect, SetTransIndex(-1) to disable it.
|
||||||
|
*/
|
||||||
|
void CxImage::SetTransColor(RGBQUAD rgb)
|
||||||
|
{
|
||||||
|
rgb.rgbReserved=0;
|
||||||
|
info.nBkgndColor = rgb;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImage::IsTransparent() const
|
||||||
|
{
|
||||||
|
return info.nBkgndIndex>=0; // <vho>
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Returns true if the image has 256 colors or less.
|
||||||
|
*/
|
||||||
|
bool CxImage::IsIndexed() const
|
||||||
|
{
|
||||||
|
return head.biClrUsed!=0;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \return 1 = indexed, 2 = RGB, 4 = RGBA
|
||||||
|
*/
|
||||||
|
uint8_t CxImage::GetColorType()
|
||||||
|
{
|
||||||
|
uint8_t b = (uint8_t)((head.biBitCount>8) ? 2 /*COLORTYPE_COLOR*/ : 1 /*COLORTYPE_PALETTE*/);
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (AlphaIsValid()) b = 4 /*COLORTYPE_ALPHA*/;
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \return Resolution for TIFF, JPEG, PNG and BMP formats.
|
||||||
|
*/
|
||||||
|
int32_t CxImage::GetXDPI() const
|
||||||
|
{
|
||||||
|
return info.xDPI;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \return Resolution for TIFF, JPEG, PNG and BMP formats.
|
||||||
|
*/
|
||||||
|
int32_t CxImage::GetYDPI() const
|
||||||
|
{
|
||||||
|
return info.yDPI;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Set resolution for TIFF, JPEG, PNG and BMP formats.
|
||||||
|
*/
|
||||||
|
void CxImage::SetXDPI(int32_t dpi)
|
||||||
|
{
|
||||||
|
if (dpi<=0) dpi = CXIMAGE_DEFAULT_DPI;
|
||||||
|
info.xDPI = dpi;
|
||||||
|
head.biXPelsPerMeter = (int32_t) floor(dpi * 10000.0 / 254.0 + 0.5);
|
||||||
|
if (pDib) ((BITMAPINFOHEADER*)pDib)->biXPelsPerMeter = head.biXPelsPerMeter;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Set resolution for TIFF, JPEG, PNG and BMP formats.
|
||||||
|
*/
|
||||||
|
void CxImage::SetYDPI(int32_t dpi)
|
||||||
|
{
|
||||||
|
if (dpi<=0) dpi = CXIMAGE_DEFAULT_DPI;
|
||||||
|
info.yDPI = dpi;
|
||||||
|
head.biYPelsPerMeter = (int32_t) floor(dpi * 10000.0 / 254.0 + 0.5);
|
||||||
|
if (pDib) ((BITMAPINFOHEADER*)pDib)->biYPelsPerMeter = head.biYPelsPerMeter;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \sa SetFlags
|
||||||
|
*/
|
||||||
|
uint32_t CxImage::GetFlags() const
|
||||||
|
{
|
||||||
|
return info.dwFlags;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Image flags, for future use
|
||||||
|
* \param flags
|
||||||
|
* - 0x??00000 = reserved for 16 bit, CMYK, multilayer
|
||||||
|
* - 0x00??0000 = blend modes
|
||||||
|
* - 0x0000???? = layer id or user flags
|
||||||
|
*
|
||||||
|
* \param bLockReservedFlags protects the "reserved" and "blend modes" flags
|
||||||
|
*/
|
||||||
|
void CxImage::SetFlags(uint32_t flags, bool bLockReservedFlags)
|
||||||
|
{
|
||||||
|
if (bLockReservedFlags) info.dwFlags = flags & 0x0000ffff;
|
||||||
|
else info.dwFlags = flags;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \sa SetCodecOption
|
||||||
|
*/
|
||||||
|
uint32_t CxImage::GetCodecOption(uint32_t imagetype)
|
||||||
|
{
|
||||||
|
imagetype = GetTypeIndexFromId(imagetype);
|
||||||
|
if (imagetype==0){
|
||||||
|
imagetype = GetTypeIndexFromId(GetType());
|
||||||
|
}
|
||||||
|
return info.dwCodecOpt[imagetype];
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Encode option for GIF, TIF, JPG, PNG and RAW
|
||||||
|
* - GIF : 0 = LZW (default), 1 = none, 2 = RLE.
|
||||||
|
* - TIF : 0 = automatic (default), or a valid compression code as defined in "tiff.h" (COMPRESSION_NONE = 1, COMPRESSION_CCITTRLE = 2, ...)
|
||||||
|
* - JPG : valid values stored in enum CODEC_OPTION ( ENCODE_BASELINE = 0x01, ENCODE_PROGRESSIVE = 0x10, ...)
|
||||||
|
* - PNG : combination of interlace option and compression option
|
||||||
|
* interlace option : 1 = interlace, 0 = no interlace
|
||||||
|
* compression option : 2 = no compression, 4 = best speed, 6 = best compression, 8 = default compression
|
||||||
|
* default is no interlace and default compression
|
||||||
|
* example : 5 = 1+4 = interlace + best speed
|
||||||
|
* - RAW : valid values stored in enum CODEC_OPTION ( DECODE_QUALITY_LIN = 0x00, DECODE_QUALITY_VNG = 0x01, ...)
|
||||||
|
*
|
||||||
|
* \return true if everything is ok
|
||||||
|
*/
|
||||||
|
bool CxImage::SetCodecOption(uint32_t opt, uint32_t imagetype)
|
||||||
|
{
|
||||||
|
imagetype = GetTypeIndexFromId(imagetype);
|
||||||
|
if (imagetype==0){
|
||||||
|
imagetype = GetTypeIndexFromId(GetType());
|
||||||
|
}
|
||||||
|
info.dwCodecOpt[imagetype] = opt;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \return internal hDib object..
|
||||||
|
*/
|
||||||
|
void* CxImage::GetDIB() const
|
||||||
|
{
|
||||||
|
return pDib;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
uint32_t CxImage::GetHeight() const
|
||||||
|
{
|
||||||
|
return head.biHeight;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
uint32_t CxImage::GetWidth() const
|
||||||
|
{
|
||||||
|
return head.biWidth;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \return uint32_t aligned width of the image.
|
||||||
|
*/
|
||||||
|
uint32_t CxImage::GetEffWidth() const
|
||||||
|
{
|
||||||
|
return info.dwEffWidth;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \return 2, 16, 256; 0 for RGB images.
|
||||||
|
*/
|
||||||
|
uint32_t CxImage::GetNumColors() const
|
||||||
|
{
|
||||||
|
return head.biClrUsed;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \return: 1, 4, 8, 24.
|
||||||
|
*/
|
||||||
|
uint16_t CxImage::GetBpp() const
|
||||||
|
{
|
||||||
|
return head.biBitCount;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \return original image format
|
||||||
|
* \sa ENUM_CXIMAGE_FORMATS.
|
||||||
|
*/
|
||||||
|
uint32_t CxImage::GetType() const
|
||||||
|
{
|
||||||
|
return info.dwType;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* change image format identifier
|
||||||
|
* \sa ENUM_CXIMAGE_FORMATS.
|
||||||
|
*/
|
||||||
|
bool CxImage::SetType(uint32_t type)
|
||||||
|
{
|
||||||
|
switch (type){
|
||||||
|
#if CXIMAGE_SUPPORT_BMP
|
||||||
|
case CXIMAGE_FORMAT_BMP:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_GIF
|
||||||
|
case CXIMAGE_FORMAT_GIF:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JPG
|
||||||
|
case CXIMAGE_FORMAT_JPG:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PNG
|
||||||
|
case CXIMAGE_FORMAT_PNG:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_MNG
|
||||||
|
case CXIMAGE_FORMAT_MNG:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_ICO
|
||||||
|
case CXIMAGE_FORMAT_ICO:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_TIF
|
||||||
|
case CXIMAGE_FORMAT_TIF:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_TGA
|
||||||
|
case CXIMAGE_FORMAT_TGA:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PCX
|
||||||
|
case CXIMAGE_FORMAT_PCX:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_WBMP
|
||||||
|
case CXIMAGE_FORMAT_WBMP:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_WMF
|
||||||
|
case CXIMAGE_FORMAT_WMF:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JBG
|
||||||
|
case CXIMAGE_FORMAT_JBG:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JP2
|
||||||
|
case CXIMAGE_FORMAT_JP2:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JPC
|
||||||
|
case CXIMAGE_FORMAT_JPC:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PGX
|
||||||
|
case CXIMAGE_FORMAT_PGX:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PNM
|
||||||
|
case CXIMAGE_FORMAT_PNM:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_RAS
|
||||||
|
case CXIMAGE_FORMAT_RAS:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_SKA
|
||||||
|
case CXIMAGE_FORMAT_SKA:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_RAW
|
||||||
|
case CXIMAGE_FORMAT_RAW:
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PSD
|
||||||
|
case CXIMAGE_FORMAT_PSD:
|
||||||
|
#endif
|
||||||
|
info.dwType = type;
|
||||||
|
return true;
|
||||||
|
case CXIMAGE_FORMAT_UNKNOWN:
|
||||||
|
default:
|
||||||
|
info.dwType = CXIMAGE_FORMAT_UNKNOWN;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
uint32_t CxImage::GetNumTypes()
|
||||||
|
{
|
||||||
|
return CMAX_IMAGE_FORMATS-1;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
uint32_t CxImage::GetTypeIdFromName(const TCHAR* ext)
|
||||||
|
{
|
||||||
|
#if CXIMAGE_SUPPORT_BMP
|
||||||
|
if (_tcsnicmp(ext,_T("bmp"),3)==0 ) return CXIMAGE_FORMAT_BMP;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JPG
|
||||||
|
if (_tcsnicmp(ext,_T("jpg"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("jpe"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("jfi"),3)==0 ) return CXIMAGE_FORMAT_JPG;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_GIF
|
||||||
|
if (_tcsnicmp(ext,_T("gif"),3)==0 ) return CXIMAGE_FORMAT_GIF;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PNG
|
||||||
|
if (_tcsnicmp(ext,_T("png"),3)==0 ) return CXIMAGE_FORMAT_PNG;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_ICO
|
||||||
|
if (_tcsnicmp(ext,_T("ico"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("cur"),3)==0 ) return CXIMAGE_FORMAT_ICO;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_TIF
|
||||||
|
if (_tcsnicmp(ext,_T("tif"),3)==0 ) return CXIMAGE_FORMAT_TIF;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_TGA
|
||||||
|
if (_tcsnicmp(ext,_T("tga"),3)==0 ) return CXIMAGE_FORMAT_TGA;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PCX
|
||||||
|
if (_tcsnicmp(ext,_T("pcx"),3)==0 ) return CXIMAGE_FORMAT_PCX;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_WBMP
|
||||||
|
if (_tcsnicmp(ext,_T("wbm"),3)==0 ) return CXIMAGE_FORMAT_WBMP;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_WMF
|
||||||
|
if (_tcsnicmp(ext,_T("wmf"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("emf"),3)==0 ) return CXIMAGE_FORMAT_WMF;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JP2
|
||||||
|
if (_tcsnicmp(ext,_T("jp2"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("j2k"),3)==0 ) return CXIMAGE_FORMAT_JP2;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JPC
|
||||||
|
if (_tcsnicmp(ext,_T("jpc"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("j2c"),3)==0 ) return CXIMAGE_FORMAT_JPC;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PGX
|
||||||
|
if (_tcsnicmp(ext,_T("pgx"),3)==0 ) return CXIMAGE_FORMAT_PGX;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_RAS
|
||||||
|
if (_tcsnicmp(ext,_T("ras"),3)==0 ) return CXIMAGE_FORMAT_RAS;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PNM
|
||||||
|
if (_tcsnicmp(ext,_T("pnm"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("pgm"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("ppm"),3)==0 ) return CXIMAGE_FORMAT_PNM;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JBG
|
||||||
|
if (_tcsnicmp(ext,_T("jbg"),3)==0 ) return CXIMAGE_FORMAT_JBG;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_MNG
|
||||||
|
if (_tcsnicmp(ext,_T("mng"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("jng"),3)==0 ) return CXIMAGE_FORMAT_MNG;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_SKA
|
||||||
|
if (_tcsnicmp(ext,_T("ska"),3)==0 ) return CXIMAGE_FORMAT_SKA;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PSD
|
||||||
|
if (_tcsnicmp(ext,_T("psd"),3)==0 ) return CXIMAGE_FORMAT_PSD;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_RAW
|
||||||
|
if (_tcsnicmp(ext,_T("nef"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("crw"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("cr2"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("dng"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("arw"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("erf"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("3fr"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("dcr"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("raw"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("x3f"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("mef"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("raf"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("mrw"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("pef"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("sr2"),3)==0 ||
|
||||||
|
_tcsnicmp(ext,_T("orf"),3)==0 ) return CXIMAGE_FORMAT_RAW;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return CXIMAGE_FORMAT_UNKNOWN;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
uint32_t CxImage::GetTypeIdFromIndex(const uint32_t index)
|
||||||
|
{
|
||||||
|
uint32_t n;
|
||||||
|
|
||||||
|
n=0; if (index == n) return CXIMAGE_FORMAT_UNKNOWN;
|
||||||
|
#if CXIMAGE_SUPPORT_BMP
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_BMP;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_GIF
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_GIF;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JPG
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_JPG;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PNG
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_PNG;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_ICO
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_ICO;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_TIF
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_TIF;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_TGA
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_TGA;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PCX
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_PCX;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_WBMP
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_WBMP;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_WMF
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_WMF;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JP2
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_JP2;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JPC
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_JPC;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PGX
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_PGX;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PNM
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_PNM;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_RAS
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_RAS;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JBG
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_JBG;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_MNG
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_MNG;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_SKA
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_SKA;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_RAW
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_RAW;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PSD
|
||||||
|
n++; if (index == n) return CXIMAGE_FORMAT_PSD;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return CXIMAGE_FORMAT_UNKNOWN;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
uint32_t CxImage::GetTypeIndexFromId(const uint32_t id)
|
||||||
|
{
|
||||||
|
uint32_t n;
|
||||||
|
|
||||||
|
n=0; if (id == CXIMAGE_FORMAT_UNKNOWN) return n;
|
||||||
|
#if CXIMAGE_SUPPORT_BMP
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_BMP) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_GIF
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_GIF) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JPG
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_JPG) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PNG
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_PNG) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_ICO
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_ICO) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_TIF
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_TIF) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_TGA
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_TGA) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PCX
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_PCX) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_WBMP
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_WBMP) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_WMF
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_WMF) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JP2
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_JP2) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JPC
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_JPC) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PGX
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_PGX) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PNM
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_PNM) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_RAS
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_RAS) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JBG
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_JBG) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_MNG
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_MNG) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_SKA
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_SKA) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_RAW
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_RAW) return n;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PSD
|
||||||
|
n++; if (id == CXIMAGE_FORMAT_PSD) return n;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \return current frame delay in milliseconds. Only for GIF and MNG formats.
|
||||||
|
*/
|
||||||
|
uint32_t CxImage::GetFrameDelay() const
|
||||||
|
{
|
||||||
|
return info.dwFrameDelay;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Sets current frame delay. Only for GIF format.
|
||||||
|
* \param d = delay in milliseconds
|
||||||
|
*/
|
||||||
|
void CxImage::SetFrameDelay(uint32_t d)
|
||||||
|
{
|
||||||
|
info.dwFrameDelay=d;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::GetOffset(int32_t *x,int32_t *y)
|
||||||
|
{
|
||||||
|
*x=info.xOffset;
|
||||||
|
*y=info.yOffset;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::SetOffset(int32_t x,int32_t y)
|
||||||
|
{
|
||||||
|
info.xOffset=x;
|
||||||
|
info.yOffset=y;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \sa SetJpegQuality, GetJpegQualityF
|
||||||
|
* \author [DP]; changes [Stefan Schürmans]
|
||||||
|
*/
|
||||||
|
uint8_t CxImage::GetJpegQuality() const
|
||||||
|
{
|
||||||
|
return (uint8_t)(info.fQuality + 0.5f);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \sa SetJpegQuality, GetJpegQuality
|
||||||
|
* \author [Stefan Schürmans]
|
||||||
|
*/
|
||||||
|
float CxImage::GetJpegQualityF() const
|
||||||
|
{
|
||||||
|
return info.fQuality;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* quality level for JPEG and JPEG2000
|
||||||
|
* \param q: can be from 0 to 100
|
||||||
|
* \author [DP]; changes [Stefan Schürmans]
|
||||||
|
*/
|
||||||
|
void CxImage::SetJpegQuality(uint8_t q){
|
||||||
|
info.fQuality = (float)q;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* quality level for JPEG and JPEG2000
|
||||||
|
* necessary for JPEG2000 when quality is between 0.0 and 1.0
|
||||||
|
* \param q: can be from 0.0 to 100.0
|
||||||
|
* \author [Stefan Schürmans]
|
||||||
|
*/
|
||||||
|
void CxImage::SetJpegQualityF(float q){
|
||||||
|
if (q>0) info.fQuality = q;
|
||||||
|
else info.fQuality = 0.0f;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \sa SetJpegScale
|
||||||
|
*/
|
||||||
|
uint8_t CxImage::GetJpegScale() const
|
||||||
|
{
|
||||||
|
return info.nJpegScale;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* scaling down during JPEG decoding valid numbers are 1, 2, 4, 8
|
||||||
|
* \author [ignacio]
|
||||||
|
*/
|
||||||
|
void CxImage::SetJpegScale(uint8_t q){
|
||||||
|
info.nJpegScale = q;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Used to monitor the slow loops.
|
||||||
|
* \return value is from 0 to 100.
|
||||||
|
* \sa SetProgress
|
||||||
|
*/
|
||||||
|
int32_t CxImage::GetProgress() const
|
||||||
|
{
|
||||||
|
return info.nProgress;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \return the escape code.
|
||||||
|
* \sa SetEscape
|
||||||
|
*/
|
||||||
|
int32_t CxImage::GetEscape() const
|
||||||
|
{
|
||||||
|
return info.nEscape;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Forces the value of the internal progress variable.
|
||||||
|
* \param p should be from 0 to 100.
|
||||||
|
* \sa GetProgress
|
||||||
|
*/
|
||||||
|
void CxImage::SetProgress(int32_t p)
|
||||||
|
{
|
||||||
|
info.nProgress = p;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Used to quit the slow loops or the codecs.
|
||||||
|
* - SetEscape(-1) before Decode forces the function to exit, right after
|
||||||
|
* the image width and height are available ( for bmp, jpg, gif, tif )
|
||||||
|
*/
|
||||||
|
void CxImage::SetEscape(int32_t i)
|
||||||
|
{
|
||||||
|
info.nEscape = i;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Checks if the image is correctly initializated.
|
||||||
|
*/
|
||||||
|
bool CxImage::IsValid() const
|
||||||
|
{
|
||||||
|
return pDib!=0;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* True if the image is enabled for painting.
|
||||||
|
*/
|
||||||
|
bool CxImage::IsEnabled() const
|
||||||
|
{
|
||||||
|
return info.bEnabled;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Enables/disables the image.
|
||||||
|
*/
|
||||||
|
void CxImage::Enable(bool enable)
|
||||||
|
{
|
||||||
|
info.bEnabled=enable;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* This function must be used after a Decode() / Load() call.
|
||||||
|
* Use the sequence SetFrame(-1); Load(...); GetNumFrames();
|
||||||
|
* to get the number of images without loading the first image.
|
||||||
|
* \return the number of images in the file.
|
||||||
|
*/
|
||||||
|
int32_t CxImage::GetNumFrames() const
|
||||||
|
{
|
||||||
|
return info.nNumFrames;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \return the current selected image (zero-based index).
|
||||||
|
*/
|
||||||
|
int32_t CxImage::GetFrame() const
|
||||||
|
{
|
||||||
|
return info.nFrame;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Sets the image number that the next Decode() / Load() call will load
|
||||||
|
*/
|
||||||
|
void CxImage::SetFrame(int32_t nFrame){
|
||||||
|
info.nFrame=nFrame;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Sets the method for drawing the frame related to others
|
||||||
|
* \sa GetDisposalMethod
|
||||||
|
*/
|
||||||
|
void CxImage::SetDisposalMethod(uint8_t dm)
|
||||||
|
{ info.dispmeth=dm; }
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Gets the method for drawing the frame related to others
|
||||||
|
* Values : 0 - No disposal specified. The decoder is
|
||||||
|
* not required to take any action.
|
||||||
|
* 1 - Do not dispose. The graphic is to be left
|
||||||
|
* in place.
|
||||||
|
* 2 - Restore to background color. The area used by the
|
||||||
|
* graphic must be restored to the background color.
|
||||||
|
* 3 - Restore to previous. The decoder is required to
|
||||||
|
* restore the area overwritten by the graphic with
|
||||||
|
* what was there prior to rendering the graphic.
|
||||||
|
* 4-7 - To be defined.
|
||||||
|
*/
|
||||||
|
uint8_t CxImage::GetDisposalMethod() const
|
||||||
|
{ return info.dispmeth; }
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImage::GetRetreiveAllFrames() const
|
||||||
|
{ return info.bGetAllFrames; }
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::SetRetreiveAllFrames(bool flag)
|
||||||
|
{ info.bGetAllFrames = flag; }
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CxImage * CxImage::GetFrame(int32_t nFrame) const
|
||||||
|
{
|
||||||
|
if ( ppFrames == NULL) return NULL;
|
||||||
|
if ( info.nNumFrames == 0) return NULL;
|
||||||
|
if ( nFrame >= info.nNumFrames ) return NULL;
|
||||||
|
if ( nFrame < 0) nFrame = info.nNumFrames - 1;
|
||||||
|
return ppFrames[nFrame];
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int16_t CxImage::m_ntohs(const int16_t word)
|
||||||
|
{
|
||||||
|
if (info.bLittleEndianHost) return word;
|
||||||
|
return ( (word & 0xff) << 8 ) | ( (word >> 8) & 0xff );
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int32_t CxImage::m_ntohl(const int32_t dword)
|
||||||
|
{
|
||||||
|
if (info.bLittleEndianHost) return dword;
|
||||||
|
return ((dword & 0xff) << 24 ) | ((dword & 0xff00) << 8 ) |
|
||||||
|
((dword >> 8) & 0xff00) | ((dword >> 24) & 0xff);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::bihtoh(BITMAPINFOHEADER* bih)
|
||||||
|
{
|
||||||
|
bih->biSize = m_ntohl(bih->biSize);
|
||||||
|
bih->biWidth = m_ntohl(bih->biWidth);
|
||||||
|
bih->biHeight = m_ntohl(bih->biHeight);
|
||||||
|
bih->biPlanes = m_ntohs(bih->biPlanes);
|
||||||
|
bih->biBitCount = m_ntohs(bih->biBitCount);
|
||||||
|
bih->biCompression = m_ntohl(bih->biCompression);
|
||||||
|
bih->biSizeImage = m_ntohl(bih->biSizeImage);
|
||||||
|
bih->biXPelsPerMeter = m_ntohl(bih->biXPelsPerMeter);
|
||||||
|
bih->biYPelsPerMeter = m_ntohl(bih->biYPelsPerMeter);
|
||||||
|
bih->biClrUsed = m_ntohl(bih->biClrUsed);
|
||||||
|
bih->biClrImportant = m_ntohl(bih->biClrImportant);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Returns the last reported error.
|
||||||
|
*/
|
||||||
|
const char* CxImage::GetLastError()
|
||||||
|
{
|
||||||
|
return info.szLastError;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
uint32_t CxImage::DumpSize()
|
||||||
|
{
|
||||||
|
uint32_t n;
|
||||||
|
n = sizeof(BITMAPINFOHEADER) + sizeof(CXIMAGEINFO) + GetSize();
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (pAlpha){
|
||||||
|
n += 1 + head.biWidth * head.biHeight;
|
||||||
|
} else n++;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_SELECTION
|
||||||
|
if (pSelection){
|
||||||
|
n += 1 + head.biWidth * head.biHeight;
|
||||||
|
} else n++;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_LAYERS
|
||||||
|
if (ppLayers){
|
||||||
|
for (int32_t m=0; m<GetNumLayers(); m++){
|
||||||
|
if (GetLayer(m)){
|
||||||
|
n += 1 + GetLayer(m)->DumpSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else n++;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ppFrames){
|
||||||
|
for (int32_t m=0; m<GetNumFrames(); m++){
|
||||||
|
if (GetFrame(m)){
|
||||||
|
n += 1 + GetFrame(m)->DumpSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else n++;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
uint32_t CxImage::Dump(uint8_t * dst)
|
||||||
|
{
|
||||||
|
if (!dst) return 0;
|
||||||
|
|
||||||
|
memcpy(dst,&head,sizeof(BITMAPINFOHEADER));
|
||||||
|
dst += sizeof(BITMAPINFOHEADER);
|
||||||
|
|
||||||
|
memcpy(dst,&info,sizeof(CXIMAGEINFO));
|
||||||
|
dst += sizeof(CXIMAGEINFO);
|
||||||
|
|
||||||
|
memcpy(dst,pDib,GetSize());
|
||||||
|
dst += GetSize();
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (pAlpha){
|
||||||
|
memset(dst++, 1, 1);
|
||||||
|
memcpy(dst,pAlpha,head.biWidth * head.biHeight);
|
||||||
|
dst += head.biWidth * head.biHeight;
|
||||||
|
} else {
|
||||||
|
memset(dst++, 0, 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_SELECTION
|
||||||
|
if (pSelection){
|
||||||
|
memset(dst++, 1, 1);
|
||||||
|
memcpy(dst,pSelection,head.biWidth * head.biHeight);
|
||||||
|
dst += head.biWidth * head.biHeight;
|
||||||
|
} else {
|
||||||
|
memset(dst++, 0, 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_LAYERS
|
||||||
|
if (ppLayers){
|
||||||
|
memset(dst++, 1, 1);
|
||||||
|
for (int32_t m=0; m<GetNumLayers(); m++){
|
||||||
|
if (GetLayer(m)){
|
||||||
|
dst += GetLayer(m)->Dump(dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memset(dst++, 0, 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ppFrames){
|
||||||
|
memset(dst++, 1, 1);
|
||||||
|
for (int32_t m=0; m<GetNumFrames(); m++){
|
||||||
|
if (GetFrame(m)){
|
||||||
|
dst += GetFrame(m)->Dump(dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memset(dst++, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DumpSize();
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
uint32_t CxImage::UnDump(const uint8_t * src)
|
||||||
|
{
|
||||||
|
if (!src)
|
||||||
|
return 0;
|
||||||
|
if (!Destroy())
|
||||||
|
return 0;
|
||||||
|
if (!DestroyFrames())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint32_t n = 0;
|
||||||
|
|
||||||
|
memcpy(&head,src,sizeof(BITMAPINFOHEADER));
|
||||||
|
n += sizeof(BITMAPINFOHEADER);
|
||||||
|
|
||||||
|
memcpy(&info,&src[n],sizeof(CXIMAGEINFO));
|
||||||
|
n += sizeof(CXIMAGEINFO);
|
||||||
|
|
||||||
|
if (!Create(head.biWidth, head.biHeight, head.biBitCount, info.dwType))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memcpy(pDib,&src[n],GetSize());
|
||||||
|
n += GetSize();
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (src[n++]){
|
||||||
|
if (AlphaCreate()){
|
||||||
|
memcpy(pAlpha, &src[n], head.biWidth * head.biHeight);
|
||||||
|
}
|
||||||
|
n += head.biWidth * head.biHeight;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_SELECTION
|
||||||
|
if (src[n++]){
|
||||||
|
RECT box = info.rSelectionBox;
|
||||||
|
if (SelectionCreate()){
|
||||||
|
info.rSelectionBox = box;
|
||||||
|
memcpy(pSelection, &src[n], head.biWidth * head.biHeight);
|
||||||
|
}
|
||||||
|
n += head.biWidth * head.biHeight;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_LAYERS
|
||||||
|
if (src[n++]){
|
||||||
|
ppLayers = new CxImage*[info.nNumLayers];
|
||||||
|
for (int32_t m=0; m<GetNumLayers(); m++){
|
||||||
|
ppLayers[m] = new CxImage();
|
||||||
|
n += ppLayers[m]->UnDump(&src[n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (src[n++]){
|
||||||
|
ppFrames = new CxImage*[info.nNumFrames];
|
||||||
|
for (int32_t m=0; m<GetNumFrames(); m++){
|
||||||
|
ppFrames[m] = new CxImage();
|
||||||
|
n += ppFrames[m]->UnDump(&src[n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \return A.BBCCCDDDD
|
||||||
|
* - A = main version
|
||||||
|
* - BB = main revision
|
||||||
|
* - CCC = minor revision (letter)
|
||||||
|
* - DDDD = experimental revision
|
||||||
|
*/
|
||||||
|
const float CxImage::GetVersionNumber()
|
||||||
|
{
|
||||||
|
return 7.000010000f;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const TCHAR* CxImage::GetVersion()
|
||||||
|
{
|
||||||
|
static const TCHAR CxImageVersion[] = _T("CxImage 7.0.1");
|
||||||
|
return (CxImageVersion);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
* File: ImaIter.h
|
||||||
|
* Purpose: Declaration of the Platform Independent Image Base Class
|
||||||
|
* Author: Alejandro Aguilar Sierra
|
||||||
|
* Created: 1995
|
||||||
|
* Copyright: (c) 1995, Alejandro Aguilar Sierra <asierra(at)servidor(dot)unam(dot)mx>
|
||||||
|
*
|
||||||
|
* 07/08/2001 Davide Pizzolato - www.xdp.it
|
||||||
|
* - removed slow loops
|
||||||
|
* - added safe checks
|
||||||
|
*
|
||||||
|
* Permission is given by the author to freely redistribute and include
|
||||||
|
* this code in any program as int32_t as this credit is given where due.
|
||||||
|
*
|
||||||
|
* COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
|
||||||
|
* OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
|
||||||
|
* THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
|
||||||
|
* OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
|
||||||
|
* CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
|
||||||
|
* THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
|
||||||
|
* SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
|
||||||
|
* PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
|
||||||
|
* THIS DISCLAIMER.
|
||||||
|
*
|
||||||
|
* Use at your own risk!
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(__ImaIter_h)
|
||||||
|
#define __ImaIter_h
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
#include "ximadef.h"
|
||||||
|
|
||||||
|
class CImageIterator
|
||||||
|
{
|
||||||
|
friend class CxImage;
|
||||||
|
protected:
|
||||||
|
int32_t Itx, Ity; // Counters
|
||||||
|
int32_t Stepx, Stepy;
|
||||||
|
uint8_t* IterImage; // Image pointer
|
||||||
|
CxImage *ima;
|
||||||
|
public:
|
||||||
|
// Constructors
|
||||||
|
CImageIterator ( void );
|
||||||
|
CImageIterator ( CxImage *image );
|
||||||
|
operator CxImage* ();
|
||||||
|
|
||||||
|
// Iterators
|
||||||
|
BOOL ItOK ();
|
||||||
|
void Reset ();
|
||||||
|
void Upset ();
|
||||||
|
void SetRow(uint8_t *buf, int32_t n);
|
||||||
|
void GetRow(uint8_t *buf, int32_t n);
|
||||||
|
uint8_t GetByte( ) { return IterImage[Itx]; }
|
||||||
|
void SetByte(uint8_t b) { IterImage[Itx] = b; }
|
||||||
|
uint8_t* GetRow(void);
|
||||||
|
uint8_t* GetRow(int32_t n);
|
||||||
|
BOOL NextRow();
|
||||||
|
BOOL PrevRow();
|
||||||
|
BOOL NextByte();
|
||||||
|
BOOL PrevByte();
|
||||||
|
|
||||||
|
void SetSteps(int32_t x, int32_t y=0) { Stepx = x; Stepy = y; }
|
||||||
|
void GetSteps(int32_t *x, int32_t *y) { *x = Stepx; *y = Stepy; }
|
||||||
|
BOOL NextStep();
|
||||||
|
BOOL PrevStep();
|
||||||
|
|
||||||
|
void SetY(int32_t y); /* AD - for interlace */
|
||||||
|
int32_t GetY() {return Ity;}
|
||||||
|
BOOL GetCol(uint8_t* pCol, uint32_t x);
|
||||||
|
BOOL SetCol(uint8_t* pCol, uint32_t x);
|
||||||
|
};
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline
|
||||||
|
CImageIterator::CImageIterator(void)
|
||||||
|
{
|
||||||
|
ima = 0;
|
||||||
|
IterImage = 0;
|
||||||
|
Itx = Ity = 0;
|
||||||
|
Stepx = Stepy = 0;
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline
|
||||||
|
CImageIterator::CImageIterator(CxImage *imageImpl): ima(imageImpl)
|
||||||
|
{
|
||||||
|
if (ima) IterImage = ima->GetBits();
|
||||||
|
Itx = Ity = 0;
|
||||||
|
Stepx = Stepy = 0;
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline
|
||||||
|
CImageIterator::operator CxImage* ()
|
||||||
|
{
|
||||||
|
return ima;
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline BOOL CImageIterator::ItOK ()
|
||||||
|
{
|
||||||
|
if (ima) return ima->IsInside(Itx, Ity);
|
||||||
|
else return FALSE;
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline void CImageIterator::Reset()
|
||||||
|
{
|
||||||
|
if (ima) IterImage = ima->GetBits();
|
||||||
|
else IterImage=0;
|
||||||
|
Itx = Ity = 0;
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline void CImageIterator::Upset()
|
||||||
|
{
|
||||||
|
Itx = 0;
|
||||||
|
Ity = ima->GetHeight()-1;
|
||||||
|
IterImage = ima->GetBits() + ima->GetEffWidth()*(ima->GetHeight()-1);
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline BOOL CImageIterator::NextRow()
|
||||||
|
{
|
||||||
|
if (++Ity >= (int32_t)ima->GetHeight()) return 0;
|
||||||
|
IterImage += ima->GetEffWidth();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline BOOL CImageIterator::PrevRow()
|
||||||
|
{
|
||||||
|
if (--Ity < 0) return 0;
|
||||||
|
IterImage -= ima->GetEffWidth();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* AD - for interlace */
|
||||||
|
inline void CImageIterator::SetY(int32_t y)
|
||||||
|
{
|
||||||
|
if ((y < 0) || (y > (int32_t)ima->GetHeight())) return;
|
||||||
|
Ity = y;
|
||||||
|
IterImage = ima->GetBits() + ima->GetEffWidth()*y;
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline void CImageIterator::SetRow(uint8_t *buf, int32_t n)
|
||||||
|
{
|
||||||
|
if (n<0) n = (int32_t)ima->GetEffWidth();
|
||||||
|
else n = min(n,(int32_t)ima->GetEffWidth());
|
||||||
|
|
||||||
|
if ((IterImage!=NULL)&&(buf!=NULL)&&(n>0)) memcpy(IterImage,buf,n);
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline void CImageIterator::GetRow(uint8_t *buf, int32_t n)
|
||||||
|
{
|
||||||
|
if ((IterImage!=NULL)&&(buf!=NULL)&&(n>0))
|
||||||
|
memcpy(buf,IterImage,min(n,(int32_t)ima->GetEffWidth()));
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline uint8_t* CImageIterator::GetRow()
|
||||||
|
{
|
||||||
|
return IterImage;
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline uint8_t* CImageIterator::GetRow(int32_t n)
|
||||||
|
{
|
||||||
|
SetY(n);
|
||||||
|
return IterImage;
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline BOOL CImageIterator::NextByte()
|
||||||
|
{
|
||||||
|
if (++Itx < (int32_t)ima->GetEffWidth()) return 1;
|
||||||
|
else
|
||||||
|
if (++Ity < (int32_t)ima->GetHeight()){
|
||||||
|
IterImage += ima->GetEffWidth();
|
||||||
|
Itx = 0;
|
||||||
|
return 1;
|
||||||
|
} else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline BOOL CImageIterator::PrevByte()
|
||||||
|
{
|
||||||
|
if (--Itx >= 0) return 1;
|
||||||
|
else
|
||||||
|
if (--Ity >= 0){
|
||||||
|
IterImage -= ima->GetEffWidth();
|
||||||
|
Itx = 0;
|
||||||
|
return 1;
|
||||||
|
} else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline BOOL CImageIterator::NextStep()
|
||||||
|
{
|
||||||
|
Itx += Stepx;
|
||||||
|
if (Itx < (int32_t)ima->GetEffWidth()) return 1;
|
||||||
|
else {
|
||||||
|
Ity += Stepy;
|
||||||
|
if (Ity < (int32_t)ima->GetHeight()){
|
||||||
|
IterImage += ima->GetEffWidth();
|
||||||
|
Itx = 0;
|
||||||
|
return 1;
|
||||||
|
} else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline BOOL CImageIterator::PrevStep()
|
||||||
|
{
|
||||||
|
Itx -= Stepx;
|
||||||
|
if (Itx >= 0) return 1;
|
||||||
|
else {
|
||||||
|
Ity -= Stepy;
|
||||||
|
if (Ity >= 0 && Ity < (int32_t)ima->GetHeight()) {
|
||||||
|
IterImage -= ima->GetEffWidth();
|
||||||
|
Itx = 0;
|
||||||
|
return 1;
|
||||||
|
} else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline BOOL CImageIterator::GetCol(uint8_t* pCol, uint32_t x)
|
||||||
|
{
|
||||||
|
if ((pCol==0)||(ima->GetBpp()<8)||(x>=ima->GetWidth()))
|
||||||
|
return 0;
|
||||||
|
uint32_t h = ima->GetHeight();
|
||||||
|
//uint32_t line = ima->GetEffWidth();
|
||||||
|
uint8_t bytes = (uint8_t)(ima->GetBpp()>>3);
|
||||||
|
uint8_t* pSrc;
|
||||||
|
for (uint32_t y=0;y<h;y++){
|
||||||
|
pSrc = ima->GetBits(y) + x*bytes;
|
||||||
|
for (uint8_t w=0;w<bytes;w++){
|
||||||
|
*pCol++=*pSrc++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
inline BOOL CImageIterator::SetCol(uint8_t* pCol, uint32_t x)
|
||||||
|
{
|
||||||
|
if ((pCol==0)||(ima->GetBpp()<8)||(x>=ima->GetWidth()))
|
||||||
|
return 0;
|
||||||
|
uint32_t h = ima->GetHeight();
|
||||||
|
//uint32_t line = ima->GetEffWidth();
|
||||||
|
uint8_t bytes = (uint8_t)(ima->GetBpp()>>3);
|
||||||
|
uint8_t* pSrc;
|
||||||
|
for (uint32_t y=0;y<h;y++){
|
||||||
|
pSrc = ima->GetBits(y) + x*bytes;
|
||||||
|
for (uint8_t w=0;w<bytes;w++){
|
||||||
|
*pSrc++=*pCol++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,325 @@
|
|||||||
|
/*
|
||||||
|
* File: ximajas.cpp
|
||||||
|
* Purpose: Platform Independent JasPer Image Class Loader and Writer
|
||||||
|
* 12/Apr/2003 Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximajas.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_JASPER
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageJAS::Decode(CxFile *hFile, uint32_t imagetype)
|
||||||
|
{
|
||||||
|
if (hFile == NULL) return false;
|
||||||
|
|
||||||
|
jas_image_t *image=0;
|
||||||
|
jas_stream_t *in=0;
|
||||||
|
jas_matrix_t **bufs=0;
|
||||||
|
int32_t i,error=0;
|
||||||
|
int32_t fmt;
|
||||||
|
//jas_setdbglevel(0);
|
||||||
|
|
||||||
|
cx_try
|
||||||
|
{
|
||||||
|
if (jas_init())
|
||||||
|
cx_throw("cannot initialize jasper");
|
||||||
|
|
||||||
|
in = jas_stream_fdopen(0, "rb");
|
||||||
|
if (!in)
|
||||||
|
cx_throw("error: cannot open standard input");
|
||||||
|
|
||||||
|
CxFileJas src(hFile,in);
|
||||||
|
|
||||||
|
fmt = jas_image_getfmt(in);
|
||||||
|
if (fmt<0)
|
||||||
|
cx_throw("error: unknowm format");
|
||||||
|
|
||||||
|
image = jas_image_decode(in, fmt, 0);
|
||||||
|
if (!image){
|
||||||
|
fmt = -1;
|
||||||
|
cx_throw("error: cannot load image data");
|
||||||
|
}
|
||||||
|
|
||||||
|
char szfmt[4];
|
||||||
|
*szfmt = '\0';
|
||||||
|
strncpy(szfmt,jas_image_fmttostr(fmt),3);
|
||||||
|
szfmt[3] = '\0';
|
||||||
|
|
||||||
|
fmt = -1;
|
||||||
|
#if CXIMAGE_SUPPORT_JP2
|
||||||
|
if (strcmp(szfmt,"jp2")==0) fmt = CXIMAGE_FORMAT_JP2;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JPC
|
||||||
|
if (strcmp(szfmt,"jpc")==0) fmt = CXIMAGE_FORMAT_JPC;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_RAS
|
||||||
|
if (strcmp(szfmt,"ras")==0) fmt = CXIMAGE_FORMAT_RAS;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PNM
|
||||||
|
if (strcmp(szfmt,"pnm")==0) fmt = CXIMAGE_FORMAT_PNM;
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PGX
|
||||||
|
if (strcmp(szfmt,"pgx")==0) fmt = CXIMAGE_FORMAT_PGX;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//if (fmt<0)
|
||||||
|
// cx_throw("error: unknowm format");
|
||||||
|
|
||||||
|
int32_t x,y,w,h,depth,cmptno;
|
||||||
|
|
||||||
|
w = jas_image_cmptwidth(image,0);
|
||||||
|
h = jas_image_cmptheight(image,0);
|
||||||
|
depth = jas_image_cmptprec(image,0);
|
||||||
|
|
||||||
|
if (info.nEscape == -1){
|
||||||
|
head.biWidth = w;
|
||||||
|
head.biHeight= h;
|
||||||
|
info.dwType = fmt<0 ? 0 : fmt;
|
||||||
|
cx_throw("output dimensions returned");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image->numcmpts_ > 64 || image->numcmpts_ < 0)
|
||||||
|
cx_throw("error: too many components");
|
||||||
|
|
||||||
|
// <LD> 01/Jan/2005: Always force conversion to sRGB. Seems to be required for many types of JPEG2000 file.
|
||||||
|
// if (depth!=1 && depth!=4 && depth!=8)
|
||||||
|
if (image->numcmpts_>=3 && depth <=8)
|
||||||
|
{
|
||||||
|
jas_image_t *newimage;
|
||||||
|
jas_cmprof_t *outprof;
|
||||||
|
//jas_eprintf("forcing conversion to sRGB\n");
|
||||||
|
outprof = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB);
|
||||||
|
if (!outprof) {
|
||||||
|
cx_throw("cannot create sRGB profile");
|
||||||
|
}
|
||||||
|
newimage = jas_image_chclrspc(image, outprof, JAS_CMXFORM_INTENT_PER);
|
||||||
|
if (!newimage) {
|
||||||
|
jas_cmprof_destroy(outprof); // <LD> 01/Jan/2005: Destroy color profile on error.
|
||||||
|
cx_throw("cannot convert to sRGB");
|
||||||
|
}
|
||||||
|
jas_image_destroy(image);
|
||||||
|
jas_cmprof_destroy(outprof);
|
||||||
|
image = newimage;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufs = (jas_matrix_t **)calloc(image->numcmpts_, sizeof(jas_matrix_t**));
|
||||||
|
for (i = 0; i < image->numcmpts_; ++i) {
|
||||||
|
bufs[i] = jas_matrix_create(1, w);
|
||||||
|
if (!bufs[i]) {
|
||||||
|
cx_throw("error: cannot allocate memory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t nshift = (depth>8) ? (depth-8) : 0;
|
||||||
|
|
||||||
|
if (image->numcmpts_==3 &&
|
||||||
|
image->cmpts_[0]->width_ == image->cmpts_[1]->width_ &&
|
||||||
|
image->cmpts_[1]->width_ == image->cmpts_[2]->width_ &&
|
||||||
|
image->cmpts_[0]->height_ == image->cmpts_[1]->height_ &&
|
||||||
|
image->cmpts_[1]->height_ == image->cmpts_[2]->height_ &&
|
||||||
|
image->cmpts_[0]->prec_ == image->cmpts_[1]->prec_ &&
|
||||||
|
image->cmpts_[1]->prec_ == image->cmpts_[2]->prec_ )
|
||||||
|
{
|
||||||
|
|
||||||
|
if(!Create(w,h,24,fmt))
|
||||||
|
cx_throw("");
|
||||||
|
|
||||||
|
RGBQUAD c;
|
||||||
|
for (y=0; y<h; y++) {
|
||||||
|
for (cmptno = 0; cmptno < image->numcmpts_; ++cmptno) {
|
||||||
|
jas_image_readcmpt(image, cmptno, 0, y, w, 1, bufs[cmptno]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (x=0; x<w; x++){
|
||||||
|
c.rgbRed = (uint8_t)((jas_matrix_getv(bufs[0], x)>>nshift));
|
||||||
|
c.rgbGreen = (uint8_t)((jas_matrix_getv(bufs[1], x)>>nshift));
|
||||||
|
c.rgbBlue = (uint8_t)((jas_matrix_getv(bufs[2], x)>>nshift));
|
||||||
|
SetPixelColor(x,h-1-y,c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info.nNumFrames = image->numcmpts_;
|
||||||
|
if ((info.nFrame<0)||(info.nFrame>=info.nNumFrames)){
|
||||||
|
cx_throw("wrong frame!");
|
||||||
|
}
|
||||||
|
for (cmptno=0; cmptno<=info.nFrame; cmptno++) {
|
||||||
|
w = jas_image_cmptwidth(image,cmptno);
|
||||||
|
h = jas_image_cmptheight(image,cmptno);
|
||||||
|
depth = jas_image_cmptprec(image,cmptno);
|
||||||
|
if (depth>8) depth=8;
|
||||||
|
if(!Create(w,h,depth,imagetype))
|
||||||
|
cx_throw("");
|
||||||
|
SetGrayPalette();
|
||||||
|
for (y=0; y<h; y++) {
|
||||||
|
jas_image_readcmpt(image, cmptno, 0, y, w, 1, bufs[0]);
|
||||||
|
for (x=0; x<w; x++){
|
||||||
|
SetPixelIndex(x,h-1-y,(uint8_t)((jas_matrix_getv(bufs[0], x)>>nshift)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} cx_catch {
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
if (info.nEscape == -1 && fmt>0){
|
||||||
|
error = 0;
|
||||||
|
} else {
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufs) {
|
||||||
|
for (i = 0; i < image->numcmpts_; ++i){ if (bufs[i]) jas_matrix_destroy(bufs[i]);}
|
||||||
|
free(bufs);
|
||||||
|
}
|
||||||
|
jas_cleanup();
|
||||||
|
if (image) jas_image_destroy(image);
|
||||||
|
if (in) jas_stream_close(in);
|
||||||
|
return (error==0);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageJAS::Encode(CxFile * hFile, uint32_t imagetype)
|
||||||
|
{
|
||||||
|
if (EncodeSafeCheck(hFile)) return false;
|
||||||
|
|
||||||
|
if (head.biClrUsed!=0 && !IsGrayScale()){
|
||||||
|
strcpy(info.szLastError,"JasPer can save only RGB or GrayScale images");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
jas_image_t *image=0;
|
||||||
|
jas_stream_t *out=0;
|
||||||
|
jas_matrix_t *cmpts[3];
|
||||||
|
int32_t x,y,yflip,error=0;
|
||||||
|
uint_fast16_t cmptno, numcmpts=0;
|
||||||
|
jas_image_cmptparm_t cmptparms[3], *cmptparm;
|
||||||
|
|
||||||
|
cx_try {
|
||||||
|
|
||||||
|
if (jas_init())
|
||||||
|
cx_throw("cannot initialize jasper");
|
||||||
|
|
||||||
|
out = jas_stream_fdopen(0, "wb");
|
||||||
|
if (!out)
|
||||||
|
cx_throw("error: cannot open standard output");
|
||||||
|
|
||||||
|
CxFileJas src(hFile,out);
|
||||||
|
|
||||||
|
numcmpts = head.biClrUsed==0 ? 3 : 1;
|
||||||
|
|
||||||
|
for (cmptno = 0, cmptparm = cmptparms; cmptno < numcmpts; ++cmptno, ++cmptparm) {
|
||||||
|
cmptparm->tlx = 0;
|
||||||
|
cmptparm->tly = 0;
|
||||||
|
cmptparm->hstep = 1;
|
||||||
|
cmptparm->vstep = 1;
|
||||||
|
cmptparm->width = head.biWidth;
|
||||||
|
cmptparm->height = head.biHeight;
|
||||||
|
cmptparm->prec = 8;
|
||||||
|
cmptparm->sgnd = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create image object. */
|
||||||
|
image = jas_image_create(numcmpts, cmptparms, JAS_CLRSPC_UNKNOWN);
|
||||||
|
if (!image)
|
||||||
|
cx_throw("error : jas_image_create");
|
||||||
|
|
||||||
|
if (numcmpts == 3) {
|
||||||
|
jas_image_setclrspc(image, JAS_CLRSPC_SRGB);
|
||||||
|
jas_image_setcmpttype(image, 0,
|
||||||
|
JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
|
||||||
|
jas_image_setcmpttype(image, 1,
|
||||||
|
JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
|
||||||
|
jas_image_setcmpttype(image, 2,
|
||||||
|
JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
|
||||||
|
} else {
|
||||||
|
jas_image_setclrspc(image, JAS_CLRSPC_SGRAY);
|
||||||
|
jas_image_setcmpttype(image, 0,
|
||||||
|
JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (x = 0; x < numcmpts; ++x) { cmpts[x] = 0; }
|
||||||
|
/* Create temporary matrices to hold component data. */
|
||||||
|
for (x = 0; x < numcmpts; ++x) {
|
||||||
|
cmpts[x] = jas_matrix_create(1, head.biWidth);
|
||||||
|
if (!cmpts[x]) {
|
||||||
|
cx_throw("error : can't allocate memory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RGBQUAD c;
|
||||||
|
for (y = 0; y < head.biHeight; ++y) {
|
||||||
|
for (x = 0; x < head.biWidth; ++x) {
|
||||||
|
if (head.biClrUsed==0){
|
||||||
|
c = GetPixelColor(x,y);
|
||||||
|
jas_matrix_setv(cmpts[0], x, c.rgbRed);
|
||||||
|
jas_matrix_setv(cmpts[1], x, c.rgbGreen);
|
||||||
|
jas_matrix_setv(cmpts[2], x, c.rgbBlue);
|
||||||
|
} else {
|
||||||
|
jas_matrix_setv(cmpts[0], x, GetPixelIndex(x,y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yflip = head.biHeight - 1 - y;
|
||||||
|
for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
|
||||||
|
if (jas_image_writecmpt(image, cmptno, 0, yflip, head.biWidth, 1, cmpts[cmptno])) {
|
||||||
|
cx_throw("error : jas_image_writecmpt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char szfmt[4];
|
||||||
|
*szfmt = '\0';
|
||||||
|
#if CXIMAGE_SUPPORT_JP2
|
||||||
|
if (imagetype == CXIMAGE_FORMAT_JP2) strcpy(szfmt,"jp2");
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_JPC
|
||||||
|
if (imagetype == CXIMAGE_FORMAT_JPC) strcpy(szfmt,"jpc");
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_RAS
|
||||||
|
if (imagetype == CXIMAGE_FORMAT_RAS) strcpy(szfmt,"ras");
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PNM
|
||||||
|
if (imagetype == CXIMAGE_FORMAT_PNM) strcpy(szfmt,"pnm");
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_PGX
|
||||||
|
if (imagetype == CXIMAGE_FORMAT_PGX){
|
||||||
|
strcpy(szfmt,"pgx");
|
||||||
|
if (head.biClrUsed==0) cx_throw("PGX can save only GrayScale images");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
int32_t outfmt = jas_image_strtofmt(szfmt);
|
||||||
|
|
||||||
|
char szoutopts[32];
|
||||||
|
sprintf(szoutopts,"rate=%.3f", info.fQuality/100.0f);
|
||||||
|
|
||||||
|
if (jas_image_encode(image, out, outfmt, szoutopts)) {
|
||||||
|
cx_throw("error: cannot encode image");
|
||||||
|
}
|
||||||
|
jas_stream_flush(out);
|
||||||
|
|
||||||
|
} cx_catch {
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (x = 0; x < numcmpts; ++x) { if (cmpts[x]) { jas_matrix_destroy(cmpts[x]); } }
|
||||||
|
jas_cleanup();
|
||||||
|
if (image) jas_image_destroy(image);
|
||||||
|
if (out) jas_stream_close(out);
|
||||||
|
|
||||||
|
return (error==0);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_JASPER
|
||||||
|
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* File: ximajas.h
|
||||||
|
* Purpose: Jasper Image Class Loader and Writer
|
||||||
|
*/
|
||||||
|
/* ==========================================================
|
||||||
|
* CxImageJAS (c) 12/Apr/2003 Davide Pizzolato - www.xdp.it
|
||||||
|
* For conditions of distribution and use, see copyright notice in ximage.h
|
||||||
|
*
|
||||||
|
* based on JasPer Copyright (c) 2001-2003 Michael David Adams - All rights reserved.
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
#if !defined(__ximaJAS_h)
|
||||||
|
#define __ximaJAS_h
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_JASPER
|
||||||
|
|
||||||
|
#ifdef _LINUX
|
||||||
|
#include <jasper/jasper.h>
|
||||||
|
#else
|
||||||
|
#include "../jasper/include/jasper/jasper.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CxImageJAS: public CxImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CxImageJAS(): CxImage((uint32_t)0) {} // <vho> cast to uint32_t
|
||||||
|
|
||||||
|
// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,0);}
|
||||||
|
// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,0);}
|
||||||
|
bool Decode(CxFile * hFile, uint32_t imagetype = 0);
|
||||||
|
bool Decode(FILE *hFile, uint32_t imagetype = 0) { CxIOFile file(hFile); return Decode(&file,imagetype); }
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
bool Encode(CxFile * hFile, uint32_t imagetype = 0);
|
||||||
|
bool Encode(FILE *hFile, uint32_t imagetype = 0) { CxIOFile file(hFile); return Encode(&file,imagetype); }
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
protected:
|
||||||
|
|
||||||
|
class CxFileJas
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CxFileJas(CxFile* pFile,jas_stream_t *stream)
|
||||||
|
{
|
||||||
|
if (stream->obj_) jas_free(stream->obj_);
|
||||||
|
stream->obj_ = pFile;
|
||||||
|
|
||||||
|
// <vho> - cannot set the stream->ops_->functions here,
|
||||||
|
// because this overwrites a static structure in the Jasper library.
|
||||||
|
// This structure is used by Jasper for internal operations too, e.g. tempfile.
|
||||||
|
// However the ops_ pointer in the stream can be overwritten.
|
||||||
|
|
||||||
|
//stream->ops_->close_ = JasClose;
|
||||||
|
//stream->ops_->read_ = JasRead;
|
||||||
|
//stream->ops_->seek_ = JasSeek;
|
||||||
|
//stream->ops_->write_ = JasWrite;
|
||||||
|
|
||||||
|
jas_stream_CxFile.close_ = JasClose;
|
||||||
|
jas_stream_CxFile.read_ = JasRead;
|
||||||
|
jas_stream_CxFile.seek_ = JasSeek;
|
||||||
|
jas_stream_CxFile.write_ = JasWrite;
|
||||||
|
|
||||||
|
stream->ops_ = &jas_stream_CxFile;
|
||||||
|
|
||||||
|
// <vho> - end
|
||||||
|
}
|
||||||
|
static int32_t JasRead(jas_stream_obj_t *obj, char *buf, int32_t cnt)
|
||||||
|
{ return ((CxFile*)obj)->Read(buf,1,cnt); }
|
||||||
|
static int32_t JasWrite(jas_stream_obj_t *obj, char *buf, int32_t cnt)
|
||||||
|
{ return ((CxFile*)obj)->Write(buf,1,cnt); }
|
||||||
|
static long JasSeek(jas_stream_obj_t *obj, long offset, int32_t origin)
|
||||||
|
{ return ((CxFile*)obj)->Seek(offset,origin); }
|
||||||
|
static int32_t JasClose(jas_stream_obj_t * /*obj*/)
|
||||||
|
{ return 1; }
|
||||||
|
|
||||||
|
// <vho>
|
||||||
|
private:
|
||||||
|
jas_stream_ops_t jas_stream_CxFile;
|
||||||
|
// <vho> - end
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* File: ximajbg.cpp
|
||||||
|
* Purpose: Platform Independent JBG Image Class Loader and Writer
|
||||||
|
* 18/Aug/2002 Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximajbg.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_JBG
|
||||||
|
|
||||||
|
#include "ximaiter.h"
|
||||||
|
|
||||||
|
#define JBIG_BUFSIZE 8192
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageJBG::Decode(CxFile *hFile)
|
||||||
|
{
|
||||||
|
if (hFile == NULL) return false;
|
||||||
|
|
||||||
|
struct jbg_dec_state jbig_state;
|
||||||
|
uint32_t xmax = 4294967295UL, ymax = 4294967295UL;
|
||||||
|
uint32_t len, cnt;
|
||||||
|
uint8_t *buffer=0,*p;
|
||||||
|
int32_t result;
|
||||||
|
|
||||||
|
cx_try
|
||||||
|
{
|
||||||
|
jbg_dec_init(&jbig_state);
|
||||||
|
jbg_dec_maxsize(&jbig_state, xmax, ymax);
|
||||||
|
|
||||||
|
buffer = (uint8_t*)malloc(JBIG_BUFSIZE);
|
||||||
|
if (!buffer) cx_throw("Sorry, not enough memory available!");
|
||||||
|
|
||||||
|
result = JBG_EAGAIN;
|
||||||
|
do {
|
||||||
|
len = hFile->Read(buffer, 1, JBIG_BUFSIZE);
|
||||||
|
if (!len) break;
|
||||||
|
cnt = 0;
|
||||||
|
p = buffer;
|
||||||
|
while (len > 0 && (result == JBG_EAGAIN || result == JBG_EOK)) {
|
||||||
|
result = jbg_dec_in(&jbig_state, p, len, &cnt);
|
||||||
|
p += cnt;
|
||||||
|
len -= cnt;
|
||||||
|
}
|
||||||
|
} while (result == JBG_EAGAIN || result == JBG_EOK);
|
||||||
|
|
||||||
|
if (hFile->Error())
|
||||||
|
cx_throw("Problem while reading input file");
|
||||||
|
if (result != JBG_EOK && result != JBG_EOK_INTR)
|
||||||
|
cx_throw("Problem with input file");
|
||||||
|
|
||||||
|
int32_t w, h, bpp, planes, ew;
|
||||||
|
|
||||||
|
w = jbg_dec_getwidth(&jbig_state);
|
||||||
|
h = jbg_dec_getheight(&jbig_state);
|
||||||
|
planes = jbg_dec_getplanes(&jbig_state);
|
||||||
|
bpp = (planes+7)>>3;
|
||||||
|
ew = (w + 7)>>3;
|
||||||
|
|
||||||
|
if (info.nEscape == -1){
|
||||||
|
head.biWidth = w;
|
||||||
|
head.biHeight= h;
|
||||||
|
info.dwType = CXIMAGE_FORMAT_JBG;
|
||||||
|
cx_throw("output dimensions returned");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (planes){
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
uint8_t* binary_image = jbg_dec_getimage(&jbig_state, 0);
|
||||||
|
|
||||||
|
if (!Create(w,h,1,CXIMAGE_FORMAT_JBG))
|
||||||
|
cx_throw("");
|
||||||
|
|
||||||
|
SetPaletteColor(0,255,255,255);
|
||||||
|
SetPaletteColor(1,0,0,0);
|
||||||
|
|
||||||
|
CImageIterator iter(this);
|
||||||
|
iter.Upset();
|
||||||
|
for (int32_t i=0;i<h;i++){
|
||||||
|
iter.SetRow(binary_image+i*ew,ew);
|
||||||
|
iter.PrevRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
cx_throw("cannot decode images with more than 1 plane");
|
||||||
|
}
|
||||||
|
|
||||||
|
jbg_dec_free(&jbig_state);
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
} cx_catch {
|
||||||
|
jbg_dec_free(&jbig_state);
|
||||||
|
if (buffer) free(buffer);
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_JBG) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageJBG::Encode(CxFile * hFile)
|
||||||
|
{
|
||||||
|
if (EncodeSafeCheck(hFile)) return false;
|
||||||
|
|
||||||
|
if (head.biBitCount != 1){
|
||||||
|
strcpy(info.szLastError,"JBG can save only 1-bpp images");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t w, h, bpp, planes, ew, i, j, x, y;
|
||||||
|
|
||||||
|
w = head.biWidth;
|
||||||
|
h = head.biHeight;
|
||||||
|
planes = 1;
|
||||||
|
bpp = (planes+7)>>3;
|
||||||
|
ew = (w + 7)>>3;
|
||||||
|
|
||||||
|
uint8_t mask;
|
||||||
|
RGBQUAD *rgb = GetPalette();
|
||||||
|
if (CompareColors(&rgb[0],&rgb[1])<0) mask=255; else mask=0;
|
||||||
|
|
||||||
|
uint8_t *buffer = (uint8_t*)malloc(ew*h*2);
|
||||||
|
if (!buffer) {
|
||||||
|
strcpy(info.szLastError,"Sorry, not enough memory available!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (y=0; y<h; y++){
|
||||||
|
i= y*ew;
|
||||||
|
j= (h-y-1)*info.dwEffWidth;
|
||||||
|
for (x=0; x<ew; x++){
|
||||||
|
buffer[i + x]=info.pImage[j + x]^mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct jbg_enc_state jbig_state;
|
||||||
|
jbg_enc_init(&jbig_state, w, h, planes, &buffer, jbig_data_out, hFile);
|
||||||
|
|
||||||
|
//jbg_enc_layers(&jbig_state, 2);
|
||||||
|
//jbg_enc_lrlmax(&jbig_state, 800, 600);
|
||||||
|
|
||||||
|
// Specify a few other options (each is ignored if negative)
|
||||||
|
int32_t dl = -1, dh = -1, d = -1, l0 = -1, mx = -1;
|
||||||
|
int32_t options = JBG_TPDON | JBG_TPBON | JBG_DPON;
|
||||||
|
int32_t order = JBG_ILEAVE | JBG_SMID;
|
||||||
|
jbg_enc_lrange(&jbig_state, dl, dh);
|
||||||
|
jbg_enc_options(&jbig_state, order, options, l0, mx, -1);
|
||||||
|
|
||||||
|
// now encode everything and send it to data_out()
|
||||||
|
jbg_enc_out(&jbig_state);
|
||||||
|
|
||||||
|
// give encoder a chance to free its temporary data structures
|
||||||
|
jbg_enc_free(&jbig_state);
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
if (hFile->Error()){
|
||||||
|
strcpy(info.szLastError,"Problem while writing JBG file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_JBG
|
||||||
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* File: ximajbg.h
|
||||||
|
* Purpose: JBG Image Class Loader and Writer
|
||||||
|
*/
|
||||||
|
/* ==========================================================
|
||||||
|
* CxImageJBG (c) 18/Aug/2002 Davide Pizzolato - www.xdp.it
|
||||||
|
* For conditions of distribution and use, see copyright notice in ximage.h
|
||||||
|
*
|
||||||
|
* based on LIBJBG Copyright (c) 2002, Markus Kuhn - All rights reserved.
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
#if !defined(__ximaJBG_h)
|
||||||
|
#define __ximaJBG_h
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_JBG
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "../jbig/jbig.h"
|
||||||
|
};
|
||||||
|
|
||||||
|
class CxImageJBG: public CxImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CxImageJBG(): CxImage(CXIMAGE_FORMAT_JBG) {}
|
||||||
|
|
||||||
|
// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_JBG);}
|
||||||
|
// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_JBG);}
|
||||||
|
bool Decode(CxFile * hFile);
|
||||||
|
bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
bool Encode(CxFile * hFile);
|
||||||
|
bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
protected:
|
||||||
|
static void jbig_data_out(uint8_t *buffer, uint32_t len, void *file)
|
||||||
|
{((CxFile*)file)->Write(buffer,len,1);}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,542 @@
|
|||||||
|
/*
|
||||||
|
* File: ximajpg.cpp
|
||||||
|
* Purpose: Platform Independent JPEG Image Class Loader and Writer
|
||||||
|
* 07/Aug/2001 Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximajpg.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_JPG
|
||||||
|
|
||||||
|
#ifdef _LINUX
|
||||||
|
#include <jmorecfg.h>
|
||||||
|
#else
|
||||||
|
#include "../jpeg/jmorecfg.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ximaiter.h"
|
||||||
|
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
struct jpg_error_mgr {
|
||||||
|
struct jpeg_error_mgr pub; /* "public" fields */
|
||||||
|
jmp_buf setjmp_buffer; /* for return to caller */
|
||||||
|
char* buffer; /* error message <CSC>*/
|
||||||
|
};
|
||||||
|
typedef jpg_error_mgr *jpg_error_ptr;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Here's the routine that will replace the standard error_exit method:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
static void
|
||||||
|
ima_jpeg_error_exit (j_common_ptr cinfo)
|
||||||
|
{
|
||||||
|
/* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
|
||||||
|
jpg_error_ptr myerr = (jpg_error_ptr) cinfo->err;
|
||||||
|
/* Create the message */
|
||||||
|
myerr->pub.format_message (cinfo, myerr->buffer);
|
||||||
|
/* Send it to stderr, adding a newline */
|
||||||
|
/* Return control to the setjmp point */
|
||||||
|
longjmp(myerr->setjmp_buffer, 1);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CxImageJPG::CxImageJPG(): CxImage(CXIMAGE_FORMAT_JPG)
|
||||||
|
{
|
||||||
|
#if CXIMAGEJPG_SUPPORT_EXIF
|
||||||
|
m_exif = NULL;
|
||||||
|
memset(&info.ExifInfo, 0, sizeof(EXIFINFO));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CxImageJPG::~CxImageJPG()
|
||||||
|
{
|
||||||
|
#if CXIMAGEJPG_SUPPORT_EXIF
|
||||||
|
if (m_exif) delete m_exif;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGEJPG_SUPPORT_EXIF
|
||||||
|
bool CxImageJPG::DecodeExif(CxFile * hFile)
|
||||||
|
{
|
||||||
|
m_exif = new CxExifInfo(&info.ExifInfo);
|
||||||
|
if (m_exif){
|
||||||
|
int32_t pos=hFile->Tell();
|
||||||
|
m_exif->DecodeExif(hFile);
|
||||||
|
hFile->Seek(pos,SEEK_SET);
|
||||||
|
return m_exif->m_exifinfo->IsExif;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageJPG::GetExifThumbnail(const TCHAR *filename, const TCHAR *outname, int32_t type)
|
||||||
|
{
|
||||||
|
CxIOFile file;
|
||||||
|
if (!file.Open(filename, _T("rb"))) return false;
|
||||||
|
CxExifInfo exif(&info.ExifInfo);
|
||||||
|
exif.DecodeExif(&file);
|
||||||
|
if (info.ExifInfo.IsExif && info.ExifInfo.ThumbnailPointer && info.ExifInfo.ThumbnailSize > 0)
|
||||||
|
{ // have a thumbnail - check whether it needs rotating or resizing
|
||||||
|
// TODO: Write a fast routine to read the jpeg header to get the width and height
|
||||||
|
CxImage image(info.ExifInfo.ThumbnailPointer, info.ExifInfo.ThumbnailSize, CXIMAGE_FORMAT_JPG);
|
||||||
|
if (image.IsValid())
|
||||||
|
{
|
||||||
|
if (image.GetWidth() > 256 || image.GetHeight() > 256)
|
||||||
|
{ // resize the image
|
||||||
|
// float amount = 256.0f / max(image.GetWidth(), image.GetHeight());
|
||||||
|
// image.Resample((int32_t)(image.GetWidth() * amount), (int32_t)(image.GetHeight() * amount), 0);
|
||||||
|
}
|
||||||
|
#if CXIMAGE_SUPPORT_TRANSFORMATION
|
||||||
|
if (info.ExifInfo.Orientation != 1)
|
||||||
|
image.RotateExif(info.ExifInfo.Orientation);
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
return image.Save(outname, CXIMAGE_FORMAT_JPG);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
// nice and fast, but we can't resize :(
|
||||||
|
/*
|
||||||
|
FILE *hFileWrite;
|
||||||
|
if ((hFileWrite=fopen(outname, "wb")) != NULL)
|
||||||
|
{
|
||||||
|
fwrite(m_exifinfo.ThumbnailPointer, m_exifinfo.ThumbnailSize, 1, hFileWrite);
|
||||||
|
fclose(hFileWrite);
|
||||||
|
return true;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif //CXIMAGEJPG_SUPPORT_EXIF
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageJPG::Decode(CxFile * hFile)
|
||||||
|
{
|
||||||
|
|
||||||
|
bool is_exif = false;
|
||||||
|
#if CXIMAGEJPG_SUPPORT_EXIF
|
||||||
|
is_exif = DecodeExif(hFile);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CImageIterator iter(this);
|
||||||
|
/* This struct contains the JPEG decompression parameters and pointers to
|
||||||
|
* working space (which is allocated as needed by the JPEG library).
|
||||||
|
*/
|
||||||
|
struct jpeg_decompress_struct cinfo;
|
||||||
|
/* We use our private extension JPEG error handler. <CSC> */
|
||||||
|
struct jpg_error_mgr jerr;
|
||||||
|
jerr.buffer=info.szLastError;
|
||||||
|
/* More stuff */
|
||||||
|
JSAMPARRAY buffer; /* Output row buffer */
|
||||||
|
int32_t row_stride; /* physical row width in output buffer */
|
||||||
|
|
||||||
|
/* In this example we want to open the input file before doing anything else,
|
||||||
|
* so that the setjmp() error recovery below can assume the file is open.
|
||||||
|
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
|
||||||
|
* requires it in order to read binary files.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Step 1: allocate and initialize JPEG decompression object */
|
||||||
|
/* We set up the normal JPEG error routines, then override error_exit. */
|
||||||
|
cinfo.err = jpeg_std_error(&jerr.pub);
|
||||||
|
jerr.pub.error_exit = ima_jpeg_error_exit;
|
||||||
|
|
||||||
|
CxFileJpg src(hFile);
|
||||||
|
|
||||||
|
/* Establish the setjmp return context for my_error_exit to use. */
|
||||||
|
if (setjmp(jerr.setjmp_buffer)) {
|
||||||
|
/* If we get here, the JPEG code has signaled an error.
|
||||||
|
* We need to clean up the JPEG object, close the input file, and return.
|
||||||
|
*/
|
||||||
|
jpeg_destroy_decompress(&cinfo);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Now we can initialize the JPEG decompression object. */
|
||||||
|
jpeg_create_decompress(&cinfo);
|
||||||
|
|
||||||
|
/* Step 2: specify data source (eg, a file) */
|
||||||
|
//jpeg_stdio_src(&cinfo, infile);
|
||||||
|
cinfo.src = &src;
|
||||||
|
|
||||||
|
/* Step 3: read file parameters with jpeg_read_header() */
|
||||||
|
(void) jpeg_read_header(&cinfo, TRUE);
|
||||||
|
|
||||||
|
/* Step 4 <chupeev> handle decoder options*/
|
||||||
|
uint32_t dwCodecOptions = GetCodecOption(CXIMAGE_FORMAT_JPG); //[nm_114]
|
||||||
|
if ((dwCodecOptions & DECODE_GRAYSCALE) != 0)
|
||||||
|
cinfo.out_color_space = JCS_GRAYSCALE;
|
||||||
|
if ((dwCodecOptions & DECODE_QUANTIZE) != 0) {
|
||||||
|
cinfo.quantize_colors = TRUE;
|
||||||
|
cinfo.desired_number_of_colors = GetJpegQuality();
|
||||||
|
}
|
||||||
|
if ((dwCodecOptions & DECODE_DITHER) != 0)
|
||||||
|
cinfo.dither_mode = m_nDither;
|
||||||
|
if ((dwCodecOptions & DECODE_ONEPASS) != 0)
|
||||||
|
cinfo.two_pass_quantize = FALSE;
|
||||||
|
if ((dwCodecOptions & DECODE_NOSMOOTH) != 0)
|
||||||
|
cinfo.do_fancy_upsampling = FALSE;
|
||||||
|
|
||||||
|
//<DP>: Load true color images as RGB (no quantize)
|
||||||
|
/* Step 4: set parameters for decompression */
|
||||||
|
/* if (cinfo.jpeg_color_space!=JCS_GRAYSCALE) {
|
||||||
|
* cinfo.quantize_colors = TRUE;
|
||||||
|
* cinfo.desired_number_of_colors = 128;
|
||||||
|
*}
|
||||||
|
*/ //</DP>
|
||||||
|
|
||||||
|
cinfo.scale_num = 1;
|
||||||
|
// Set the scale <ignacio>
|
||||||
|
cinfo.scale_denom = GetJpegScale();
|
||||||
|
|
||||||
|
// Borrowed the idea from GIF implementation <ignacio>
|
||||||
|
if (info.nEscape == -1) {
|
||||||
|
// Return output dimensions only
|
||||||
|
jpeg_calc_output_dimensions(&cinfo);
|
||||||
|
head.biWidth = cinfo.output_width;
|
||||||
|
head.biHeight = cinfo.output_height;
|
||||||
|
info.dwType = CXIMAGE_FORMAT_JPG;
|
||||||
|
jpeg_destroy_decompress(&cinfo);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 5: Start decompressor */
|
||||||
|
jpeg_start_decompress(&cinfo);
|
||||||
|
|
||||||
|
/* We may need to do some setup of our own at this point before reading
|
||||||
|
* the data. After jpeg_start_decompress() we have the correct scaled
|
||||||
|
* output image dimensions available, as well as the output colormap
|
||||||
|
* if we asked for color quantization.
|
||||||
|
*/
|
||||||
|
//Create the image using output dimensions <ignacio>
|
||||||
|
//Create(cinfo.image_width, cinfo.image_height, 8*cinfo.output_components, CXIMAGE_FORMAT_JPG);
|
||||||
|
Create(cinfo.output_width, cinfo.output_height, 8*cinfo.output_components, CXIMAGE_FORMAT_JPG);
|
||||||
|
|
||||||
|
if (!pDib) longjmp(jerr.setjmp_buffer, 1); //<DP> check if the image has been created
|
||||||
|
|
||||||
|
if (is_exif){
|
||||||
|
#if CXIMAGEJPG_SUPPORT_EXIF
|
||||||
|
if ((info.ExifInfo.Xresolution != 0.0) && (info.ExifInfo.ResolutionUnit != 0))
|
||||||
|
SetXDPI((int32_t)(info.ExifInfo.Xresolution/info.ExifInfo.ResolutionUnit));
|
||||||
|
if ((info.ExifInfo.Yresolution != 0.0) && (info.ExifInfo.ResolutionUnit != 0))
|
||||||
|
SetYDPI((int32_t)(info.ExifInfo.Yresolution/info.ExifInfo.ResolutionUnit));
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
switch (cinfo.density_unit) {
|
||||||
|
case 0: // [andy] fix for aspect ratio...
|
||||||
|
if((cinfo.Y_density > 0) && (cinfo.X_density > 0)){
|
||||||
|
SetYDPI((int32_t)(GetXDPI()*(float(cinfo.Y_density)/float(cinfo.X_density))));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2: // [andy] fix: cinfo.X/Y_density is pixels per centimeter
|
||||||
|
SetXDPI((int32_t)floor(cinfo.X_density * 2.54 + 0.5));
|
||||||
|
SetYDPI((int32_t)floor(cinfo.Y_density * 2.54 + 0.5));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SetXDPI(cinfo.X_density);
|
||||||
|
SetYDPI(cinfo.Y_density);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cinfo.out_color_space==JCS_GRAYSCALE){
|
||||||
|
SetGrayPalette();
|
||||||
|
head.biClrUsed =256;
|
||||||
|
} else {
|
||||||
|
if (cinfo.quantize_colors){
|
||||||
|
SetPalette(cinfo.actual_number_of_colors, cinfo.colormap[0], cinfo.colormap[1], cinfo.colormap[2]);
|
||||||
|
head.biClrUsed=cinfo.actual_number_of_colors;
|
||||||
|
} else {
|
||||||
|
head.biClrUsed=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* JSAMPLEs per row in output buffer */
|
||||||
|
row_stride = cinfo.output_width * cinfo.output_components;
|
||||||
|
|
||||||
|
/* Make a one-row-high sample array that will go away when done with image */
|
||||||
|
buffer = (*cinfo.mem->alloc_sarray)
|
||||||
|
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
|
||||||
|
|
||||||
|
/* Step 6: while (scan lines remain to be read) */
|
||||||
|
/* jpeg_read_scanlines(...); */
|
||||||
|
/* Here we use the library's state variable cinfo.output_scanline as the
|
||||||
|
* loop counter, so that we don't have to keep track ourselves.
|
||||||
|
*/
|
||||||
|
iter.Upset();
|
||||||
|
while (cinfo.output_scanline < cinfo.output_height) {
|
||||||
|
|
||||||
|
if (info.nEscape) longjmp(jerr.setjmp_buffer, 1); // <vho> - cancel decoding
|
||||||
|
|
||||||
|
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
|
||||||
|
// info.nProgress = (int32_t)(100*cinfo.output_scanline/cinfo.output_height);
|
||||||
|
//<DP> Step 6a: CMYK->RGB */
|
||||||
|
if ((cinfo.num_components==4)&&(cinfo.quantize_colors==FALSE)){
|
||||||
|
uint8_t k,*dst,*src;
|
||||||
|
dst=iter.GetRow();
|
||||||
|
src=buffer[0];
|
||||||
|
for(int32_t x3=0,x4=0; x3<(int32_t)info.dwEffWidth && x4<row_stride; x3+=3, x4+=4){
|
||||||
|
k=src[x4+3];
|
||||||
|
dst[x3] =(uint8_t)((k * src[x4+2])/255);
|
||||||
|
dst[x3+1]=(uint8_t)((k * src[x4+1])/255);
|
||||||
|
dst[x3+2]=(uint8_t)((k * src[x4+0])/255);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Assume put_scanline_someplace wants a pointer and sample count. */
|
||||||
|
iter.SetRow(buffer[0], row_stride);
|
||||||
|
}
|
||||||
|
iter.PrevRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 7: Finish decompression */
|
||||||
|
(void) jpeg_finish_decompress(&cinfo);
|
||||||
|
/* We can ignore the return value since suspension is not possible
|
||||||
|
* with the stdio data source.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//<DP> Step 7A: Swap red and blue components
|
||||||
|
// not necessary if swapped red and blue definition in jmorecfg.h;ln322 <W. Morrison>
|
||||||
|
if ((cinfo.num_components==3)&&(cinfo.quantize_colors==FALSE)){
|
||||||
|
uint8_t* r0=GetBits();
|
||||||
|
for(int32_t y=0;y<head.biHeight;y++){
|
||||||
|
if (info.nEscape) longjmp(jerr.setjmp_buffer, 1); // <vho> - cancel decoding
|
||||||
|
RGBtoBGR(r0,3*head.biWidth);
|
||||||
|
r0+=info.dwEffWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 8: Release JPEG decompression object */
|
||||||
|
/* This is an important step since it will release a good deal of memory. */
|
||||||
|
jpeg_destroy_decompress(&cinfo);
|
||||||
|
|
||||||
|
/* At this point you may want to check to see whether any corrupt-data
|
||||||
|
* warnings occurred (test whether jerr.pub.num_warnings is nonzero).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* And we're done! */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageJPG::Encode(CxFile * hFile)
|
||||||
|
{
|
||||||
|
if (EncodeSafeCheck(hFile)) return false;
|
||||||
|
|
||||||
|
if (head.biClrUsed!=0 && !IsGrayScale()){
|
||||||
|
strcpy(info.szLastError,"JPEG can save only RGB or GreyScale images");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// necessary for EXIF, and for roll backs
|
||||||
|
int32_t pos=hFile->Tell();
|
||||||
|
|
||||||
|
/* This struct contains the JPEG compression parameters and pointers to
|
||||||
|
* working space (which is allocated as needed by the JPEG library).
|
||||||
|
* It is possible to have several such structures, representing multiple
|
||||||
|
* compression/decompression processes, in existence at once. We refer
|
||||||
|
* to any one struct (and its associated working data) as a "JPEG object".
|
||||||
|
*/
|
||||||
|
struct jpeg_compress_struct cinfo;
|
||||||
|
/* This struct represents a JPEG error handler. It is declared separately
|
||||||
|
* because applications often want to supply a specialized error handler
|
||||||
|
* (see the second half of this file for an example). But here we just
|
||||||
|
* take the easy way out and use the standard error handler, which will
|
||||||
|
* print a message on stderr and call exit() if compression fails.
|
||||||
|
* Note that this struct must live as int32_t as the main JPEG parameter
|
||||||
|
* struct, to avoid dangling-pointer problems.
|
||||||
|
*/
|
||||||
|
//struct jpeg_error_mgr jerr;
|
||||||
|
/* We use our private extension JPEG error handler. <CSC> */
|
||||||
|
struct jpg_error_mgr jerr;
|
||||||
|
jerr.buffer=info.szLastError;
|
||||||
|
/* More stuff */
|
||||||
|
int32_t row_stride; /* physical row width in image buffer */
|
||||||
|
JSAMPARRAY buffer; /* Output row buffer */
|
||||||
|
|
||||||
|
/* Step 1: allocate and initialize JPEG compression object */
|
||||||
|
/* We have to set up the error handler first, in case the initialization
|
||||||
|
* step fails. (Unlikely, but it could happen if you are out of memory.)
|
||||||
|
* This routine fills in the contents of struct jerr, and returns jerr's
|
||||||
|
* address which we place into the link field in cinfo.
|
||||||
|
*/
|
||||||
|
//cinfo.err = jpeg_std_error(&jerr); <CSC>
|
||||||
|
/* We set up the normal JPEG error routines, then override error_exit. */
|
||||||
|
cinfo.err = jpeg_std_error(&jerr.pub);
|
||||||
|
jerr.pub.error_exit = ima_jpeg_error_exit;
|
||||||
|
|
||||||
|
/* Establish the setjmp return context for my_error_exit to use. */
|
||||||
|
if (setjmp(jerr.setjmp_buffer)) {
|
||||||
|
/* If we get here, the JPEG code has signaled an error.
|
||||||
|
* We need to clean up the JPEG object, close the input file, and return.
|
||||||
|
*/
|
||||||
|
strcpy(info.szLastError, jerr.buffer); //<CSC>
|
||||||
|
jpeg_destroy_compress(&cinfo);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we can initialize the JPEG compression object. */
|
||||||
|
jpeg_create_compress(&cinfo);
|
||||||
|
/* Step 2: specify data destination (eg, a file) */
|
||||||
|
/* Note: steps 2 and 3 can be done in either order. */
|
||||||
|
/* Here we use the library-supplied code to send compressed data to a
|
||||||
|
* stdio stream. You can also write your own code to do something else.
|
||||||
|
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
|
||||||
|
* requires it in order to write binary files.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//jpeg_stdio_dest(&cinfo, outfile);
|
||||||
|
CxFileJpg dest(hFile);
|
||||||
|
cinfo.dest = &dest;
|
||||||
|
|
||||||
|
/* Step 3: set parameters for compression */
|
||||||
|
/* First we supply a description of the input image.
|
||||||
|
* Four fields of the cinfo struct must be filled in:
|
||||||
|
*/
|
||||||
|
cinfo.image_width = GetWidth(); // image width and height, in pixels
|
||||||
|
cinfo.image_height = GetHeight();
|
||||||
|
|
||||||
|
if (IsGrayScale()){
|
||||||
|
cinfo.input_components = 1; // # of color components per pixel
|
||||||
|
cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */
|
||||||
|
} else {
|
||||||
|
cinfo.input_components = 3; // # of color components per pixel
|
||||||
|
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now use the library's routine to set default compression parameters.
|
||||||
|
* (You must set at least cinfo.in_color_space before calling this,
|
||||||
|
* since the defaults depend on the source color space.)
|
||||||
|
*/
|
||||||
|
jpeg_set_defaults(&cinfo);
|
||||||
|
/* Now you can set any non-default parameters you wish to.
|
||||||
|
* Here we just illustrate the use of quality (quantization table) scaling:
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint32_t dwCodecOptions = GetCodecOption(CXIMAGE_FORMAT_JPG); //[nm_114]
|
||||||
|
//#ifdef C_ARITH_CODING_SUPPORTED
|
||||||
|
if ((dwCodecOptions & ENCODE_ARITHMETIC) != 0)
|
||||||
|
cinfo.arith_code = TRUE;
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
//#ifdef ENTROPY_OPT_SUPPORTED
|
||||||
|
if ((dwCodecOptions & ENCODE_OPTIMIZE) != 0)
|
||||||
|
cinfo.optimize_coding = TRUE;
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
if ((dwCodecOptions & ENCODE_GRAYSCALE) != 0)
|
||||||
|
jpeg_set_colorspace(&cinfo, JCS_GRAYSCALE);
|
||||||
|
|
||||||
|
if ((dwCodecOptions & ENCODE_SMOOTHING) != 0)
|
||||||
|
cinfo.smoothing_factor = m_nSmoothing;
|
||||||
|
|
||||||
|
jpeg_set_quality(&cinfo, GetJpegQuality(), (dwCodecOptions & ENCODE_BASELINE) != 0);
|
||||||
|
|
||||||
|
//#ifdef C_PROGRESSIVE_SUPPORTED
|
||||||
|
if ((dwCodecOptions & ENCODE_PROGRESSIVE) != 0)
|
||||||
|
jpeg_simple_progression(&cinfo);
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
#ifdef C_LOSSLESS_SUPPORTED
|
||||||
|
if ((dwCodecOptions & ENCODE_LOSSLESS) != 0)
|
||||||
|
jpeg_simple_lossless(&cinfo, m_nPredictor, m_nPointTransform);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//SetCodecOption(ENCODE_SUBSAMPLE_444 | GetCodecOption(CXIMAGE_FORMAT_JPG),CXIMAGE_FORMAT_JPG);
|
||||||
|
|
||||||
|
// 2x2, 1x1, 1x1 (4:1:1) : High (default sub sampling)
|
||||||
|
cinfo.comp_info[0].h_samp_factor = 2;
|
||||||
|
cinfo.comp_info[0].v_samp_factor = 2;
|
||||||
|
cinfo.comp_info[1].h_samp_factor = 1;
|
||||||
|
cinfo.comp_info[1].v_samp_factor = 1;
|
||||||
|
cinfo.comp_info[2].h_samp_factor = 1;
|
||||||
|
cinfo.comp_info[2].v_samp_factor = 1;
|
||||||
|
|
||||||
|
if ((dwCodecOptions & ENCODE_SUBSAMPLE_422) != 0){
|
||||||
|
// 2x1, 1x1, 1x1 (4:2:2) : Medium
|
||||||
|
cinfo.comp_info[0].h_samp_factor = 2;
|
||||||
|
cinfo.comp_info[0].v_samp_factor = 1;
|
||||||
|
cinfo.comp_info[1].h_samp_factor = 1;
|
||||||
|
cinfo.comp_info[1].v_samp_factor = 1;
|
||||||
|
cinfo.comp_info[2].h_samp_factor = 1;
|
||||||
|
cinfo.comp_info[2].v_samp_factor = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dwCodecOptions & ENCODE_SUBSAMPLE_444) != 0){
|
||||||
|
// 1x1 1x1 1x1 (4:4:4) : None
|
||||||
|
cinfo.comp_info[0].h_samp_factor = 1;
|
||||||
|
cinfo.comp_info[0].v_samp_factor = 1;
|
||||||
|
cinfo.comp_info[1].h_samp_factor = 1;
|
||||||
|
cinfo.comp_info[1].v_samp_factor = 1;
|
||||||
|
cinfo.comp_info[2].h_samp_factor = 1;
|
||||||
|
cinfo.comp_info[2].v_samp_factor = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cinfo.density_unit=1;
|
||||||
|
cinfo.X_density=(uint16_t)GetXDPI();
|
||||||
|
cinfo.Y_density=(uint16_t)GetYDPI();
|
||||||
|
|
||||||
|
/* Step 4: Start compressor */
|
||||||
|
/* TRUE ensures that we will write a complete interchange-JPEG file.
|
||||||
|
* Pass TRUE unless you are very sure of what you're doing.
|
||||||
|
*/
|
||||||
|
jpeg_start_compress(&cinfo, TRUE);
|
||||||
|
|
||||||
|
/* Step 5: while (scan lines remain to be written) */
|
||||||
|
/* jpeg_write_scanlines(...); */
|
||||||
|
/* Here we use the library's state variable cinfo.next_scanline as the
|
||||||
|
* loop counter, so that we don't have to keep track ourselves.
|
||||||
|
* To keep things simple, we pass one scanline per call; you can pass
|
||||||
|
* more if you wish, though.
|
||||||
|
*/
|
||||||
|
row_stride = info.dwEffWidth; /* JSAMPLEs per row in image_buffer */
|
||||||
|
|
||||||
|
//<DP> "8+row_stride" fix heap deallocation problem during debug???
|
||||||
|
buffer = (*cinfo.mem->alloc_sarray)
|
||||||
|
((j_common_ptr) &cinfo, JPOOL_IMAGE, 8+row_stride, 1);
|
||||||
|
|
||||||
|
CImageIterator iter(this);
|
||||||
|
|
||||||
|
iter.Upset();
|
||||||
|
while (cinfo.next_scanline < cinfo.image_height) {
|
||||||
|
// info.nProgress = (int32_t)(100*cinfo.next_scanline/cinfo.image_height);
|
||||||
|
iter.GetRow(buffer[0], row_stride);
|
||||||
|
// not necessary if swapped red and blue definition in jmorecfg.h;ln322 <W. Morrison>
|
||||||
|
if (head.biClrUsed==0){ // swap R & B for RGB images
|
||||||
|
RGBtoBGR(buffer[0], row_stride); // Lance : 1998/09/01 : Bug ID: EXP-2.1.1-9
|
||||||
|
}
|
||||||
|
iter.PrevRow();
|
||||||
|
(void) jpeg_write_scanlines(&cinfo, buffer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 6: Finish compression */
|
||||||
|
jpeg_finish_compress(&cinfo);
|
||||||
|
|
||||||
|
/* Step 7: release JPEG compression object */
|
||||||
|
/* This is an important step since it will release a good deal of memory. */
|
||||||
|
jpeg_destroy_compress(&cinfo);
|
||||||
|
|
||||||
|
|
||||||
|
#if CXIMAGEJPG_SUPPORT_EXIF
|
||||||
|
if (m_exif && m_exif->m_exifinfo->IsExif){
|
||||||
|
// discard useless sections (if any) read from original image
|
||||||
|
m_exif->DiscardAllButExif();
|
||||||
|
// read new created image, to split the sections
|
||||||
|
hFile->Seek(pos,SEEK_SET);
|
||||||
|
m_exif->DecodeExif(hFile,EXIF_READ_IMAGE);
|
||||||
|
// save back the image, adding EXIF section
|
||||||
|
hFile->Seek(pos,SEEK_SET);
|
||||||
|
m_exif->EncodeExif(hFile);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* And we're done! */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_JPG
|
||||||
|
|
||||||
@@ -0,0 +1,283 @@
|
|||||||
|
/*
|
||||||
|
* File: ximajpg.h
|
||||||
|
* Purpose: JPG Image Class Loader and Writer
|
||||||
|
*/
|
||||||
|
/* ==========================================================
|
||||||
|
* CxImageJPG (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it
|
||||||
|
* For conditions of distribution and use, see copyright notice in ximage.h
|
||||||
|
*
|
||||||
|
* Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes
|
||||||
|
*
|
||||||
|
* Special thanks to Chris Shearer Cooper for CxFileJpg tips & code
|
||||||
|
*
|
||||||
|
* EXIF support based on jhead-1.8 by Matthias Wandel <mwandel(at)rim(dot)net>
|
||||||
|
*
|
||||||
|
* original CImageJPG and CImageIterator implementation are:
|
||||||
|
* Copyright: (c) 1995, Alejandro Aguilar Sierra <asierra(at)servidor(dot)unam(dot)mx>
|
||||||
|
*
|
||||||
|
* This software is based in part on the work of the Independent JPEG Group.
|
||||||
|
* Copyright (C) 1991-1998, Thomas G. Lane.
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
#if !defined(__ximaJPEG_h)
|
||||||
|
#define __ximaJPEG_h
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_JPG
|
||||||
|
|
||||||
|
#define CXIMAGEJPG_SUPPORT_EXIF CXIMAGE_SUPPORT_EXIF
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#ifdef _LINUX
|
||||||
|
#include <jpeglib.h>
|
||||||
|
#include <jerror.h>
|
||||||
|
#else
|
||||||
|
#include "../jpeg/jpeglib.h"
|
||||||
|
#include "../jpeg/jerror.h"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
class DLL_EXP CxImageJPG: public CxImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CxImageJPG();
|
||||||
|
~CxImageJPG();
|
||||||
|
|
||||||
|
// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_JPG);}
|
||||||
|
// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_JPG);}
|
||||||
|
bool Decode(CxFile * hFile);
|
||||||
|
bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
bool Encode(CxFile * hFile);
|
||||||
|
bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EXIF support based on jhead-1.8 by Matthias Wandel <mwandel(at)rim(dot)net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if CXIMAGEJPG_SUPPORT_EXIF
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// JPEG markers consist of one or more 0xFF bytes, followed by a marker
|
||||||
|
// code byte (which is not an FF). Here are the marker codes of interest
|
||||||
|
// in this program. (See jdmarker.c for a more complete list.)
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define M_SOF0 0xC0 // Start Of Frame N
|
||||||
|
#define M_SOF1 0xC1 // N indicates which compression process
|
||||||
|
#define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use
|
||||||
|
#define M_SOF3 0xC3
|
||||||
|
#define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers
|
||||||
|
#define M_SOF6 0xC6
|
||||||
|
#define M_SOF7 0xC7
|
||||||
|
#define M_SOF9 0xC9
|
||||||
|
#define M_SOF10 0xCA
|
||||||
|
#define M_SOF11 0xCB
|
||||||
|
#define M_SOF13 0xCD
|
||||||
|
#define M_SOF14 0xCE
|
||||||
|
#define M_SOF15 0xCF
|
||||||
|
#define M_SOI 0xD8 // Start Of Image (beginning of datastream)
|
||||||
|
#define M_EOI 0xD9 // End Of Image (end of datastream)
|
||||||
|
#define M_SOS 0xDA // Start Of Scan (begins compressed data)
|
||||||
|
#define M_JFIF 0xE0 // Jfif marker
|
||||||
|
#define M_EXIF 0xE1 // Exif marker
|
||||||
|
#define M_COM 0xFE // COMment
|
||||||
|
|
||||||
|
#define PSEUDO_IMAGE_MARKER 0x123; // Extra value.
|
||||||
|
|
||||||
|
#define EXIF_READ_EXIF 0x01
|
||||||
|
#define EXIF_READ_IMAGE 0x02
|
||||||
|
#define EXIF_READ_ALL 0x03
|
||||||
|
|
||||||
|
class DLL_EXP CxExifInfo
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef struct tag_Section_t{
|
||||||
|
uint8_t* Data;
|
||||||
|
int32_t Type;
|
||||||
|
unsigned Size;
|
||||||
|
} Section_t;
|
||||||
|
|
||||||
|
public:
|
||||||
|
EXIFINFO* m_exifinfo;
|
||||||
|
char m_szLastError[256];
|
||||||
|
CxExifInfo(EXIFINFO* info = NULL);
|
||||||
|
~CxExifInfo();
|
||||||
|
bool DecodeExif(CxFile * hFile, int32_t nReadMode = EXIF_READ_EXIF);
|
||||||
|
bool EncodeExif(CxFile * hFile);
|
||||||
|
void DiscardAllButExif();
|
||||||
|
protected:
|
||||||
|
bool process_EXIF(uint8_t * CharBuf, uint32_t length);
|
||||||
|
void process_COM (const uint8_t * Data, int32_t length);
|
||||||
|
void process_SOFn (const uint8_t * Data, int32_t marker);
|
||||||
|
int32_t Get16u(void * Short);
|
||||||
|
int32_t Get16m(void * Short);
|
||||||
|
int32_t Get32s(void * Long);
|
||||||
|
uint32_t Get32u(void * Long);
|
||||||
|
double ConvertAnyFormat(void * ValuePtr, int32_t Format);
|
||||||
|
void* FindSection(int32_t SectionType);
|
||||||
|
bool ProcessExifDir(uint8_t * DirStart, uint8_t * OffsetBase, unsigned ExifLength,
|
||||||
|
EXIFINFO * const pInfo, uint8_t ** const LastExifRefdP, int32_t NestingLevel=0);
|
||||||
|
int32_t ExifImageWidth;
|
||||||
|
int32_t MotorolaOrder;
|
||||||
|
Section_t Sections[MAX_SECTIONS];
|
||||||
|
int32_t SectionsRead;
|
||||||
|
bool freeinfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
CxExifInfo* m_exif;
|
||||||
|
bool DecodeExif(CxFile * hFile);
|
||||||
|
bool DecodeExif(FILE * hFile) { CxIOFile file(hFile); return DecodeExif(&file); }
|
||||||
|
bool GetExifThumbnail(const TCHAR *filename, const TCHAR *outname, int32_t type);
|
||||||
|
|
||||||
|
#endif //CXIMAGEJPG_SUPPORT_EXIF
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////////////////////// C x F i l e J p g ////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// thanks to Chris Shearer Cooper <cscooper(at)frii(dot)com>
|
||||||
|
class CxFileJpg : public jpeg_destination_mgr, public jpeg_source_mgr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum { eBufSize = 4096 };
|
||||||
|
|
||||||
|
CxFileJpg(CxFile* pFile)
|
||||||
|
{
|
||||||
|
m_pFile = pFile;
|
||||||
|
|
||||||
|
init_destination = InitDestination;
|
||||||
|
empty_output_buffer = EmptyOutputBuffer;
|
||||||
|
term_destination = TermDestination;
|
||||||
|
|
||||||
|
init_source = InitSource;
|
||||||
|
fill_input_buffer = FillInputBuffer;
|
||||||
|
skip_input_data = SkipInputData;
|
||||||
|
resync_to_restart = jpeg_resync_to_restart; // use default method
|
||||||
|
term_source = TermSource;
|
||||||
|
next_input_byte = NULL; //* => next byte to read from buffer
|
||||||
|
bytes_in_buffer = 0; //* # of bytes remaining in buffer
|
||||||
|
|
||||||
|
m_pBuffer = new uint8_t[eBufSize];
|
||||||
|
}
|
||||||
|
~CxFileJpg()
|
||||||
|
{
|
||||||
|
delete [] m_pBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InitDestination(j_compress_ptr cinfo)
|
||||||
|
{
|
||||||
|
CxFileJpg* pDest = (CxFileJpg*)cinfo->dest;
|
||||||
|
pDest->next_output_byte = pDest->m_pBuffer;
|
||||||
|
pDest->free_in_buffer = eBufSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
|
||||||
|
{
|
||||||
|
CxFileJpg* pDest = (CxFileJpg*)cinfo->dest;
|
||||||
|
if (pDest->m_pFile->Write(pDest->m_pBuffer,1,eBufSize)!=(size_t)eBufSize)
|
||||||
|
ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||||
|
pDest->next_output_byte = pDest->m_pBuffer;
|
||||||
|
pDest->free_in_buffer = eBufSize;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void TermDestination(j_compress_ptr cinfo)
|
||||||
|
{
|
||||||
|
CxFileJpg* pDest = (CxFileJpg*)cinfo->dest;
|
||||||
|
size_t datacount = eBufSize - pDest->free_in_buffer;
|
||||||
|
/* Write any data remaining in the buffer */
|
||||||
|
if (datacount > 0) {
|
||||||
|
if (!pDest->m_pFile->Write(pDest->m_pBuffer,1,datacount))
|
||||||
|
ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||||
|
}
|
||||||
|
pDest->m_pFile->Flush();
|
||||||
|
/* Make sure we wrote the output file OK */
|
||||||
|
if (pDest->m_pFile->Error()) ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InitSource(j_decompress_ptr cinfo)
|
||||||
|
{
|
||||||
|
CxFileJpg* pSource = (CxFileJpg*)cinfo->src;
|
||||||
|
pSource->m_bStartOfFile = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean FillInputBuffer(j_decompress_ptr cinfo)
|
||||||
|
{
|
||||||
|
size_t nbytes;
|
||||||
|
CxFileJpg* pSource = (CxFileJpg*)cinfo->src;
|
||||||
|
nbytes = pSource->m_pFile->Read(pSource->m_pBuffer,1,eBufSize);
|
||||||
|
if (nbytes <= 0){
|
||||||
|
if (pSource->m_bStartOfFile) //* Treat empty input file as fatal error
|
||||||
|
ERREXIT(cinfo, JERR_INPUT_EMPTY);
|
||||||
|
WARNMS(cinfo, JWRN_JPEG_EOF);
|
||||||
|
// Insert a fake EOI marker
|
||||||
|
pSource->m_pBuffer[0] = (JOCTET) 0xFF;
|
||||||
|
pSource->m_pBuffer[1] = (JOCTET) JPEG_EOI;
|
||||||
|
nbytes = 2;
|
||||||
|
}
|
||||||
|
pSource->next_input_byte = pSource->m_pBuffer;
|
||||||
|
pSource->bytes_in_buffer = nbytes;
|
||||||
|
pSource->m_bStartOfFile = FALSE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SkipInputData(j_decompress_ptr cinfo, long num_bytes)
|
||||||
|
{
|
||||||
|
CxFileJpg* pSource = (CxFileJpg*)cinfo->src;
|
||||||
|
if (num_bytes > 0){
|
||||||
|
while (num_bytes > (int32_t)pSource->bytes_in_buffer){
|
||||||
|
num_bytes -= (int32_t)pSource->bytes_in_buffer;
|
||||||
|
FillInputBuffer(cinfo);
|
||||||
|
// note we assume that fill_input_buffer will never return FALSE,
|
||||||
|
// so suspension need not be handled.
|
||||||
|
}
|
||||||
|
pSource->next_input_byte += (size_t) num_bytes;
|
||||||
|
pSource->bytes_in_buffer -= (size_t) num_bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void TermSource(j_decompress_ptr /*cinfo*/)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
CxFile *m_pFile;
|
||||||
|
uint8_t *m_pBuffer;
|
||||||
|
bool m_bStartOfFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum CODEC_OPTION
|
||||||
|
{
|
||||||
|
ENCODE_BASELINE = 0x1,
|
||||||
|
ENCODE_ARITHMETIC = 0x2,
|
||||||
|
ENCODE_GRAYSCALE = 0x4,
|
||||||
|
ENCODE_OPTIMIZE = 0x8,
|
||||||
|
ENCODE_PROGRESSIVE = 0x10,
|
||||||
|
ENCODE_LOSSLESS = 0x20,
|
||||||
|
ENCODE_SMOOTHING = 0x40,
|
||||||
|
DECODE_GRAYSCALE = 0x80,
|
||||||
|
DECODE_QUANTIZE = 0x100,
|
||||||
|
DECODE_DITHER = 0x200,
|
||||||
|
DECODE_ONEPASS = 0x400,
|
||||||
|
DECODE_NOSMOOTH = 0x800,
|
||||||
|
ENCODE_SUBSAMPLE_422 = 0x1000,
|
||||||
|
ENCODE_SUBSAMPLE_444 = 0x2000
|
||||||
|
};
|
||||||
|
|
||||||
|
int32_t m_nPredictor;
|
||||||
|
int32_t m_nPointTransform;
|
||||||
|
int32_t m_nSmoothing;
|
||||||
|
int32_t m_nQuantize;
|
||||||
|
J_DITHER_MODE m_nDither;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,367 @@
|
|||||||
|
// xImalpha.cpp : Alpha channel functions
|
||||||
|
/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \sa AlphaSetMax
|
||||||
|
*/
|
||||||
|
uint8_t CxImage::AlphaGetMax() const
|
||||||
|
{
|
||||||
|
return info.nAlphaMax;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Sets global Alpha (opacity) value applied to the whole image,
|
||||||
|
* valid only for painting functions.
|
||||||
|
* \param nAlphaMax: can be from 0 to 255
|
||||||
|
*/
|
||||||
|
void CxImage::AlphaSetMax(uint8_t nAlphaMax)
|
||||||
|
{
|
||||||
|
info.nAlphaMax=nAlphaMax;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Checks if the image has a valid alpha channel.
|
||||||
|
*/
|
||||||
|
bool CxImage::AlphaIsValid()
|
||||||
|
{
|
||||||
|
return pAlpha!=0;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Enables the alpha palette, so the Draw() function changes its behavior.
|
||||||
|
*/
|
||||||
|
void CxImage::AlphaPaletteEnable(bool enable)
|
||||||
|
{
|
||||||
|
info.bAlphaPaletteEnabled=enable;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* True if the alpha palette is enabled for painting.
|
||||||
|
*/
|
||||||
|
bool CxImage::AlphaPaletteIsEnabled()
|
||||||
|
{
|
||||||
|
return info.bAlphaPaletteEnabled;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Sets the alpha channel to full transparent. AlphaSet(0) has the same effect
|
||||||
|
*/
|
||||||
|
void CxImage::AlphaClear()
|
||||||
|
{
|
||||||
|
if (pAlpha) memset(pAlpha,0,head.biWidth * head.biHeight);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Sets the alpha level for the whole image.
|
||||||
|
* \param level : from 0 (transparent) to 255 (opaque)
|
||||||
|
*/
|
||||||
|
void CxImage::AlphaSet(uint8_t level)
|
||||||
|
{
|
||||||
|
if (pAlpha) memset(pAlpha,level,head.biWidth * head.biHeight);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Allocates an empty (opaque) alpha channel.
|
||||||
|
*/
|
||||||
|
bool CxImage::AlphaCreate()
|
||||||
|
{
|
||||||
|
if (pAlpha==NULL) {
|
||||||
|
pAlpha = (uint8_t*)malloc(head.biWidth * head.biHeight);
|
||||||
|
if (pAlpha) memset(pAlpha,255,head.biWidth * head.biHeight);
|
||||||
|
}
|
||||||
|
return (pAlpha!=0);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::AlphaDelete()
|
||||||
|
{
|
||||||
|
if (pAlpha) { free(pAlpha); pAlpha=0; }
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::AlphaInvert()
|
||||||
|
{
|
||||||
|
if (pAlpha) {
|
||||||
|
uint8_t *iSrc=pAlpha;
|
||||||
|
int32_t n=head.biHeight*head.biWidth;
|
||||||
|
for(int32_t i=0; i < n; i++){
|
||||||
|
*iSrc=(uint8_t)~(*(iSrc));
|
||||||
|
iSrc++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Imports an existing alpa channel from another image with the same width and height.
|
||||||
|
*/
|
||||||
|
bool CxImage::AlphaCopy(CxImage &from)
|
||||||
|
{
|
||||||
|
if (from.pAlpha == NULL || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight) return false;
|
||||||
|
if (pAlpha==NULL) pAlpha = (uint8_t*)malloc(head.biWidth * head.biHeight);
|
||||||
|
if (pAlpha==NULL) return false;
|
||||||
|
memcpy(pAlpha,from.pAlpha,head.biWidth * head.biHeight);
|
||||||
|
info.nAlphaMax=from.info.nAlphaMax;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Creates the alpha channel from a gray scale image.
|
||||||
|
*/
|
||||||
|
bool CxImage::AlphaSet(CxImage &from)
|
||||||
|
{
|
||||||
|
if (!from.IsGrayScale() || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight) return false;
|
||||||
|
if (pAlpha==NULL) pAlpha = (uint8_t*)malloc(head.biWidth * head.biHeight);
|
||||||
|
uint8_t* src = from.info.pImage;
|
||||||
|
uint8_t* dst = pAlpha;
|
||||||
|
if (src==NULL || dst==NULL) return false;
|
||||||
|
for (int32_t y=0; y<head.biHeight; y++){
|
||||||
|
memcpy(dst,src,head.biWidth);
|
||||||
|
dst += head.biWidth;
|
||||||
|
src += from.info.dwEffWidth;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Sets the alpha level for a single pixel
|
||||||
|
*/
|
||||||
|
void CxImage::AlphaSet(const int32_t x,const int32_t y,const uint8_t level)
|
||||||
|
{
|
||||||
|
if (pAlpha && IsInside(x,y)) pAlpha[x+y*head.biWidth]=level;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Gets the alpha level for a single pixel
|
||||||
|
*/
|
||||||
|
uint8_t CxImage::AlphaGet(const int32_t x,const int32_t y)
|
||||||
|
{
|
||||||
|
if (pAlpha && IsInside(x,y)) return pAlpha[x+y*head.biWidth];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Returns pointer to alpha data for pixel (x,y).
|
||||||
|
*
|
||||||
|
* \author ***bd*** 2.2004
|
||||||
|
*/
|
||||||
|
uint8_t* CxImage::AlphaGetPointer(const int32_t x,const int32_t y)
|
||||||
|
{
|
||||||
|
if (pAlpha && IsInside(x,y)) return pAlpha+x+y*head.biWidth;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Get alpha value without boundscheck (a bit faster). Pixel must be inside the image.
|
||||||
|
*
|
||||||
|
* \author ***bd*** 2.2004
|
||||||
|
*/
|
||||||
|
uint8_t CxImage::BlindAlphaGet(const int32_t x,const int32_t y)
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
if (!IsInside(x,y) || (pAlpha==0))
|
||||||
|
#if CXIMAGE_SUPPORT_EXCEPTION_HANDLING
|
||||||
|
throw 0;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return pAlpha[x+y*head.biWidth];
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Resets the alpha palette
|
||||||
|
*/
|
||||||
|
void CxImage::AlphaPaletteClear()
|
||||||
|
{
|
||||||
|
RGBQUAD c;
|
||||||
|
for(uint16_t ip=0; ip<head.biClrUsed;ip++){
|
||||||
|
c=GetPaletteColor((uint8_t)ip);
|
||||||
|
c.rgbReserved=0;
|
||||||
|
SetPaletteColor((uint8_t)ip,c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Checks if the image has a valid alpha palette.
|
||||||
|
*/
|
||||||
|
bool CxImage::AlphaPaletteIsValid()
|
||||||
|
{
|
||||||
|
RGBQUAD c;
|
||||||
|
for(uint16_t ip=0; ip<head.biClrUsed;ip++){
|
||||||
|
c=GetPaletteColor((uint8_t)ip);
|
||||||
|
if (c.rgbReserved != 0) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Blends the alpha channel and the alpha palette with the pixels. The result is a 24 bit image.
|
||||||
|
* The background color can be selected using SetTransColor().
|
||||||
|
*/
|
||||||
|
void CxImage::AlphaStrip()
|
||||||
|
{
|
||||||
|
bool bAlphaPaletteIsValid = AlphaPaletteIsValid();
|
||||||
|
bool bAlphaIsValid = AlphaIsValid();
|
||||||
|
if (!(bAlphaIsValid || bAlphaPaletteIsValid)) return;
|
||||||
|
RGBQUAD c;
|
||||||
|
int32_t a, a1;
|
||||||
|
if (head.biBitCount==24){
|
||||||
|
for(int32_t y=0; y<head.biHeight; y++){
|
||||||
|
for(int32_t x=0; x<head.biWidth; x++){
|
||||||
|
c = BlindGetPixelColor(x,y);
|
||||||
|
if (bAlphaIsValid) a=(BlindAlphaGet(x,y)*info.nAlphaMax)/255; else a=info.nAlphaMax;
|
||||||
|
a1 = 256-a;
|
||||||
|
c.rgbBlue = (uint8_t)((c.rgbBlue * a + a1 * info.nBkgndColor.rgbBlue)>>8);
|
||||||
|
c.rgbGreen = (uint8_t)((c.rgbGreen * a + a1 * info.nBkgndColor.rgbGreen)>>8);
|
||||||
|
c.rgbRed = (uint8_t)((c.rgbRed * a + a1 * info.nBkgndColor.rgbRed)>>8);
|
||||||
|
BlindSetPixelColor(x,y,c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AlphaDelete();
|
||||||
|
} else {
|
||||||
|
CxImage tmp(head.biWidth,head.biHeight,24);
|
||||||
|
if (!tmp.IsValid()){
|
||||||
|
strcpy(info.szLastError,tmp.GetLastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int32_t y=0; y<head.biHeight; y++){
|
||||||
|
for(int32_t x=0; x<head.biWidth; x++){
|
||||||
|
c = BlindGetPixelColor(x,y);
|
||||||
|
if (bAlphaIsValid) a=(BlindAlphaGet(x,y)*info.nAlphaMax)/255; else a=info.nAlphaMax;
|
||||||
|
if (bAlphaPaletteIsValid) a=(c.rgbReserved*a)/255;
|
||||||
|
a1 = 256-a;
|
||||||
|
c.rgbBlue = (uint8_t)((c.rgbBlue * a + a1 * info.nBkgndColor.rgbBlue)>>8);
|
||||||
|
c.rgbGreen = (uint8_t)((c.rgbGreen * a + a1 * info.nBkgndColor.rgbGreen)>>8);
|
||||||
|
c.rgbRed = (uint8_t)((c.rgbRed * a + a1 * info.nBkgndColor.rgbRed)>>8);
|
||||||
|
tmp.BlindSetPixelColor(x,y,c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Transfer(tmp);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImage::AlphaFlip()
|
||||||
|
{
|
||||||
|
if (!pAlpha) return false;
|
||||||
|
|
||||||
|
uint8_t *buff = (uint8_t*)malloc(head.biWidth);
|
||||||
|
if (!buff) return false;
|
||||||
|
|
||||||
|
uint8_t *iSrc,*iDst;
|
||||||
|
iSrc = pAlpha + (head.biHeight-1)*head.biWidth;
|
||||||
|
iDst = pAlpha;
|
||||||
|
for (int32_t i=0; i<(head.biHeight/2); ++i)
|
||||||
|
{
|
||||||
|
memcpy(buff, iSrc, head.biWidth);
|
||||||
|
memcpy(iSrc, iDst, head.biWidth);
|
||||||
|
memcpy(iDst, buff, head.biWidth);
|
||||||
|
iSrc-=head.biWidth;
|
||||||
|
iDst+=head.biWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buff);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImage::AlphaMirror()
|
||||||
|
{
|
||||||
|
if (!pAlpha) return false;
|
||||||
|
uint8_t* pAlpha2 = (uint8_t*)malloc(head.biWidth * head.biHeight);
|
||||||
|
if (!pAlpha2) return false;
|
||||||
|
uint8_t *iSrc,*iDst;
|
||||||
|
int32_t wdt=head.biWidth-1;
|
||||||
|
iSrc=pAlpha + wdt;
|
||||||
|
iDst=pAlpha2;
|
||||||
|
for(int32_t y=0; y < head.biHeight; y++){
|
||||||
|
for(int32_t x=0; x <= wdt; x++)
|
||||||
|
*(iDst+x)=*(iSrc-x);
|
||||||
|
iSrc+=head.biWidth;
|
||||||
|
iDst+=head.biWidth;
|
||||||
|
}
|
||||||
|
free(pAlpha);
|
||||||
|
pAlpha=pAlpha2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Exports the alpha channel in a 8bpp grayscale image.
|
||||||
|
*/
|
||||||
|
bool CxImage::AlphaSplit(CxImage *dest)
|
||||||
|
{
|
||||||
|
if (!pAlpha || !dest) return false;
|
||||||
|
|
||||||
|
CxImage tmp(head.biWidth,head.biHeight,8);
|
||||||
|
if (!tmp.IsValid()){
|
||||||
|
strcpy(info.szLastError,tmp.GetLastError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* src = pAlpha;
|
||||||
|
uint8_t* dst = tmp.info.pImage;
|
||||||
|
for (int32_t y=0; y<head.biHeight; y++){
|
||||||
|
memcpy(dst,src,head.biWidth);
|
||||||
|
dst += tmp.info.dwEffWidth;
|
||||||
|
src += head.biWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp.SetGrayPalette();
|
||||||
|
dest->Transfer(tmp);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Exports the alpha palette channel in a 8bpp grayscale image.
|
||||||
|
*/
|
||||||
|
bool CxImage::AlphaPaletteSplit(CxImage *dest)
|
||||||
|
{
|
||||||
|
if (!AlphaPaletteIsValid() || !dest) return false;
|
||||||
|
|
||||||
|
CxImage tmp(head.biWidth,head.biHeight,8);
|
||||||
|
if (!tmp.IsValid()){
|
||||||
|
strcpy(info.szLastError,tmp.GetLastError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int32_t y=0; y<head.biHeight; y++){
|
||||||
|
for(int32_t x=0; x<head.biWidth; x++){
|
||||||
|
tmp.BlindSetPixelIndex(x,y,BlindGetPixelColor(x,y).rgbReserved);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp.SetGrayPalette();
|
||||||
|
dest->Transfer(tmp);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Merge in the alpha layer the transparent color mask
|
||||||
|
* (previously set with SetTransColor or SetTransIndex)
|
||||||
|
*/
|
||||||
|
bool CxImage::AlphaFromTransparency()
|
||||||
|
{
|
||||||
|
if (!IsValid() || !IsTransparent())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
AlphaCreate();
|
||||||
|
|
||||||
|
for(int32_t y=0; y<head.biHeight; y++){
|
||||||
|
for(int32_t x=0; x<head.biWidth; x++){
|
||||||
|
if (IsTransparent(x,y)){
|
||||||
|
AlphaSet(x,y,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
// xImaLyr.cpp : Layers functions
|
||||||
|
/* 21/04/2003 v1.00 - Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_LAYERS
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* If the object is an internal layer, GetParent return its parent in the hierarchy.
|
||||||
|
*/
|
||||||
|
CxImage* CxImage::GetParent() const
|
||||||
|
{
|
||||||
|
return info.pParent;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Number of layers allocated directly by the object.
|
||||||
|
*/
|
||||||
|
int32_t CxImage::GetNumLayers() const
|
||||||
|
{
|
||||||
|
return info.nNumLayers;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Creates an empty layer. If position is less than 0, the new layer will be placed in the last position
|
||||||
|
*/
|
||||||
|
bool CxImage::LayerCreate(int32_t position)
|
||||||
|
{
|
||||||
|
if ( position < 0 || position > info.nNumLayers ) position = info.nNumLayers;
|
||||||
|
|
||||||
|
CxImage** ptmp = new CxImage*[info.nNumLayers + 1];
|
||||||
|
if (ptmp==0) return false;
|
||||||
|
|
||||||
|
int32_t i=0;
|
||||||
|
for (int32_t n=0; n<info.nNumLayers; n++){
|
||||||
|
if (position == n){
|
||||||
|
ptmp[n] = new CxImage();
|
||||||
|
i=1;
|
||||||
|
}
|
||||||
|
ptmp[n+i]=ppLayers[n];
|
||||||
|
}
|
||||||
|
if (i==0) ptmp[info.nNumLayers] = new CxImage();
|
||||||
|
|
||||||
|
if (ptmp[position]){
|
||||||
|
ptmp[position]->info.pParent = this;
|
||||||
|
} else {
|
||||||
|
free(ptmp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
info.nNumLayers++;
|
||||||
|
delete [] ppLayers;
|
||||||
|
ppLayers = ptmp;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Deletes a layer. If position is less than 0, the last layer will be deleted
|
||||||
|
*/
|
||||||
|
bool CxImage::LayerDelete(int32_t position)
|
||||||
|
{
|
||||||
|
if ( position >= info.nNumLayers ) return false;
|
||||||
|
if ( position < 0) position = info.nNumLayers - 1;
|
||||||
|
if ( position < 0) return false;
|
||||||
|
|
||||||
|
if (info.nNumLayers>1){
|
||||||
|
|
||||||
|
CxImage** ptmp = new CxImage*[info.nNumLayers - 1];
|
||||||
|
if (ptmp==0) return false;
|
||||||
|
|
||||||
|
int32_t i=0;
|
||||||
|
for (int32_t n=0; n<info.nNumLayers; n++){
|
||||||
|
if (position == n){
|
||||||
|
delete ppLayers[n];
|
||||||
|
i=1;
|
||||||
|
}
|
||||||
|
ptmp[n]=ppLayers[n+i];
|
||||||
|
}
|
||||||
|
|
||||||
|
info.nNumLayers--;
|
||||||
|
delete [] ppLayers;
|
||||||
|
ppLayers = ptmp;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
delete ppLayers[0];
|
||||||
|
delete [] ppLayers;
|
||||||
|
ppLayers = 0;
|
||||||
|
info.nNumLayers = 0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::LayerDeleteAll()
|
||||||
|
{
|
||||||
|
if (ppLayers) {
|
||||||
|
for(int32_t n=0; n<info.nNumLayers;n++){ delete ppLayers[n]; }
|
||||||
|
delete [] ppLayers; ppLayers=0; info.nNumLayers = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Returns a pointer to a layer. If position is less than 0, the last layer will be returned
|
||||||
|
*/
|
||||||
|
CxImage* CxImage::GetLayer(int32_t position)
|
||||||
|
{
|
||||||
|
if ( ppLayers == NULL) return NULL;
|
||||||
|
if ( info.nNumLayers == 0) return NULL;
|
||||||
|
if ( position >= info.nNumLayers ) return NULL;
|
||||||
|
if ( position < 0) position = info.nNumLayers - 1;
|
||||||
|
return ppLayers[position];
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_LAYERS
|
||||||
@@ -0,0 +1,430 @@
|
|||||||
|
/*
|
||||||
|
* File: ximamng.cpp
|
||||||
|
* Purpose: Platform Independent MNG Image Class Loader and Writer
|
||||||
|
* Author: 07/Aug/2001 Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximamng.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_MNG
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// callbacks for the mng decoder:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// memory allocation; data must be zeroed
|
||||||
|
static mng_ptr
|
||||||
|
mymngalloc( mng_size_t size )
|
||||||
|
{
|
||||||
|
return (mng_ptr)calloc(1, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// memory deallocation
|
||||||
|
static void mymngfree(mng_ptr p, mng_size_t size)
|
||||||
|
{
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Stream open/close:
|
||||||
|
// since the user is responsible for opening and closing the file,
|
||||||
|
// we leave the default implementation open
|
||||||
|
static mng_bool mymngopenstream(mng_handle mng) { return MNG_TRUE; }
|
||||||
|
static mng_bool mymngopenstreamwrite(mng_handle mng) { return MNG_TRUE; }
|
||||||
|
static mng_bool mymngclosestream(mng_handle mng) { return MNG_TRUE; }
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// feed data to the decoder
|
||||||
|
static mng_bool mymngreadstream(mng_handle mng, mng_ptr buffer, mng_uint32 size, mng_uint32 *bytesread)
|
||||||
|
{
|
||||||
|
mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
|
||||||
|
// read the requested amount of data from the file
|
||||||
|
*bytesread = mymng->file->Read( buffer, sizeof(uint8_t), size);
|
||||||
|
return MNG_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
static mng_bool mymngwritestream (mng_handle mng, mng_ptr pBuf, mng_uint32 iSize, mng_uint32 *iWritten)
|
||||||
|
{
|
||||||
|
mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
|
||||||
|
// write it
|
||||||
|
*iWritten = mymng->file->Write (pBuf, 1, iSize);
|
||||||
|
return MNG_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// the header's been read. set up the display stuff
|
||||||
|
static mng_bool mymngprocessheader( mng_handle mng, mng_uint32 width, mng_uint32 height )
|
||||||
|
{
|
||||||
|
// normally the image buffer is allocated here,
|
||||||
|
// but in this module we don't know nothing about
|
||||||
|
// the final environment.
|
||||||
|
|
||||||
|
mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
|
||||||
|
|
||||||
|
mymng->width = width;
|
||||||
|
mymng->height = height;
|
||||||
|
mymng->bpp = 24;
|
||||||
|
mymng->effwdt = ((((width * mymng->bpp) + 31) >> 5) << 2);
|
||||||
|
|
||||||
|
if (mng->bUseBKGD){
|
||||||
|
mymng->nBkgndIndex = 0;
|
||||||
|
mymng->nBkgndColor.rgbRed = mng->iBGred >> 8;
|
||||||
|
mymng->nBkgndColor.rgbGreen =mng->iBGgreen >> 8;
|
||||||
|
mymng->nBkgndColor.rgbBlue = mng->iBGblue >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
mymng->image = (uint8_t*)malloc(height * mymng->effwdt);
|
||||||
|
|
||||||
|
// tell the mng decoder about our bit-depth choice
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
mng_set_canvasstyle( mng, MNG_CANVAS_RGB8_A8 );
|
||||||
|
mymng->alpha = (uint8_t*)malloc(height * width);
|
||||||
|
#else
|
||||||
|
mng_set_canvasstyle( mng, MNG_CANVAS_BGR8);
|
||||||
|
mymng->alpha = NULL;
|
||||||
|
#endif
|
||||||
|
return MNG_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// return a row pointer for the decoder to fill
|
||||||
|
static mng_ptr mymnggetcanvasline( mng_handle mng, mng_uint32 line )
|
||||||
|
{
|
||||||
|
mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
|
||||||
|
return (mng_ptr)(mymng->image + (mymng->effwdt * (mymng->height - 1 - line)));
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// return a row pointer for the decoder to fill for alpha channel
|
||||||
|
static mng_ptr mymnggetalphaline( mng_handle mng, mng_uint32 line )
|
||||||
|
{
|
||||||
|
mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
|
||||||
|
return (mng_ptr)(mymng->alpha + (mymng->width * (mymng->height - 1 - line)));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// timer
|
||||||
|
static mng_uint32 mymnggetticks(mng_handle mng)
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
return (mng_uint32)GetTickCount();
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Refresh: actual frame need to be updated (Invalidate)
|
||||||
|
static mng_bool mymngrefresh(mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h)
|
||||||
|
{
|
||||||
|
// mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
|
||||||
|
return MNG_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// interframe delay callback
|
||||||
|
static mng_bool mymngsettimer(mng_handle mng, mng_uint32 msecs)
|
||||||
|
{
|
||||||
|
mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
|
||||||
|
mymng->delay = msecs; // set the timer for when the decoder wants to be woken
|
||||||
|
return MNG_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
static mng_bool mymngerror(mng_handle mng, mng_int32 code, mng_int8 severity, mng_chunkid chunktype, mng_uint32 chunkseq, mng_int32 extra1, mng_int32 extra2, mng_pchar text)
|
||||||
|
{
|
||||||
|
return mng_cleanup(&mng); //<Arkadiy Olovyannikov>
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CxImage members
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CxImageMNG::CxImageMNG(): CxImage(CXIMAGE_FORMAT_MNG)
|
||||||
|
{
|
||||||
|
hmng = NULL;
|
||||||
|
memset(&mnginfo,0,sizeof(mngstuff));
|
||||||
|
mnginfo.nBkgndIndex = -1;
|
||||||
|
mnginfo.speed = 1.0f;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CxImageMNG::~CxImageMNG()
|
||||||
|
{
|
||||||
|
// cleanup and return
|
||||||
|
if (mnginfo.thread){ //close the animation thread
|
||||||
|
mnginfo.animation_enabled=0;
|
||||||
|
ResumeThread(mnginfo.thread);
|
||||||
|
WaitForSingleObject(mnginfo.thread,500);
|
||||||
|
CloseHandle(mnginfo.thread);
|
||||||
|
}
|
||||||
|
// free objects
|
||||||
|
if (mnginfo.image) free(mnginfo.image);
|
||||||
|
if (mnginfo.alpha) free(mnginfo.alpha);
|
||||||
|
if (hmng) mng_cleanup(&hmng); //be sure it's not needed any more. (active timers ?)
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImageMNG::SetCallbacks(mng_handle mng)
|
||||||
|
{
|
||||||
|
// set the callbacks
|
||||||
|
mng_setcb_errorproc(mng, mymngerror);
|
||||||
|
mng_setcb_openstream(mng, mymngopenstream);
|
||||||
|
mng_setcb_closestream(mng, mymngclosestream);
|
||||||
|
mng_setcb_readdata(mng, mymngreadstream);
|
||||||
|
mng_setcb_processheader(mng, mymngprocessheader);
|
||||||
|
mng_setcb_getcanvasline(mng, mymnggetcanvasline);
|
||||||
|
mng_setcb_refresh(mng, mymngrefresh);
|
||||||
|
mng_setcb_gettickcount(mng, mymnggetticks);
|
||||||
|
mng_setcb_settimer(mng, mymngsettimer);
|
||||||
|
mng_setcb_refresh(mng, mymngrefresh);
|
||||||
|
mng_setcb_getalphaline(mng, mymnggetalphaline);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// can't use the CxImage implementation because it looses mnginfo
|
||||||
|
bool CxImageMNG::Load(const TCHAR * imageFileName){
|
||||||
|
FILE* hFile; //file handle to read the image
|
||||||
|
#ifdef WIN32
|
||||||
|
if ((hFile=_tfopen(imageFileName,_T("rb")))==NULL) return false; // For UNICODE support
|
||||||
|
#else
|
||||||
|
if ((hFile=fopen(imageFileName,"rb"))==NULL) return false;
|
||||||
|
#endif
|
||||||
|
bool bOK = Decode(hFile);
|
||||||
|
fclose(hFile);
|
||||||
|
return bOK;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageMNG::Decode(CxFile *hFile)
|
||||||
|
{
|
||||||
|
if (hFile == NULL) return false;
|
||||||
|
|
||||||
|
cx_try
|
||||||
|
{
|
||||||
|
// set up the mng decoder for our stream
|
||||||
|
hmng = mng_initialize(&mnginfo, (mng_memalloc)mymngalloc, (mng_memfree)mymngfree, MNG_NULL);
|
||||||
|
if (hmng == NULL) cx_throw("could not initialize libmng");
|
||||||
|
|
||||||
|
// set the file we want to play
|
||||||
|
mnginfo.file = hFile;
|
||||||
|
|
||||||
|
// Set the colorprofile, lcms uses this:
|
||||||
|
mng_set_srgb(hmng, MNG_TRUE );
|
||||||
|
// Set white as background color:
|
||||||
|
uint16_t Red,Green,Blue;
|
||||||
|
Red = Green = Blue = (255 << 8) + 255;
|
||||||
|
mng_set_bgcolor(hmng, Red, Green, Blue );
|
||||||
|
// If PNG Background is available, use it:
|
||||||
|
mng_set_usebkgd(hmng, MNG_TRUE );
|
||||||
|
|
||||||
|
// No need to store chunks:
|
||||||
|
mng_set_storechunks(hmng, MNG_FALSE);
|
||||||
|
// No need to wait: straight reading
|
||||||
|
mng_set_suspensionmode(hmng, MNG_FALSE);
|
||||||
|
|
||||||
|
SetCallbacks(hmng);
|
||||||
|
|
||||||
|
mng_datap pData = (mng_datap)hmng;
|
||||||
|
|
||||||
|
// read in the image
|
||||||
|
info.nNumFrames=0;
|
||||||
|
int32_t retval=MNG_NOERROR;
|
||||||
|
|
||||||
|
retval = mng_readdisplay(hmng);
|
||||||
|
|
||||||
|
if (retval != MNG_NOERROR && retval != MNG_NEEDTIMERWAIT){
|
||||||
|
mng_store_error(hmng,retval,0,0);
|
||||||
|
if (hmng->zErrortext){
|
||||||
|
cx_throw(hmng->zErrortext);
|
||||||
|
} else {
|
||||||
|
cx_throw("Error in MNG file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.nEscape == -1) {
|
||||||
|
// Return output dimensions only
|
||||||
|
head.biWidth = hmng->iWidth;
|
||||||
|
head.biHeight = hmng->iHeight;
|
||||||
|
info.dwType = CXIMAGE_FORMAT_MNG;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read all
|
||||||
|
while(pData->bReading){
|
||||||
|
retval = mng_display_resume(hmng);
|
||||||
|
info.nNumFrames++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// single frame check:
|
||||||
|
if (retval != MNG_NEEDTIMERWAIT){
|
||||||
|
info.nNumFrames--;
|
||||||
|
} else {
|
||||||
|
mnginfo.animation=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.nNumFrames<=0) info.nNumFrames=1;
|
||||||
|
|
||||||
|
if (mnginfo.animation_enabled==0){
|
||||||
|
// select the frame
|
||||||
|
if (info.nFrame>=0 && info.nFrame<info.nNumFrames){
|
||||||
|
for (int32_t n=0;n<info.nFrame;n++) mng_display_resume(hmng);
|
||||||
|
} else cx_throw("Error: frame not present in MNG file");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mnginfo.nBkgndIndex >= 0){
|
||||||
|
info.nBkgndIndex = mnginfo.nBkgndIndex;
|
||||||
|
info.nBkgndColor.rgbRed = mnginfo.nBkgndColor.rgbRed;
|
||||||
|
info.nBkgndColor.rgbGreen = mnginfo.nBkgndColor.rgbGreen;
|
||||||
|
info.nBkgndColor.rgbBlue = mnginfo.nBkgndColor.rgbBlue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//store the newly created image
|
||||||
|
if (Create(mnginfo.width,mnginfo.height,mnginfo.bpp, CXIMAGE_FORMAT_MNG)){
|
||||||
|
memcpy(GetBits(), mnginfo.image, info.dwEffWidth * head.biHeight);
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
SwapRGB2BGR();
|
||||||
|
AlphaCreate();
|
||||||
|
if(AlphaIsValid() && mnginfo.alpha){
|
||||||
|
memcpy(AlphaGetPointer(),mnginfo.alpha,mnginfo.width * mnginfo.height);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else cx_throw("CxImageMNG::Decode cannot create image");
|
||||||
|
|
||||||
|
|
||||||
|
} cx_catch {
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageMNG::Encode(CxFile *hFile)
|
||||||
|
{
|
||||||
|
if (EncodeSafeCheck(hFile)) return false;
|
||||||
|
|
||||||
|
cx_try
|
||||||
|
{
|
||||||
|
if (head.biClrUsed != 0) cx_throw("MNG encoder can save only RGB images");
|
||||||
|
// set the file we want to play
|
||||||
|
mnginfo.file = hFile;
|
||||||
|
mnginfo.bpp = head.biBitCount;
|
||||||
|
mnginfo.effwdt = info.dwEffWidth;
|
||||||
|
mnginfo.height = head.biHeight;
|
||||||
|
mnginfo.width = head.biWidth;
|
||||||
|
|
||||||
|
mnginfo.image = (uint8_t*)malloc(head.biSizeImage);
|
||||||
|
if (mnginfo.image == NULL) cx_throw("could not allocate memory for MNG");
|
||||||
|
memcpy(mnginfo.image,info.pImage, head.biSizeImage);
|
||||||
|
|
||||||
|
// set up the mng decoder for our stream
|
||||||
|
hmng = mng_initialize(&mnginfo, (mng_memalloc)mymngalloc, (mng_memfree)mymngfree, MNG_NULL);
|
||||||
|
if (hmng == NULL) cx_throw("could not initialize libmng");
|
||||||
|
|
||||||
|
mng_setcb_openstream(hmng, mymngopenstreamwrite );
|
||||||
|
mng_setcb_closestream(hmng, mymngclosestream);
|
||||||
|
mng_setcb_writedata(hmng, mymngwritestream);
|
||||||
|
|
||||||
|
// Write File:
|
||||||
|
mng_create(hmng);
|
||||||
|
// Just a single Frame (save a normal PNG):
|
||||||
|
WritePNG(hmng, 0, 1 );
|
||||||
|
// Now write file:
|
||||||
|
mng_write(hmng);
|
||||||
|
|
||||||
|
} cx_catch {
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Writes a single PNG datastream
|
||||||
|
void CxImageMNG::WritePNG( mng_handle hMNG, int32_t Frame, int32_t FrameCount )
|
||||||
|
{
|
||||||
|
mngstuff *mymng = (mngstuff *)mng_get_userdata(hMNG);
|
||||||
|
|
||||||
|
int32_t OffsetX=0,OffsetY=0,OffsetW=mymng->width,OffsetH=mymng->height;
|
||||||
|
|
||||||
|
uint8_t *tmpbuffer = new uint8_t[ (mymng->effwdt+1) * mymng->height];
|
||||||
|
if( tmpbuffer == 0 ) return;
|
||||||
|
|
||||||
|
// Write DEFI chunk.
|
||||||
|
mng_putchunk_defi( hMNG, 0, 0, 0, MNG_TRUE, OffsetX, OffsetY, MNG_FALSE, 0, 0, 0, 0 );
|
||||||
|
|
||||||
|
// Write Header:
|
||||||
|
mng_putchunk_ihdr(
|
||||||
|
hMNG,
|
||||||
|
OffsetW, OffsetH,
|
||||||
|
MNG_BITDEPTH_8,
|
||||||
|
MNG_COLORTYPE_RGB,
|
||||||
|
MNG_COMPRESSION_DEFLATE,
|
||||||
|
MNG_FILTER_ADAPTIVE,
|
||||||
|
MNG_INTERLACE_NONE
|
||||||
|
);
|
||||||
|
|
||||||
|
// transfer data, add Filterbyte:
|
||||||
|
for( int32_t Row=0; Row<OffsetH; Row++ ){
|
||||||
|
// First Byte in each Scanline is Filterbyte: Currently 0 -> No Filter.
|
||||||
|
tmpbuffer[Row*(mymng->effwdt+1)]=0;
|
||||||
|
// Copy the scanline: (reverse order)
|
||||||
|
memcpy(tmpbuffer+Row*(mymng->effwdt+1)+1,
|
||||||
|
mymng->image+((OffsetH-1-(OffsetY+Row))*(mymng->effwdt))+OffsetX,mymng->effwdt);
|
||||||
|
// swap red and blue components
|
||||||
|
RGBtoBGR(tmpbuffer+Row*(mymng->effwdt+1)+1,mymng->effwdt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compress data with ZLib (Deflate):
|
||||||
|
uint8_t *dstbuffer = new uint8_t[(mymng->effwdt+1)*OffsetH];
|
||||||
|
if( dstbuffer == 0 ) return;
|
||||||
|
uint32_t dstbufferSize=(mymng->effwdt+1)*OffsetH;
|
||||||
|
|
||||||
|
// Compress data:
|
||||||
|
if(Z_OK != compress2((Bytef *)dstbuffer,(ULONG *)&dstbufferSize,(const Bytef*)tmpbuffer,
|
||||||
|
(ULONG) (mymng->effwdt+1)*OffsetH,9 )) return;
|
||||||
|
|
||||||
|
// Write Data into MNG File:
|
||||||
|
mng_putchunk_idat( hMNG, dstbufferSize, (mng_ptr*)dstbuffer);
|
||||||
|
mng_putchunk_iend(hMNG);
|
||||||
|
|
||||||
|
// Free the stuff:
|
||||||
|
delete [] tmpbuffer;
|
||||||
|
delete [] dstbuffer;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int32_t CxImageMNG::Resume()
|
||||||
|
{
|
||||||
|
if (MNG_NEEDTIMERWAIT == mng_display_resume(hmng)){
|
||||||
|
if (info.pImage==NULL){
|
||||||
|
Create(mnginfo.width,mnginfo.height,mnginfo.bpp, CXIMAGE_FORMAT_MNG);
|
||||||
|
}
|
||||||
|
if (IsValid()){
|
||||||
|
memcpy(GetBits(), mnginfo.image, info.dwEffWidth * head.biHeight);
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
SwapRGB2BGR();
|
||||||
|
AlphaCreate();
|
||||||
|
if(AlphaIsValid() && mnginfo.alpha){
|
||||||
|
memcpy(AlphaGetPointer(),mnginfo.alpha,mnginfo.width * mnginfo.height);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mnginfo.animation_enabled = 0;
|
||||||
|
}
|
||||||
|
return mnginfo.animation_enabled;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImageMNG::SetSpeed(float speed)
|
||||||
|
{
|
||||||
|
if (speed>10.0) mnginfo.speed = 10.0f;
|
||||||
|
else if (speed<0.1) mnginfo.speed = 0.1f;
|
||||||
|
else mnginfo.speed=speed;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_MNG
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* File: ximamng.h
|
||||||
|
* Purpose: Declaration of the MNG Image Class
|
||||||
|
* Author: Davide Pizzolato - www.xdp.it
|
||||||
|
* Created: 2001
|
||||||
|
*/
|
||||||
|
/* ==========================================================
|
||||||
|
* CxImageMNG (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it
|
||||||
|
* For conditions of distribution and use, see copyright notice in ximage.h
|
||||||
|
*
|
||||||
|
* Special thanks to Frank Haug <f.haug(at)jdm(dot)de> for suggestions and code.
|
||||||
|
*
|
||||||
|
* original mng.cpp code created by Nikolaus Brennig, November 14th, 2000. <virtualnik(at)nol(dot)at>
|
||||||
|
*
|
||||||
|
* LIBMNG Copyright (c) 2000,2001 Gerard Juyn (gerard@libmng.com)
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(__ximaMNG_h)
|
||||||
|
#define __ximaMNG_h
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_MNG
|
||||||
|
|
||||||
|
//#define MNG_NO_CMS
|
||||||
|
#define MNG_SUPPORT_DISPLAY
|
||||||
|
#define MNG_SUPPORT_READ
|
||||||
|
#define MNG_SUPPORT_WRITE
|
||||||
|
#define MNG_ACCESS_CHUNKS
|
||||||
|
#define MNG_STORE_CHUNKS
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "../mng/libmng.h"
|
||||||
|
#include "../mng/libmng_data.h"
|
||||||
|
#include "../mng/libmng_error.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
//uint32_t _stdcall RunMNGThread(void *lpParam);
|
||||||
|
|
||||||
|
typedef struct tagmngstuff
|
||||||
|
{
|
||||||
|
CxFile *file;
|
||||||
|
uint8_t *image;
|
||||||
|
uint8_t *alpha;
|
||||||
|
HANDLE thread;
|
||||||
|
mng_uint32 delay;
|
||||||
|
mng_uint32 width;
|
||||||
|
mng_uint32 height;
|
||||||
|
mng_uint32 effwdt;
|
||||||
|
mng_int16 bpp;
|
||||||
|
mng_bool animation;
|
||||||
|
mng_bool animation_enabled;
|
||||||
|
float speed;
|
||||||
|
int32_t nBkgndIndex;
|
||||||
|
RGBQUAD nBkgndColor;
|
||||||
|
} mngstuff;
|
||||||
|
|
||||||
|
class CxImageMNG: public CxImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CxImageMNG();
|
||||||
|
~CxImageMNG();
|
||||||
|
|
||||||
|
bool Load(const TCHAR * imageFileName);
|
||||||
|
|
||||||
|
bool Decode(CxFile * hFile);
|
||||||
|
bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
bool Encode(CxFile * hFile);
|
||||||
|
bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }
|
||||||
|
bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_MNG);}
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
|
||||||
|
int32_t Resume();
|
||||||
|
void SetSpeed(float speed);
|
||||||
|
|
||||||
|
mng_handle hmng;
|
||||||
|
mngstuff mnginfo;
|
||||||
|
protected:
|
||||||
|
void WritePNG(mng_handle hMNG, int32_t Frame, int32_t FrameCount );
|
||||||
|
void SetCallbacks(mng_handle mng);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,834 @@
|
|||||||
|
// xImaPal.cpp : Palette and Pixel functions
|
||||||
|
/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* returns the palette dimension in byte
|
||||||
|
*/
|
||||||
|
uint32_t CxImage::GetPaletteSize()
|
||||||
|
{
|
||||||
|
return (head.biClrUsed * sizeof(RGBQUAD));
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::SetPaletteColor(uint8_t idx, uint8_t r, uint8_t g, uint8_t b, uint8_t alpha)
|
||||||
|
{
|
||||||
|
if ((pDib)&&(head.biClrUsed)){
|
||||||
|
uint8_t* iDst = (uint8_t*)(pDib) + sizeof(BITMAPINFOHEADER);
|
||||||
|
if (idx<head.biClrUsed){
|
||||||
|
int32_t ldx=idx*sizeof(RGBQUAD);
|
||||||
|
iDst[ldx++] = (uint8_t) b;
|
||||||
|
iDst[ldx++] = (uint8_t) g;
|
||||||
|
iDst[ldx++] = (uint8_t) r;
|
||||||
|
iDst[ldx] = (uint8_t) alpha;
|
||||||
|
info.last_c_isvalid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::SetPaletteColor(uint8_t idx, RGBQUAD c)
|
||||||
|
{
|
||||||
|
if ((pDib)&&(head.biClrUsed)){
|
||||||
|
uint8_t* iDst = (uint8_t*)(pDib) + sizeof(BITMAPINFOHEADER);
|
||||||
|
if (idx<head.biClrUsed){
|
||||||
|
int32_t ldx=idx*sizeof(RGBQUAD);
|
||||||
|
iDst[ldx++] = (uint8_t) c.rgbBlue;
|
||||||
|
iDst[ldx++] = (uint8_t) c.rgbGreen;
|
||||||
|
iDst[ldx++] = (uint8_t) c.rgbRed;
|
||||||
|
iDst[ldx] = (uint8_t) c.rgbReserved;
|
||||||
|
info.last_c_isvalid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::SetPaletteColor(uint8_t idx, COLORREF cr)
|
||||||
|
{
|
||||||
|
if ((pDib)&&(head.biClrUsed)){
|
||||||
|
uint8_t* iDst = (uint8_t*)(pDib) + sizeof(BITMAPINFOHEADER);
|
||||||
|
if (idx<head.biClrUsed){
|
||||||
|
int32_t ldx=idx*sizeof(RGBQUAD);
|
||||||
|
iDst[ldx++] = (uint8_t) GetBValue(cr);
|
||||||
|
iDst[ldx++] = (uint8_t) GetGValue(cr);
|
||||||
|
iDst[ldx++] = (uint8_t) GetRValue(cr);
|
||||||
|
iDst[ldx] = (uint8_t) 0;
|
||||||
|
info.last_c_isvalid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* returns the pointer to the first palette index
|
||||||
|
*/
|
||||||
|
RGBQUAD* CxImage::GetPalette() const
|
||||||
|
{
|
||||||
|
if ((pDib)&&(head.biClrUsed))
|
||||||
|
return (RGBQUAD*)((uint8_t*)pDib + sizeof(BITMAPINFOHEADER));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Returns the color of the specified index.
|
||||||
|
*/
|
||||||
|
RGBQUAD CxImage::GetPaletteColor(uint8_t idx)
|
||||||
|
{
|
||||||
|
RGBQUAD rgb = {0,0,0,0};
|
||||||
|
if ((pDib)&&(head.biClrUsed)){
|
||||||
|
uint8_t* iDst = (uint8_t*)(pDib) + sizeof(BITMAPINFOHEADER);
|
||||||
|
if (idx<head.biClrUsed){
|
||||||
|
int32_t ldx=idx*sizeof(RGBQUAD);
|
||||||
|
rgb.rgbBlue = iDst[ldx++];
|
||||||
|
rgb.rgbGreen=iDst[ldx++];
|
||||||
|
rgb.rgbRed =iDst[ldx++];
|
||||||
|
rgb.rgbReserved = iDst[ldx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Returns the palette index of the specified pixel.
|
||||||
|
*/
|
||||||
|
uint8_t CxImage::GetPixelIndex(int32_t x,int32_t y)
|
||||||
|
{
|
||||||
|
if ((pDib==NULL)||(head.biClrUsed==0)) return 0;
|
||||||
|
|
||||||
|
if ((x<0)||(y<0)||(x>=head.biWidth)||(y>=head.biHeight)) {
|
||||||
|
if (info.nBkgndIndex >= 0) return (uint8_t)info.nBkgndIndex;
|
||||||
|
else return *info.pImage;
|
||||||
|
}
|
||||||
|
if (head.biBitCount==8){
|
||||||
|
return info.pImage[y*info.dwEffWidth + x];
|
||||||
|
} else {
|
||||||
|
uint8_t pos;
|
||||||
|
uint8_t iDst= info.pImage[y*info.dwEffWidth + (x*head.biBitCount >> 3)];
|
||||||
|
if (head.biBitCount==4){
|
||||||
|
pos = (uint8_t)(4*(1-x%2));
|
||||||
|
iDst &= (0x0F<<pos);
|
||||||
|
return (uint8_t)(iDst >> pos);
|
||||||
|
} else if (head.biBitCount==1){
|
||||||
|
pos = (uint8_t)(7-x%8);
|
||||||
|
iDst &= (0x01<<pos);
|
||||||
|
return (uint8_t)(iDst >> pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
uint8_t CxImage::BlindGetPixelIndex(const int32_t x,const int32_t y)
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
if ((pDib==NULL) || (head.biClrUsed==0) || !IsInside(x,y))
|
||||||
|
#if CXIMAGE_SUPPORT_EXCEPTION_HANDLING
|
||||||
|
throw 0;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (head.biBitCount==8){
|
||||||
|
return info.pImage[y*info.dwEffWidth + x];
|
||||||
|
} else {
|
||||||
|
uint8_t pos;
|
||||||
|
uint8_t iDst= info.pImage[y*info.dwEffWidth + (x*head.biBitCount >> 3)];
|
||||||
|
if (head.biBitCount==4){
|
||||||
|
pos = (uint8_t)(4*(1-x%2));
|
||||||
|
iDst &= (0x0F<<pos);
|
||||||
|
return (uint8_t)(iDst >> pos);
|
||||||
|
} else if (head.biBitCount==1){
|
||||||
|
pos = (uint8_t)(7-x%8);
|
||||||
|
iDst &= (0x01<<pos);
|
||||||
|
return (uint8_t)(iDst >> pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
RGBQUAD CxImage::GetPixelColor(int32_t x,int32_t y, bool bGetAlpha)
|
||||||
|
{
|
||||||
|
// RGBQUAD rgb={0,0,0,0};
|
||||||
|
RGBQUAD rgb=info.nBkgndColor; //<mpwolski>
|
||||||
|
if ((pDib==NULL)||(x<0)||(y<0)||
|
||||||
|
(x>=head.biWidth)||(y>=head.biHeight)){
|
||||||
|
if (info.nBkgndIndex >= 0){
|
||||||
|
if (head.biBitCount<24) return GetPaletteColor((uint8_t)info.nBkgndIndex);
|
||||||
|
else return info.nBkgndColor;
|
||||||
|
} else if (pDib) return GetPixelColor(0,0);
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (head.biClrUsed){
|
||||||
|
rgb = GetPaletteColor(BlindGetPixelIndex(x,y));
|
||||||
|
} else {
|
||||||
|
uint8_t* iDst = info.pImage + y*info.dwEffWidth + x*3;
|
||||||
|
rgb.rgbBlue = *iDst++;
|
||||||
|
rgb.rgbGreen= *iDst++;
|
||||||
|
rgb.rgbRed = *iDst;
|
||||||
|
}
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (pAlpha && bGetAlpha) rgb.rgbReserved = BlindAlphaGet(x,y);
|
||||||
|
#else
|
||||||
|
rgb.rgbReserved = 0;
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* This is (a bit) faster version of GetPixelColor.
|
||||||
|
* It tests bounds only in debug mode (_DEBUG defined).
|
||||||
|
*
|
||||||
|
* It is an error to request out-of-borders pixel with this method.
|
||||||
|
* In DEBUG mode an exception will be thrown, and data will be violated in non-DEBUG mode.
|
||||||
|
* \author ***bd*** 2.2004
|
||||||
|
*/
|
||||||
|
RGBQUAD CxImage::BlindGetPixelColor(const int32_t x,const int32_t y, bool bGetAlpha)
|
||||||
|
{
|
||||||
|
RGBQUAD rgb;
|
||||||
|
#ifdef _DEBUG
|
||||||
|
if ((pDib==NULL) || !IsInside(x,y))
|
||||||
|
#if CXIMAGE_SUPPORT_EXCEPTION_HANDLING
|
||||||
|
throw 0;
|
||||||
|
#else
|
||||||
|
{rgb.rgbReserved = 0; return rgb;}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (head.biClrUsed){
|
||||||
|
rgb = GetPaletteColor(BlindGetPixelIndex(x,y));
|
||||||
|
} else {
|
||||||
|
uint8_t* iDst = info.pImage + y*info.dwEffWidth + x*3;
|
||||||
|
rgb.rgbBlue = *iDst++;
|
||||||
|
rgb.rgbGreen= *iDst++;
|
||||||
|
rgb.rgbRed = *iDst;
|
||||||
|
rgb.rgbReserved = 0; //needed for images without alpha layer
|
||||||
|
}
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (pAlpha && bGetAlpha) rgb.rgbReserved = BlindAlphaGet(x,y);
|
||||||
|
#else
|
||||||
|
rgb.rgbReserved = 0;
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
uint8_t CxImage::GetPixelGray(int32_t x, int32_t y)
|
||||||
|
{
|
||||||
|
RGBQUAD color = GetPixelColor(x,y);
|
||||||
|
return (uint8_t)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::BlindSetPixelIndex(int32_t x,int32_t y,uint8_t i)
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
if ((pDib==NULL)||(head.biClrUsed==0)||
|
||||||
|
(x<0)||(y<0)||(x>=head.biWidth)||(y>=head.biHeight))
|
||||||
|
#if CXIMAGE_SUPPORT_EXCEPTION_HANDLING
|
||||||
|
throw 0;
|
||||||
|
#else
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (head.biBitCount==8){
|
||||||
|
info.pImage[y*info.dwEffWidth + x]=i;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
uint8_t pos;
|
||||||
|
uint8_t* iDst= info.pImage + y*info.dwEffWidth + (x*head.biBitCount >> 3);
|
||||||
|
if (head.biBitCount==4){
|
||||||
|
pos = (uint8_t)(4*(1-x%2));
|
||||||
|
*iDst &= ~(0x0F<<pos);
|
||||||
|
*iDst |= ((i & 0x0F)<<pos);
|
||||||
|
return;
|
||||||
|
} else if (head.biBitCount==1){
|
||||||
|
pos = (uint8_t)(7-x%8);
|
||||||
|
*iDst &= ~(0x01<<pos);
|
||||||
|
*iDst |= ((i & 0x01)<<pos);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::SetPixelIndex(int32_t x,int32_t y,uint8_t i)
|
||||||
|
{
|
||||||
|
if ((pDib==NULL)||(head.biClrUsed==0)||
|
||||||
|
(x<0)||(y<0)||(x>=head.biWidth)||(y>=head.biHeight)) return ;
|
||||||
|
|
||||||
|
if (head.biBitCount==8){
|
||||||
|
info.pImage[y*info.dwEffWidth + x]=i;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
uint8_t pos;
|
||||||
|
uint8_t* iDst= info.pImage + y*info.dwEffWidth + (x*head.biBitCount >> 3);
|
||||||
|
if (head.biBitCount==4){
|
||||||
|
pos = (uint8_t)(4*(1-x%2));
|
||||||
|
*iDst &= ~(0x0F<<pos);
|
||||||
|
*iDst |= ((i & 0x0F)<<pos);
|
||||||
|
return;
|
||||||
|
} else if (head.biBitCount==1){
|
||||||
|
pos = (uint8_t)(7-x%8);
|
||||||
|
*iDst &= ~(0x01<<pos);
|
||||||
|
*iDst |= ((i & 0x01)<<pos);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::SetPixelColor(int32_t x,int32_t y,COLORREF cr)
|
||||||
|
{
|
||||||
|
SetPixelColor(x,y,RGBtoRGBQUAD(cr));
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::BlindSetPixelColor(int32_t x,int32_t y,RGBQUAD c, bool bSetAlpha)
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
if ((pDib==NULL)||(x<0)||(y<0)||
|
||||||
|
(x>=head.biWidth)||(y>=head.biHeight))
|
||||||
|
#if CXIMAGE_SUPPORT_EXCEPTION_HANDLING
|
||||||
|
throw 0;
|
||||||
|
#else
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
if (head.biClrUsed)
|
||||||
|
BlindSetPixelIndex(x,y,GetNearestIndex(c));
|
||||||
|
else {
|
||||||
|
uint8_t* iDst = info.pImage + y*info.dwEffWidth + x*3;
|
||||||
|
*iDst++ = c.rgbBlue;
|
||||||
|
*iDst++ = c.rgbGreen;
|
||||||
|
*iDst = c.rgbRed;
|
||||||
|
}
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (bSetAlpha) AlphaSet(x,y,c.rgbReserved);
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::SetPixelColor(int32_t x,int32_t y,RGBQUAD c, bool bSetAlpha)
|
||||||
|
{
|
||||||
|
if ((pDib==NULL)||(x<0)||(y<0)||
|
||||||
|
(x>=head.biWidth)||(y>=head.biHeight)) return;
|
||||||
|
if (head.biClrUsed)
|
||||||
|
BlindSetPixelIndex(x,y,GetNearestIndex(c));
|
||||||
|
else {
|
||||||
|
uint8_t* iDst = info.pImage + y*info.dwEffWidth + x*3;
|
||||||
|
*iDst++ = c.rgbBlue;
|
||||||
|
*iDst++ = c.rgbGreen;
|
||||||
|
*iDst = c.rgbRed;
|
||||||
|
}
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (bSetAlpha) AlphaSet(x,y,c.rgbReserved);
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Blends the current pixel color with a new color.
|
||||||
|
* \param x,y = pixel
|
||||||
|
* \param c = new color
|
||||||
|
* \param blend = can be from 0 (no effect) to 1 (full effect).
|
||||||
|
* \param bSetAlpha = if true, blends also the alpha component stored in c.rgbReserved
|
||||||
|
*/
|
||||||
|
void CxImage::BlendPixelColor(int32_t x,int32_t y,RGBQUAD c, float blend, bool bSetAlpha)
|
||||||
|
{
|
||||||
|
if ((pDib==NULL)||(x<0)||(y<0)||
|
||||||
|
(x>=head.biWidth)||(y>=head.biHeight)) return;
|
||||||
|
|
||||||
|
int32_t a0 = (int32_t)(256*blend);
|
||||||
|
int32_t a1 = 256 - a0;
|
||||||
|
|
||||||
|
RGBQUAD c0 = BlindGetPixelColor(x,y);
|
||||||
|
c.rgbRed = (uint8_t)((c.rgbRed * a0 + c0.rgbRed * a1)>>8);
|
||||||
|
c.rgbBlue = (uint8_t)((c.rgbBlue * a0 + c0.rgbBlue * a1)>>8);
|
||||||
|
c.rgbGreen = (uint8_t)((c.rgbGreen * a0 + c0.rgbGreen * a1)>>8);
|
||||||
|
|
||||||
|
if (head.biClrUsed)
|
||||||
|
BlindSetPixelIndex(x,y,GetNearestIndex(c));
|
||||||
|
else {
|
||||||
|
uint8_t* iDst = info.pImage + y*info.dwEffWidth + x*3;
|
||||||
|
*iDst++ = c.rgbBlue;
|
||||||
|
*iDst++ = c.rgbGreen;
|
||||||
|
*iDst = c.rgbRed;
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (bSetAlpha) AlphaSet(x,y,c.rgbReserved);
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Returns the best palette index that matches a specified color.
|
||||||
|
*/
|
||||||
|
uint8_t CxImage::GetNearestIndex(RGBQUAD c)
|
||||||
|
{
|
||||||
|
if ((pDib==NULL)||(head.biClrUsed==0)) return 0;
|
||||||
|
|
||||||
|
// <RJ> check matching with the previous result
|
||||||
|
if (info.last_c_isvalid && (*(int32_t*)&info.last_c == *(int32_t*)&c)) return info.last_c_index;
|
||||||
|
info.last_c = c;
|
||||||
|
info.last_c_isvalid = true;
|
||||||
|
|
||||||
|
uint8_t* iDst = (uint8_t*)(pDib) + sizeof(BITMAPINFOHEADER);
|
||||||
|
int32_t distance=200000;
|
||||||
|
int32_t i,j = 0;
|
||||||
|
int32_t k,l;
|
||||||
|
int32_t m = (int32_t)(head.biClrImportant==0 ? head.biClrUsed : head.biClrImportant);
|
||||||
|
for(i=0,l=0;i<m;i++,l+=sizeof(RGBQUAD)){
|
||||||
|
k = (iDst[l]-c.rgbBlue)*(iDst[l]-c.rgbBlue)+
|
||||||
|
(iDst[l+1]-c.rgbGreen)*(iDst[l+1]-c.rgbGreen)+
|
||||||
|
(iDst[l+2]-c.rgbRed)*(iDst[l+2]-c.rgbRed);
|
||||||
|
// k = abs(iDst[l]-c.rgbBlue)+abs(iDst[l+1]-c.rgbGreen)+abs(iDst[l+2]-c.rgbRed);
|
||||||
|
if (k==0){
|
||||||
|
j=i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (k<distance){
|
||||||
|
distance=k;
|
||||||
|
j=i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info.last_c_index = (uint8_t)j;
|
||||||
|
return (uint8_t)j;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* swaps the blue and red components (for RGB images)
|
||||||
|
* \param buffer : pointer to the pixels
|
||||||
|
* \param length : number of bytes to swap. lenght may not exceed the scan line.
|
||||||
|
*/
|
||||||
|
void CxImage::RGBtoBGR(uint8_t *buffer, int32_t length)
|
||||||
|
{
|
||||||
|
if (buffer && (head.biClrUsed==0)){
|
||||||
|
uint8_t temp;
|
||||||
|
length = min(length,(int32_t)info.dwEffWidth);
|
||||||
|
length = min(length,(int32_t)(3*head.biWidth));
|
||||||
|
for (int32_t i=0;i<length;i+=3){
|
||||||
|
temp = buffer[i]; buffer[i] = buffer[i+2]; buffer[i+2] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
RGBQUAD CxImage::RGBtoRGBQUAD(COLORREF cr)
|
||||||
|
{
|
||||||
|
RGBQUAD c;
|
||||||
|
c.rgbRed = GetRValue(cr); /* get R, G, and B out of uint32_t */
|
||||||
|
c.rgbGreen = GetGValue(cr);
|
||||||
|
c.rgbBlue = GetBValue(cr);
|
||||||
|
c.rgbReserved=0;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
COLORREF CxImage::RGBQUADtoRGB (RGBQUAD c)
|
||||||
|
{
|
||||||
|
return RGB(c.rgbRed,c.rgbGreen,c.rgbBlue);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Returns the color of the specified index.
|
||||||
|
* \param i = palette index
|
||||||
|
* \param r, g, b = output color channels
|
||||||
|
*/
|
||||||
|
bool CxImage::GetPaletteColor(uint8_t i, uint8_t* r, uint8_t* g, uint8_t* b)
|
||||||
|
{
|
||||||
|
RGBQUAD* ppal=GetPalette();
|
||||||
|
if (ppal) {
|
||||||
|
*r = ppal[i].rgbRed;
|
||||||
|
*g = ppal[i].rgbGreen;
|
||||||
|
*b = ppal[i].rgbBlue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::SetPalette(uint32_t n, uint8_t *r, uint8_t *g, uint8_t *b)
|
||||||
|
{
|
||||||
|
if ((!r)||(pDib==NULL)||(head.biClrUsed==0)) return;
|
||||||
|
if (!g) g = r;
|
||||||
|
if (!b) b = g;
|
||||||
|
RGBQUAD* ppal=GetPalette();
|
||||||
|
uint32_t m=min(n,head.biClrUsed);
|
||||||
|
for (uint32_t i=0; i<m;i++){
|
||||||
|
ppal[i].rgbRed=r[i];
|
||||||
|
ppal[i].rgbGreen=g[i];
|
||||||
|
ppal[i].rgbBlue=b[i];
|
||||||
|
}
|
||||||
|
info.last_c_isvalid = false;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::SetPalette(rgb_color *rgb,uint32_t nColors)
|
||||||
|
{
|
||||||
|
if ((!rgb)||(pDib==NULL)||(head.biClrUsed==0)) return;
|
||||||
|
RGBQUAD* ppal=GetPalette();
|
||||||
|
uint32_t m=min(nColors,head.biClrUsed);
|
||||||
|
for (uint32_t i=0; i<m;i++){
|
||||||
|
ppal[i].rgbRed=rgb[i].r;
|
||||||
|
ppal[i].rgbGreen=rgb[i].g;
|
||||||
|
ppal[i].rgbBlue=rgb[i].b;
|
||||||
|
}
|
||||||
|
info.last_c_isvalid = false;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::SetPalette(RGBQUAD* pPal,uint32_t nColors)
|
||||||
|
{
|
||||||
|
if ((pPal==NULL)||(pDib==NULL)||(head.biClrUsed==0)) return;
|
||||||
|
memcpy(GetPalette(),pPal,min(GetPaletteSize(),nColors*sizeof(RGBQUAD)));
|
||||||
|
info.last_c_isvalid = false;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Sets (or replaces) the palette to gray scale palette.
|
||||||
|
* The function doesn't change the pixels; for standard
|
||||||
|
* gray scale conversion use GrayScale().
|
||||||
|
*/
|
||||||
|
void CxImage::SetGrayPalette()
|
||||||
|
{
|
||||||
|
if ((pDib==NULL)||(head.biClrUsed==0)) return;
|
||||||
|
RGBQUAD* pal=GetPalette();
|
||||||
|
for (uint32_t ni=0;ni<head.biClrUsed;ni++)
|
||||||
|
pal[ni].rgbBlue=pal[ni].rgbGreen = pal[ni].rgbRed = (uint8_t)(ni*(255/(head.biClrUsed-1)));
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Colorize the palette.
|
||||||
|
* \sa Colorize
|
||||||
|
*/
|
||||||
|
void CxImage::BlendPalette(COLORREF cr,int32_t perc)
|
||||||
|
{
|
||||||
|
if ((pDib==NULL)||(head.biClrUsed==0)) return;
|
||||||
|
uint8_t* iDst = (uint8_t*)(pDib) + sizeof(BITMAPINFOHEADER);
|
||||||
|
uint32_t i,r,g,b;
|
||||||
|
RGBQUAD* pPal=(RGBQUAD*)iDst;
|
||||||
|
r = GetRValue(cr);
|
||||||
|
g = GetGValue(cr);
|
||||||
|
b = GetBValue(cr);
|
||||||
|
if (perc>100) perc=100;
|
||||||
|
for(i=0;i<head.biClrUsed;i++){
|
||||||
|
pPal[i].rgbBlue=(uint8_t)((pPal[i].rgbBlue*(100-perc)+b*perc)/100);
|
||||||
|
pPal[i].rgbGreen =(uint8_t)((pPal[i].rgbGreen*(100-perc)+g*perc)/100);
|
||||||
|
pPal[i].rgbRed =(uint8_t)((pPal[i].rgbRed*(100-perc)+r*perc)/100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Returns true if the image has 256 colors and a linear grey scale palette.
|
||||||
|
*/
|
||||||
|
bool CxImage::IsGrayScale()
|
||||||
|
{
|
||||||
|
RGBQUAD* ppal=GetPalette();
|
||||||
|
if(!(pDib && ppal && head.biClrUsed)) return false;
|
||||||
|
for(uint32_t i=0;i<head.biClrUsed;i++){
|
||||||
|
if (ppal[i].rgbBlue!=i || ppal[i].rgbGreen!=i || ppal[i].rgbRed!=i) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* swap two indexes in the image and their colors in the palette
|
||||||
|
*/
|
||||||
|
void CxImage::SwapIndex(uint8_t idx1, uint8_t idx2)
|
||||||
|
{
|
||||||
|
RGBQUAD* ppal=GetPalette();
|
||||||
|
if(!(pDib && ppal)) return;
|
||||||
|
//swap the colors
|
||||||
|
RGBQUAD tempRGB=GetPaletteColor(idx1);
|
||||||
|
SetPaletteColor(idx1,GetPaletteColor(idx2));
|
||||||
|
SetPaletteColor(idx2,tempRGB);
|
||||||
|
//swap the pixels
|
||||||
|
uint8_t idx;
|
||||||
|
for(int32_t y=0; y < head.biHeight; y++){
|
||||||
|
for(int32_t x=0; x < head.biWidth; x++){
|
||||||
|
idx=BlindGetPixelIndex(x,y);
|
||||||
|
if (idx==idx1) BlindSetPixelIndex(x,y,idx2);
|
||||||
|
if (idx==idx2) BlindSetPixelIndex(x,y,idx1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* swap Red and Blue colors
|
||||||
|
*/
|
||||||
|
void CxImage::SwapRGB2BGR()
|
||||||
|
{
|
||||||
|
if (!pDib) return;
|
||||||
|
|
||||||
|
if (head.biClrUsed){
|
||||||
|
RGBQUAD* ppal=GetPalette();
|
||||||
|
uint8_t b;
|
||||||
|
if(!ppal) return;
|
||||||
|
for(uint16_t a=0;a<head.biClrUsed;a++){
|
||||||
|
b=ppal[a].rgbBlue; ppal[a].rgbBlue=ppal[a].rgbRed; ppal[a].rgbRed=b;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(int32_t y=0;y<head.biHeight;y++){
|
||||||
|
RGBtoBGR(GetBits(y),3*head.biWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImage::IsTransparent(int32_t x, int32_t y)
|
||||||
|
{
|
||||||
|
if (!pDib) return false;
|
||||||
|
|
||||||
|
if (info.nBkgndIndex>=0){
|
||||||
|
if (head.biClrUsed){
|
||||||
|
if (GetPixelIndex(x,y) == info.nBkgndIndex) return true;
|
||||||
|
} else {
|
||||||
|
RGBQUAD ct = info.nBkgndColor;
|
||||||
|
RGBQUAD c = GetPixelColor(x,y,false);
|
||||||
|
if (*(int32_t*)&c==*(int32_t*)&ct) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (pAlpha) return AlphaGet(x,y)==0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImage::GetTransparentMask(CxImage* iDst)
|
||||||
|
{
|
||||||
|
if (!pDib) return false;
|
||||||
|
|
||||||
|
CxImage tmp;
|
||||||
|
tmp.Create(head.biWidth, head.biHeight, 1, GetType());
|
||||||
|
tmp.SetStdPalette();
|
||||||
|
tmp.Clear(0);
|
||||||
|
|
||||||
|
for(int32_t y=0; y<head.biHeight; y++){
|
||||||
|
for(int32_t x=0; x<head.biWidth; x++){
|
||||||
|
if (IsTransparent(x,y)){
|
||||||
|
tmp.BlindSetPixelIndex(x,y,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iDst) iDst->Transfer(tmp);
|
||||||
|
else Transfer(tmp);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Checks if image has the same palette, if any.
|
||||||
|
* \param img = image to compare.
|
||||||
|
* \param bCheckAlpha = check also the rgbReserved field.
|
||||||
|
*/
|
||||||
|
bool CxImage::IsSamePalette(CxImage &img, bool bCheckAlpha)
|
||||||
|
{
|
||||||
|
if (head.biClrUsed != img.head.biClrUsed)
|
||||||
|
return false;
|
||||||
|
if (head.biClrUsed == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RGBQUAD c1,c2;
|
||||||
|
for (uint32_t n=0; n<head.biClrUsed; n++){
|
||||||
|
c1 = GetPaletteColor((uint8_t)n);
|
||||||
|
c2 = img.GetPaletteColor((uint8_t)n);
|
||||||
|
if (c1.rgbRed != c2.rgbRed) return false;
|
||||||
|
if (c1.rgbBlue != c2.rgbBlue) return false;
|
||||||
|
if (c1.rgbGreen != c2.rgbGreen) return false;
|
||||||
|
if (bCheckAlpha && (c1.rgbReserved != c2.rgbReserved)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* \sa SetClrImportant
|
||||||
|
*/
|
||||||
|
uint32_t CxImage::GetClrImportant() const
|
||||||
|
{
|
||||||
|
return head.biClrImportant;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* sets the maximum number of colors that some functions like
|
||||||
|
* DecreaseBpp() or GetNearestIndex() will use on indexed images
|
||||||
|
* \param ncolors should be less than 2^bpp,
|
||||||
|
* or 0 if all the colors are important.
|
||||||
|
*/
|
||||||
|
void CxImage::SetClrImportant(uint32_t ncolors)
|
||||||
|
{
|
||||||
|
if (ncolors==0 || ncolors>256) {
|
||||||
|
head.biClrImportant = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(head.biBitCount){
|
||||||
|
case 1:
|
||||||
|
head.biClrImportant = min(ncolors,2);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
head.biClrImportant = min(ncolors,16);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
head.biClrImportant = ncolors;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Returns pointer to pixel. Currently implemented only for truecolor images.
|
||||||
|
*
|
||||||
|
* \param x,y - coordinates
|
||||||
|
*
|
||||||
|
* \return pointer to first byte of pixel data
|
||||||
|
*
|
||||||
|
* \author ***bd*** 2.2004
|
||||||
|
*/
|
||||||
|
void* CxImage::BlindGetPixelPointer(const int32_t x, const int32_t y)
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
if ((pDib==NULL) || !IsInside(x,y))
|
||||||
|
#if CXIMAGE_SUPPORT_EXCEPTION_HANDLING
|
||||||
|
throw 0;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
if (!IsIndexed())
|
||||||
|
return info.pImage + y*info.dwEffWidth + x*3;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::DrawLine(int32_t StartX, int32_t EndX, int32_t StartY, int32_t EndY, COLORREF cr)
|
||||||
|
{
|
||||||
|
DrawLine(StartX, EndX, StartY, EndY, RGBtoRGBQUAD(cr));
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImage::DrawLine(int32_t StartX, int32_t EndX, int32_t StartY, int32_t EndY, RGBQUAD color, bool bSetAlpha)
|
||||||
|
{
|
||||||
|
if (!pDib) return;
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// Draws a line using the Bresenham line algorithm
|
||||||
|
// Thanks to Jordan DeLozier <JDL>
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
int32_t x1 = StartX;
|
||||||
|
int32_t y1 = StartY;
|
||||||
|
int32_t x = x1; // Start x off at the first pixel
|
||||||
|
int32_t y = y1; // Start y off at the first pixel
|
||||||
|
int32_t x2 = EndX;
|
||||||
|
int32_t y2 = EndY;
|
||||||
|
|
||||||
|
int32_t xinc1,xinc2,yinc1,yinc2; // Increasing values
|
||||||
|
int32_t den, num, numadd,numpixels;
|
||||||
|
int32_t deltax = abs(x2 - x1); // The difference between the x's
|
||||||
|
int32_t deltay = abs(y2 - y1); // The difference between the y's
|
||||||
|
|
||||||
|
// Get Increasing Values
|
||||||
|
if (x2 >= x1) { // The x-values are increasing
|
||||||
|
xinc1 = 1;
|
||||||
|
xinc2 = 1;
|
||||||
|
} else { // The x-values are decreasing
|
||||||
|
xinc1 = -1;
|
||||||
|
xinc2 = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y2 >= y1) { // The y-values are increasing
|
||||||
|
yinc1 = 1;
|
||||||
|
yinc2 = 1;
|
||||||
|
} else { // The y-values are decreasing
|
||||||
|
yinc1 = -1;
|
||||||
|
yinc2 = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually draw the line
|
||||||
|
if (deltax >= deltay) // There is at least one x-value for every y-value
|
||||||
|
{
|
||||||
|
xinc1 = 0; // Don't change the x when numerator >= denominator
|
||||||
|
yinc2 = 0; // Don't change the y for every iteration
|
||||||
|
den = deltax;
|
||||||
|
num = deltax / 2;
|
||||||
|
numadd = deltay;
|
||||||
|
numpixels = deltax; // There are more x-values than y-values
|
||||||
|
}
|
||||||
|
else // There is at least one y-value for every x-value
|
||||||
|
{
|
||||||
|
xinc2 = 0; // Don't change the x for every iteration
|
||||||
|
yinc1 = 0; // Don't change the y when numerator >= denominator
|
||||||
|
den = deltay;
|
||||||
|
num = deltay / 2;
|
||||||
|
numadd = deltax;
|
||||||
|
numpixels = deltay; // There are more y-values than x-values
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32_t curpixel = 0; curpixel <= numpixels; curpixel++)
|
||||||
|
{
|
||||||
|
// Draw the current pixel
|
||||||
|
SetPixelColor(x,y,color,bSetAlpha);
|
||||||
|
|
||||||
|
num += numadd; // Increase the numerator by the top of the fraction
|
||||||
|
if (num >= den) // Check if numerator >= denominator
|
||||||
|
{
|
||||||
|
num -= den; // Calculate the new numerator value
|
||||||
|
x += xinc1; // Change the x as appropriate
|
||||||
|
y += yinc1; // Change the y as appropriate
|
||||||
|
}
|
||||||
|
x += xinc2; // Change the x as appropriate
|
||||||
|
y += yinc2; // Change the y as appropriate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Sets a palette with standard colors for 1, 4 and 8 bpp images.
|
||||||
|
*/
|
||||||
|
void CxImage::SetStdPalette()
|
||||||
|
{
|
||||||
|
if (!pDib) return;
|
||||||
|
switch (head.biBitCount){
|
||||||
|
case 8:
|
||||||
|
{
|
||||||
|
const uint8_t pal256[1024] = {0,0,0,0,0,0,128,0,0,128,0,0,0,128,128,0,128,0,0,0,128,0,128,0,128,128,0,0,192,192,192,0,
|
||||||
|
192,220,192,0,240,202,166,0,212,240,255,0,177,226,255,0,142,212,255,0,107,198,255,0,
|
||||||
|
72,184,255,0,37,170,255,0,0,170,255,0,0,146,220,0,0,122,185,0,0,98,150,0,0,74,115,0,0,
|
||||||
|
50,80,0,212,227,255,0,177,199,255,0,142,171,255,0,107,143,255,0,72,115,255,0,37,87,255,0,0,
|
||||||
|
85,255,0,0,73,220,0,0,61,185,0,0,49,150,0,0,37,115,0,0,25,80,0,212,212,255,0,177,177,255,0,
|
||||||
|
142,142,255,0,107,107,255,0,72,72,255,0,37,37,255,0,0,0,254,0,0,0,220,0,0,0,185,0,0,0,150,0,
|
||||||
|
0,0,115,0,0,0,80,0,227,212,255,0,199,177,255,0,171,142,255,0,143,107,255,0,115,72,255,0,
|
||||||
|
87,37,255,0,85,0,255,0,73,0,220,0,61,0,185,0,49,0,150,0,37,0,115,0,25,0,80,0,240,212,255,0,
|
||||||
|
226,177,255,0,212,142,255,0,198,107,255,0,184,72,255,0,170,37,255,0,170,0,255,0,146,0,220,0,
|
||||||
|
122,0,185,0,98,0,150,0,74,0,115,0,50,0,80,0,255,212,255,0,255,177,255,0,255,142,255,0,255,107,255,0,
|
||||||
|
255,72,255,0,255,37,255,0,254,0,254,0,220,0,220,0,185,0,185,0,150,0,150,0,115,0,115,0,80,0,80,0,
|
||||||
|
255,212,240,0,255,177,226,0,255,142,212,0,255,107,198,0,255,72,184,0,255,37,170,0,255,0,170,0,
|
||||||
|
220,0,146,0,185,0,122,0,150,0,98,0,115,0,74,0,80,0,50,0,255,212,227,0,255,177,199,0,255,142,171,0,
|
||||||
|
255,107,143,0,255,72,115,0,255,37,87,0,255,0,85,0,220,0,73,0,185,0,61,0,150,0,49,0,115,0,37,0,
|
||||||
|
80,0,25,0,255,212,212,0,255,177,177,0,255,142,142,0,255,107,107,0,255,72,72,0,255,37,37,0,254,0,
|
||||||
|
0,0,220,0,0,0,185,0,0,0,150,0,0,0,115,0,0,0,80,0,0,0,255,227,212,0,255,199,177,0,255,171,142,0,
|
||||||
|
255,143,107,0,255,115,72,0,255,87,37,0,255,85,0,0,220,73,0,0,185,61,0,0,150,49,0,0,115,37,0,
|
||||||
|
0,80,25,0,0,255,240,212,0,255,226,177,0,255,212,142,0,255,198,107,0,255,184,72,0,255,170,37,0,
|
||||||
|
255,170,0,0,220,146,0,0,185,122,0,0,150,98,0,0,115,74,0,0,80,50,0,0,255,255,212,0,255,255,177,0,
|
||||||
|
255,255,142,0,255,255,107,0,255,255,72,0,255,255,37,0,254,254,0,0,220,220,0,0,185,185,0,0,150,150,0,
|
||||||
|
0,115,115,0,0,80,80,0,0,240,255,212,0,226,255,177,0,212,255,142,0,198,255,107,0,184,255,72,0,
|
||||||
|
170,255,37,0,170,255,0,0,146,220,0,0,122,185,0,0,98,150,0,0,74,115,0,0,50,80,0,0,227,255,212,0,
|
||||||
|
199,255,177,0,171,255,142,0,143,255,107,0,115,255,72,0,87,255,37,0,85,255,0,0,73,220,0,0,61,185,0,
|
||||||
|
0,49,150,0,0,37,115,0,0,25,80,0,0,212,255,212,0,177,255,177,0,142,255,142,0,107,255,107,0,72,255,72,0,
|
||||||
|
37,255,37,0,0,254,0,0,0,220,0,0,0,185,0,0,0,150,0,0,0,115,0,0,0,80,0,0,212,255,227,0,177,255,199,0,
|
||||||
|
142,255,171,0,107,255,143,0,72,255,115,0,37,255,87,0,0,255,85,0,0,220,73,0,0,185,61,0,0,150,49,0,0,
|
||||||
|
115,37,0,0,80,25,0,212,255,240,0,177,255,226,0,142,255,212,0,107,255,198,0,72,255,184,0,37,255,170,0,
|
||||||
|
0,255,170,0,0,220,146,0,0,185,122,0,0,150,98,0,0,115,74,0,0,80,50,0,212,255,255,0,177,255,255,0,
|
||||||
|
142,255,255,0,107,255,255,0,72,255,255,0,37,255,255,0,0,254,254,0,0,220,220,0,0,185,185,0,0,
|
||||||
|
150,150,0,0,115,115,0,0,80,80,0,242,242,242,0,230,230,230,0,218,218,218,0,206,206,206,0,194,194,194,0,
|
||||||
|
182,182,182,0,170,170,170,0,158,158,158,0,146,146,146,0,134,134,134,0,122,122,122,0,110,110,110,0,
|
||||||
|
98,98,98,0,86,86,86,0,74,74,74,0,62,62,62,0,50,50,50,0,38,38,38,0,26,26,26,0,14,14,14,0,240,251,255,0,
|
||||||
|
164,160,160,0,128,128,128,0,0,0,255,0,0,255,0,0,0,255,255,0,255,0,0,0,255,0,255,0,255,255,0,0,255,255,255,0};
|
||||||
|
memcpy(GetPalette(),pal256,1024);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
const uint8_t pal16[64]={0,0,0,0,0,0,128,0,0,128,0,0,0,128,128,0,128,0,0,0,128,0,128,0,128,128,0,0,192,192,192,0,
|
||||||
|
128,128,128,0,0,0,255,0,0,255,0,0,0,255,255,0,255,0,0,0,255,0,255,0,255,255,0,0,255,255,255,0};
|
||||||
|
memcpy(GetPalette(),pal16,64);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
const uint8_t pal2[8]={0,0,0,0,255,255,255,0};
|
||||||
|
memcpy(GetPalette(),pal2,8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info.last_c_isvalid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -0,0 +1,479 @@
|
|||||||
|
/*
|
||||||
|
* File: ximapcx.cpp
|
||||||
|
* Purpose: Platform Independent PCX Image Class Loader and Writer
|
||||||
|
* 05/Jan/2002 Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*
|
||||||
|
* based on ppmtopcx.c - convert a portable pixmap to PCX
|
||||||
|
* Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
|
||||||
|
* based on ppmtopcx.c by Michael Davidson
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximapcx.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_PCX
|
||||||
|
|
||||||
|
#include "xmemfile.h"
|
||||||
|
|
||||||
|
#define PCX_MAGIC 0X0A // PCX magic number
|
||||||
|
#define PCX_256_COLORS 0X0C // magic number for 256 colors
|
||||||
|
#define PCX_HDR_SIZE 128 // size of PCX header
|
||||||
|
#define PCX_MAXCOLORS 256
|
||||||
|
#define PCX_MAXPLANES 4
|
||||||
|
#define PCX_MAXVAL 255
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImagePCX::Decode(CxFile *hFile)
|
||||||
|
{
|
||||||
|
if (hFile == NULL) return false;
|
||||||
|
|
||||||
|
PCXHEADER pcxHeader;
|
||||||
|
int32_t i, x, y, y2, nbytes, count, Height, Width;
|
||||||
|
uint8_t c, ColorMap[PCX_MAXCOLORS][3];
|
||||||
|
uint8_t *pcximage = NULL, *lpHead1 = NULL, *lpHead2 = NULL;
|
||||||
|
uint8_t *pcxplanes, *pcxpixels;
|
||||||
|
|
||||||
|
cx_try
|
||||||
|
{
|
||||||
|
if (hFile->Read(&pcxHeader,sizeof(PCXHEADER),1)==0) cx_throw("Can't read PCX image");
|
||||||
|
|
||||||
|
PCX_toh(&pcxHeader);
|
||||||
|
|
||||||
|
if (pcxHeader.Manufacturer != PCX_MAGIC) cx_throw("Error: Not a PCX file");
|
||||||
|
// Check for PCX run length encoding
|
||||||
|
if (pcxHeader.Encoding != 1) cx_throw("PCX file has unknown encoding scheme");
|
||||||
|
|
||||||
|
Width = (pcxHeader.Xmax - pcxHeader.Xmin) + 1;
|
||||||
|
Height = (pcxHeader.Ymax - pcxHeader.Ymin) + 1;
|
||||||
|
info.xDPI = pcxHeader.Hres;
|
||||||
|
info.yDPI = pcxHeader.Vres;
|
||||||
|
|
||||||
|
if (info.nEscape == -1){
|
||||||
|
head.biWidth = Width;
|
||||||
|
head.biHeight= Height;
|
||||||
|
info.dwType = CXIMAGE_FORMAT_PCX;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that we can handle this image format
|
||||||
|
if (pcxHeader.ColorPlanes > 4)
|
||||||
|
cx_throw("Can't handle image with more than 4 planes");
|
||||||
|
|
||||||
|
// Create the image
|
||||||
|
if (pcxHeader.ColorPlanes >= 3 && pcxHeader.BitsPerPixel == 8){
|
||||||
|
Create (Width, Height, 24, CXIMAGE_FORMAT_PCX);
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (pcxHeader.ColorPlanes==4) AlphaCreate();
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
} else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 1)
|
||||||
|
Create (Width, Height, 4, CXIMAGE_FORMAT_PCX);
|
||||||
|
else
|
||||||
|
Create (Width, Height, pcxHeader.BitsPerPixel, CXIMAGE_FORMAT_PCX);
|
||||||
|
|
||||||
|
if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding
|
||||||
|
|
||||||
|
//Read the image and check if it's ok
|
||||||
|
nbytes = pcxHeader.BytesPerLine * pcxHeader.ColorPlanes * Height;
|
||||||
|
lpHead1 = pcximage = (uint8_t*)malloc(nbytes);
|
||||||
|
while (nbytes > 0){
|
||||||
|
if (hFile == NULL || hFile->Eof()) cx_throw("corrupted PCX");
|
||||||
|
|
||||||
|
hFile->Read(&c,1,1);
|
||||||
|
if ((c & 0XC0) != 0XC0){ // Repeated group
|
||||||
|
*pcximage++ = c;
|
||||||
|
--nbytes;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
count = c & 0X3F; // extract count
|
||||||
|
hFile->Read(&c,1,1);
|
||||||
|
if (count > nbytes) cx_throw("repeat count spans end of image");
|
||||||
|
|
||||||
|
nbytes -= count;
|
||||||
|
while (--count >=0) *pcximage++ = c;
|
||||||
|
}
|
||||||
|
pcximage = lpHead1;
|
||||||
|
|
||||||
|
//store the palette
|
||||||
|
for (i = 0; i < 16; i++){
|
||||||
|
ColorMap[i][0] = pcxHeader.ColorMap[i][0];
|
||||||
|
ColorMap[i][1] = pcxHeader.ColorMap[i][1];
|
||||||
|
ColorMap[i][2] = pcxHeader.ColorMap[i][2];
|
||||||
|
}
|
||||||
|
if (pcxHeader.BitsPerPixel == 8 && pcxHeader.ColorPlanes == 1){
|
||||||
|
hFile->Read(&c,1,1);
|
||||||
|
if (c != PCX_256_COLORS) cx_throw("bad color map signature");
|
||||||
|
|
||||||
|
for (i = 0; i < PCX_MAXCOLORS; i++){
|
||||||
|
hFile->Read(&ColorMap[i][0],1,1);
|
||||||
|
hFile->Read(&ColorMap[i][1],1,1);
|
||||||
|
hFile->Read(&ColorMap[i][2],1,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 1){
|
||||||
|
ColorMap[0][0] = ColorMap[0][1] = ColorMap[0][2] = 0;
|
||||||
|
ColorMap[1][0] = ColorMap[1][1] = ColorMap[1][2] = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t idx=0; idx<head.biClrUsed; idx++) SetPaletteColor((uint8_t)idx,ColorMap[idx][0],ColorMap[idx][1],ColorMap[idx][2]);
|
||||||
|
|
||||||
|
lpHead2 = pcxpixels = (uint8_t *)malloc(Width + pcxHeader.BytesPerLine * 8);
|
||||||
|
// Convert the image
|
||||||
|
for (y = 0; y < Height; y++){
|
||||||
|
|
||||||
|
if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding
|
||||||
|
|
||||||
|
y2=Height-1-y;
|
||||||
|
pcxpixels = lpHead2;
|
||||||
|
pcxplanes = pcximage + (y * pcxHeader.BytesPerLine * pcxHeader.ColorPlanes);
|
||||||
|
|
||||||
|
if (pcxHeader.ColorPlanes == 3 && pcxHeader.BitsPerPixel == 8){
|
||||||
|
// Deal with 24 bit color image
|
||||||
|
for (x = 0; x < Width; x++){
|
||||||
|
SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x]));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
} else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 8){
|
||||||
|
for (x = 0; x < Width; x++){
|
||||||
|
SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x]));
|
||||||
|
AlphaSet(x,y2,pcxplanes[3*pcxHeader.BytesPerLine + x]);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
} else if (pcxHeader.ColorPlanes == 1) {
|
||||||
|
if (!PCX_UnpackPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel)){
|
||||||
|
cx_throw("PCX_UnpackPixels: Can't handle packed pixels with more than 1 plane");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!PCX_PlanesToPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel)){
|
||||||
|
cx_throw("PCX_PlanesToPixels: more than 4 planes or more than 1 bit per pixel");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (x = 0; x < Width; x++) SetPixelIndex(x,y2,pcxpixels[x]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} cx_catch {
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
if (lpHead1){ free(lpHead1); lpHead1 = NULL; }
|
||||||
|
if (lpHead2){ free(lpHead2); lpHead2 = NULL; }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (lpHead1){ free(lpHead1); lpHead1 = NULL; }
|
||||||
|
if (lpHead2){ free(lpHead2); lpHead2 = NULL; }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImagePCX::Encode(CxFile * hFile)
|
||||||
|
{
|
||||||
|
if (EncodeSafeCheck(hFile)) return false;
|
||||||
|
|
||||||
|
cx_try
|
||||||
|
{
|
||||||
|
PCXHEADER pcxHeader;
|
||||||
|
memset(&pcxHeader,0,sizeof(pcxHeader));
|
||||||
|
pcxHeader.Manufacturer = PCX_MAGIC;
|
||||||
|
pcxHeader.Version = 5;
|
||||||
|
pcxHeader.Encoding = 1;
|
||||||
|
pcxHeader.Xmin = 0;
|
||||||
|
pcxHeader.Ymin = 0;
|
||||||
|
pcxHeader.Xmax = (uint16_t)head.biWidth-1;
|
||||||
|
pcxHeader.Ymax = (uint16_t)head.biHeight-1;
|
||||||
|
pcxHeader.Hres = (uint16_t)info.xDPI;
|
||||||
|
pcxHeader.Vres = (uint16_t)info.yDPI;
|
||||||
|
pcxHeader.Reserved = 0;
|
||||||
|
pcxHeader.PaletteType = head.biClrUsed==0;
|
||||||
|
|
||||||
|
switch(head.biBitCount){
|
||||||
|
case 24:
|
||||||
|
case 8:
|
||||||
|
{
|
||||||
|
pcxHeader.BitsPerPixel = 8;
|
||||||
|
pcxHeader.ColorPlanes = head.biClrUsed==0 ? 3 : 1;
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (AlphaIsValid() && head.biClrUsed==0) pcxHeader.ColorPlanes =4;
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
pcxHeader.BytesPerLine = (uint16_t)head.biWidth;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: //(4 1)
|
||||||
|
pcxHeader.BitsPerPixel = 1;
|
||||||
|
pcxHeader.ColorPlanes = head.biClrUsed==16 ? 4 : 1;
|
||||||
|
pcxHeader.BytesPerLine = (uint16_t)((head.biWidth * pcxHeader.BitsPerPixel + 7)>>3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 1){
|
||||||
|
pcxHeader.ColorMap[0][0] = pcxHeader.ColorMap[0][1] = pcxHeader.ColorMap[0][2] = 0;
|
||||||
|
pcxHeader.ColorMap[1][0] = pcxHeader.ColorMap[1][1] = pcxHeader.ColorMap[1][2] = 255;
|
||||||
|
}
|
||||||
|
if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 4){
|
||||||
|
RGBQUAD c;
|
||||||
|
for (int32_t i = 0; i < 16; i++){
|
||||||
|
c=GetPaletteColor(i);
|
||||||
|
pcxHeader.ColorMap[i][0] = c.rgbRed;
|
||||||
|
pcxHeader.ColorMap[i][1] = c.rgbGreen;
|
||||||
|
pcxHeader.ColorMap[i][2] = c.rgbBlue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pcxHeader.BytesPerLine = (pcxHeader.BytesPerLine + 1)&(~1);
|
||||||
|
|
||||||
|
PCX_toh(&pcxHeader);
|
||||||
|
if (hFile->Write(&pcxHeader, sizeof(pcxHeader), 1) == 0 )
|
||||||
|
cx_throw("cannot write PCX header");
|
||||||
|
PCX_toh(&pcxHeader);
|
||||||
|
|
||||||
|
CxMemFile buffer;
|
||||||
|
buffer.Open();
|
||||||
|
|
||||||
|
uint8_t c,n;
|
||||||
|
int32_t x,y;
|
||||||
|
if (head.biClrUsed==0){
|
||||||
|
for (y = head.biHeight-1; y >=0 ; y--){
|
||||||
|
for (int32_t p=0; p<pcxHeader.ColorPlanes; p++){
|
||||||
|
c=n=0;
|
||||||
|
for (x = 0; x<head.biWidth; x++){
|
||||||
|
if (p==0)
|
||||||
|
PCX_PackPixels(BlindGetPixelColor(x,y).rgbRed,c,n,buffer);
|
||||||
|
else if (p==1)
|
||||||
|
PCX_PackPixels(BlindGetPixelColor(x,y).rgbGreen,c,n,buffer);
|
||||||
|
else if (p==2)
|
||||||
|
PCX_PackPixels(BlindGetPixelColor(x,y).rgbBlue,c,n,buffer);
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
else if (p==3)
|
||||||
|
PCX_PackPixels(BlindAlphaGet(x,y),c,n,buffer);
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
}
|
||||||
|
PCX_PackPixels(-1-(head.biWidth&0x1),c,n,buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1);
|
||||||
|
|
||||||
|
} else if (head.biBitCount==8) {
|
||||||
|
|
||||||
|
for (y = head.biHeight-1; y >=0 ; y--){
|
||||||
|
c=n=0;
|
||||||
|
for (x = 0; x<head.biWidth; x++){
|
||||||
|
PCX_PackPixels(GetPixelIndex(x,y),c,n,buffer);
|
||||||
|
}
|
||||||
|
PCX_PackPixels(-1-(head.biWidth&0x1),c,n,buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1);
|
||||||
|
|
||||||
|
if (head.biBitCount == 8){
|
||||||
|
hFile->PutC(0x0C);
|
||||||
|
uint8_t* pal = (uint8_t*)malloc(768);
|
||||||
|
RGBQUAD c;
|
||||||
|
for (int32_t i=0;i<256;i++){
|
||||||
|
c=GetPaletteColor(i);
|
||||||
|
pal[3*i+0] = c.rgbRed;
|
||||||
|
pal[3*i+1] = c.rgbGreen;
|
||||||
|
pal[3*i+2] = c.rgbBlue;
|
||||||
|
}
|
||||||
|
hFile->Write(pal,768,1);
|
||||||
|
free(pal);
|
||||||
|
}
|
||||||
|
} else { //(head.biBitCount==4) || (head.biBitCount==1)
|
||||||
|
|
||||||
|
RGBQUAD *rgb = GetPalette();
|
||||||
|
bool binvert = false;
|
||||||
|
if (CompareColors(&rgb[0],&rgb[1])>0) binvert=(head.biBitCount==1);
|
||||||
|
|
||||||
|
uint8_t* plane = (uint8_t*)malloc(pcxHeader.BytesPerLine);
|
||||||
|
uint8_t* raw = (uint8_t*)malloc(head.biWidth);
|
||||||
|
|
||||||
|
for(y = head.biHeight-1; y >=0 ; y--) {
|
||||||
|
|
||||||
|
for( x = 0; x < head.biWidth; x++) raw[x] = (uint8_t)GetPixelIndex(x,y);
|
||||||
|
|
||||||
|
if (binvert) for( x = 0; x < head.biWidth; x++) raw[x] = 1-raw[x];
|
||||||
|
|
||||||
|
for( x = 0; x < pcxHeader.ColorPlanes; x++ ) {
|
||||||
|
PCX_PixelsToPlanes(raw, head.biWidth, plane, x);
|
||||||
|
PCX_PackPlanes(plane, pcxHeader.BytesPerLine, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(plane);
|
||||||
|
free(raw);
|
||||||
|
|
||||||
|
hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} cx_catch {
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Convert multi-plane format into 1 pixel per byte
|
||||||
|
// from unpacked file data bitplanes[] into pixel row pixels[]
|
||||||
|
// image Height rows, with each row having planes image planes each
|
||||||
|
// bytesperline bytes
|
||||||
|
bool CxImagePCX::PCX_PlanesToPixels(uint8_t * pixels, uint8_t * bitplanes, int16_t bytesperline, int16_t planes, int16_t bitsperpixel)
|
||||||
|
{
|
||||||
|
int32_t i, j, npixels;
|
||||||
|
uint8_t * p;
|
||||||
|
if (planes > 4) return false;
|
||||||
|
if (bitsperpixel != 1) return false;
|
||||||
|
|
||||||
|
// Clear the pixel buffer
|
||||||
|
npixels = (bytesperline * 8) / bitsperpixel;
|
||||||
|
p = pixels;
|
||||||
|
while (--npixels >= 0) *p++ = 0;
|
||||||
|
|
||||||
|
// Do the format conversion
|
||||||
|
for (i = 0; i < planes; i++){
|
||||||
|
int32_t pixbit, bits, mask;
|
||||||
|
p = pixels;
|
||||||
|
pixbit = (1 << i); // pixel bit for this plane
|
||||||
|
for (j = 0; j < bytesperline; j++){
|
||||||
|
bits = *bitplanes++;
|
||||||
|
for (mask = 0X80; mask != 0; mask >>= 1, p++)
|
||||||
|
if (bits & mask) *p |= pixbit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// convert packed pixel format into 1 pixel per byte
|
||||||
|
// from unpacked file data bitplanes[] into pixel row pixels[]
|
||||||
|
// image Height rows, with each row having planes image planes each
|
||||||
|
// bytesperline bytes
|
||||||
|
bool CxImagePCX::PCX_UnpackPixels(uint8_t * pixels, uint8_t * bitplanes, int16_t bytesperline, int16_t planes, int16_t bitsperpixel)
|
||||||
|
{
|
||||||
|
register int32_t bits;
|
||||||
|
if (planes != 1) return false;
|
||||||
|
|
||||||
|
if (bitsperpixel == 8){ // 8 bits/pixels, no unpacking needed
|
||||||
|
while (bytesperline-- > 0) *pixels++ = *bitplanes++;
|
||||||
|
} else if (bitsperpixel == 4){ // 4 bits/pixel, two pixels per byte
|
||||||
|
while (bytesperline-- > 0){
|
||||||
|
bits = *bitplanes++;
|
||||||
|
*pixels++ = (uint8_t)((bits >> 4) & 0X0F);
|
||||||
|
*pixels++ = (uint8_t)((bits) & 0X0F);
|
||||||
|
}
|
||||||
|
} else if (bitsperpixel == 2){ // 2 bits/pixel, four pixels per byte
|
||||||
|
while (bytesperline-- > 0){
|
||||||
|
bits = *bitplanes++;
|
||||||
|
*pixels++ = (uint8_t)((bits >> 6) & 0X03);
|
||||||
|
*pixels++ = (uint8_t)((bits >> 4) & 0X03);
|
||||||
|
*pixels++ = (uint8_t)((bits >> 2) & 0X03);
|
||||||
|
*pixels++ = (uint8_t)((bits) & 0X03);
|
||||||
|
}
|
||||||
|
} else if (bitsperpixel == 1){ // 1 bits/pixel, 8 pixels per byte
|
||||||
|
while (bytesperline-- > 0){
|
||||||
|
bits = *bitplanes++;
|
||||||
|
*pixels++ = ((bits & 0X80) != 0);
|
||||||
|
*pixels++ = ((bits & 0X40) != 0);
|
||||||
|
*pixels++ = ((bits & 0X20) != 0);
|
||||||
|
*pixels++ = ((bits & 0X10) != 0);
|
||||||
|
*pixels++ = ((bits & 0X08) != 0);
|
||||||
|
*pixels++ = ((bits & 0X04) != 0);
|
||||||
|
*pixels++ = ((bits & 0X02) != 0);
|
||||||
|
*pixels++ = ((bits & 0X01) != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/* PCX_PackPixels(const int32_t p,uint8_t &c, uint8_t &n, int32_t &l, CxFile &f)
|
||||||
|
* p = current pixel (-1 ends the line -2 ends odd line)
|
||||||
|
* c = previous pixel
|
||||||
|
* n = number of consecutive pixels
|
||||||
|
*/
|
||||||
|
void CxImagePCX::PCX_PackPixels(const int32_t p,uint8_t &c, uint8_t &n, CxFile &f)
|
||||||
|
{
|
||||||
|
if (p!=c && n){
|
||||||
|
if (n==1 && c<0xC0){
|
||||||
|
f.PutC(c);
|
||||||
|
} else {
|
||||||
|
f.PutC(0xC0|n);
|
||||||
|
f.PutC(c);
|
||||||
|
}
|
||||||
|
n=0;
|
||||||
|
}
|
||||||
|
if (n==0x3F) {
|
||||||
|
f.PutC(0xFF);
|
||||||
|
f.PutC(c);
|
||||||
|
n=0;
|
||||||
|
}
|
||||||
|
if (p==-2) f.PutC(0);
|
||||||
|
c=(uint8_t)p;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImagePCX::PCX_PackPlanes(uint8_t* buff, const int32_t size, CxFile &f)
|
||||||
|
{
|
||||||
|
uint8_t *start,*end;
|
||||||
|
uint8_t c, previous, count;
|
||||||
|
|
||||||
|
start = buff;
|
||||||
|
end = buff + size;
|
||||||
|
previous = *start++;
|
||||||
|
count = 1;
|
||||||
|
|
||||||
|
while (start < end) {
|
||||||
|
c = *start++;
|
||||||
|
if (c == previous && count < 63) {
|
||||||
|
++count;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 1 || (previous & 0xc0) == 0xc0) {
|
||||||
|
f.PutC( count | 0xc0 );
|
||||||
|
}
|
||||||
|
f.PutC(previous);
|
||||||
|
previous = c;
|
||||||
|
count = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 1 || (previous & 0xc0) == 0xc0) {
|
||||||
|
count |= 0xc0;
|
||||||
|
f.PutC(count);
|
||||||
|
}
|
||||||
|
f.PutC(previous);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImagePCX::PCX_PixelsToPlanes(uint8_t* raw, int32_t width, uint8_t* buf, int32_t plane)
|
||||||
|
{
|
||||||
|
int32_t cbit, x, mask;
|
||||||
|
uint8_t *cp = buf-1;
|
||||||
|
|
||||||
|
mask = 1 << plane;
|
||||||
|
cbit = -1;
|
||||||
|
for( x = 0; x < width; x++ ) {
|
||||||
|
if( cbit < 0 ) {
|
||||||
|
cbit = 7;
|
||||||
|
*++cp = 0;
|
||||||
|
}
|
||||||
|
if( raw[x] & mask )
|
||||||
|
*cp |= (1<<cbit);
|
||||||
|
--cbit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImagePCX::PCX_toh(PCXHEADER* p)
|
||||||
|
{
|
||||||
|
p->Xmin = m_ntohs(p->Xmin);
|
||||||
|
p->Ymin = m_ntohs(p->Ymin);
|
||||||
|
p->Xmax = m_ntohs(p->Xmax);
|
||||||
|
p->Ymax = m_ntohs(p->Ymax);
|
||||||
|
p->Hres = m_ntohs(p->Hres);
|
||||||
|
p->Vres = m_ntohs(p->Vres);
|
||||||
|
p->BytesPerLine = m_ntohs(p->BytesPerLine);
|
||||||
|
p->PaletteType = m_ntohs(p->PaletteType);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_PCX
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* File: ximapcx.h
|
||||||
|
* Purpose: PCX Image Class Loader and Writer
|
||||||
|
*/
|
||||||
|
/* ==========================================================
|
||||||
|
* CxImagePCX (c) 05/Jan/2002 Davide Pizzolato - www.xdp.it
|
||||||
|
* For conditions of distribution and use, see copyright notice in ximage.h
|
||||||
|
*
|
||||||
|
* Parts of the code come from Paintlib: Copyright (c) 1996-1998 Ulrich von Zadow
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
#if !defined(__ximaPCX_h)
|
||||||
|
#define __ximaPCX_h
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_PCX
|
||||||
|
|
||||||
|
class CxImagePCX: public CxImage
|
||||||
|
{
|
||||||
|
// PCX Image File
|
||||||
|
#pragma pack(1)
|
||||||
|
typedef struct tagPCXHEADER
|
||||||
|
{
|
||||||
|
char Manufacturer; // always 0X0A
|
||||||
|
char Version; // version number
|
||||||
|
char Encoding; // always 1
|
||||||
|
char BitsPerPixel; // color bits
|
||||||
|
uint16_t Xmin, Ymin; // image origin
|
||||||
|
uint16_t Xmax, Ymax; // image dimensions
|
||||||
|
uint16_t Hres, Vres; // resolution values
|
||||||
|
uint8_t ColorMap[16][3]; // color palette
|
||||||
|
char Reserved;
|
||||||
|
char ColorPlanes; // color planes
|
||||||
|
uint16_t BytesPerLine; // line buffer size
|
||||||
|
uint16_t PaletteType; // grey or color palette
|
||||||
|
char Filter[58];
|
||||||
|
} PCXHEADER;
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
public:
|
||||||
|
CxImagePCX(): CxImage(CXIMAGE_FORMAT_PCX) {}
|
||||||
|
|
||||||
|
// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_PCX);}
|
||||||
|
// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_PCX);}
|
||||||
|
bool Decode(CxFile * hFile);
|
||||||
|
bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
bool Encode(CxFile * hFile);
|
||||||
|
bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
protected:
|
||||||
|
bool PCX_PlanesToPixels(uint8_t * pixels, uint8_t * bitplanes, int16_t bytesperline, int16_t planes, int16_t bitsperpixel);
|
||||||
|
bool PCX_UnpackPixels(uint8_t * pixels, uint8_t * bitplanes, int16_t bytesperline, int16_t planes, int16_t bitsperpixel);
|
||||||
|
void PCX_PackPixels(const int32_t p,uint8_t &c, uint8_t &n, CxFile &f);
|
||||||
|
void PCX_PackPlanes(uint8_t* buff, const int32_t size, CxFile &f);
|
||||||
|
void PCX_PixelsToPlanes(uint8_t* raw, int32_t width, uint8_t* buf, int32_t plane);
|
||||||
|
void PCX_toh(PCXHEADER* p);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,553 @@
|
|||||||
|
/*
|
||||||
|
* File: ximapng.cpp
|
||||||
|
* Purpose: Platform Independent PNG Image Class Loader and Writer
|
||||||
|
* 07/Aug/2001 Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximapng.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_PNG
|
||||||
|
|
||||||
|
#include "ximaiter.h"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImagePNG::ima_png_error(png_struct *png_ptr, char *message)
|
||||||
|
{
|
||||||
|
strcpy(info.szLastError,message);
|
||||||
|
longjmp(png_ptr->png_jmpbuf, 1);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImagePNG::expand2to4bpp(uint8_t* prow)
|
||||||
|
{
|
||||||
|
uint8_t *psrc,*pdst;
|
||||||
|
uint8_t pos,idx;
|
||||||
|
for(int32_t x=head.biWidth-1;x>=0;x--){
|
||||||
|
psrc = prow + ((2*x)>>3);
|
||||||
|
pdst = prow + ((4*x)>>3);
|
||||||
|
pos = (uint8_t)(2*(3-x%4));
|
||||||
|
idx = (uint8_t)((*psrc & (0x03<<pos))>>pos);
|
||||||
|
pos = (uint8_t)(4*(1-x%2));
|
||||||
|
*pdst &= ~(0x0F<<pos);
|
||||||
|
*pdst |= (idx & 0x0F)<<pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImagePNG::Decode(CxFile *hFile)
|
||||||
|
{
|
||||||
|
png_struct *png_ptr;
|
||||||
|
png_info *info_ptr;
|
||||||
|
uint8_t *row_pointers=NULL;
|
||||||
|
CImageIterator iter(this);
|
||||||
|
|
||||||
|
cx_try
|
||||||
|
{
|
||||||
|
/* Create and initialize the png_struct with the desired error handler
|
||||||
|
* functions. If you want to use the default stderr and longjump method,
|
||||||
|
* you can supply NULL for the last three parameters. We also supply the
|
||||||
|
* the compiler header file version, so that we know if the application
|
||||||
|
* was compiled with a compatible version of the library. REQUIRED */
|
||||||
|
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,(void *)NULL,NULL,NULL);
|
||||||
|
if (png_ptr == NULL) cx_throw("Failed to create PNG structure");
|
||||||
|
|
||||||
|
/* Allocate/initialize the memory for image information. REQUIRED. */
|
||||||
|
info_ptr = png_create_info_struct(png_ptr);
|
||||||
|
if (info_ptr == NULL) {
|
||||||
|
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
|
||||||
|
cx_throw("Failed to initialize PNG info structure");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set error handling if you are using the setjmp/longjmp method (this is
|
||||||
|
* the normal method of doing things with libpng). REQUIRED unless you
|
||||||
|
* set up your own error handlers in the png_create_read_struct() earlier. */
|
||||||
|
if (setjmp(png_ptr->png_jmpbuf)) {
|
||||||
|
/* Free all of the memory associated with the png_ptr and info_ptr */
|
||||||
|
delete [] row_pointers;
|
||||||
|
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
|
||||||
|
cx_throw("");
|
||||||
|
}
|
||||||
|
|
||||||
|
// use custom I/O functions
|
||||||
|
png_set_read_fn(png_ptr, hFile, /*(png_rw_ptr)*/user_read_data);
|
||||||
|
png_set_error_fn(png_ptr,info.szLastError,/*(png_error_ptr)*/user_error_fn,NULL);
|
||||||
|
|
||||||
|
/* read the file information */
|
||||||
|
png_read_info(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
if (info.nEscape == -1){
|
||||||
|
head.biWidth = info_ptr->width;
|
||||||
|
head.biHeight= info_ptr->height;
|
||||||
|
info.dwType = CXIMAGE_FORMAT_PNG;
|
||||||
|
longjmp(png_ptr->png_jmpbuf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* calculate new number of channels */
|
||||||
|
int32_t channels=0;
|
||||||
|
switch(info_ptr->color_type){
|
||||||
|
case PNG_COLOR_TYPE_GRAY:
|
||||||
|
case PNG_COLOR_TYPE_PALETTE:
|
||||||
|
channels = 1;
|
||||||
|
break;
|
||||||
|
case PNG_COLOR_TYPE_GRAY_ALPHA:
|
||||||
|
channels = 2;
|
||||||
|
break;
|
||||||
|
case PNG_COLOR_TYPE_RGB:
|
||||||
|
channels = 3;
|
||||||
|
break;
|
||||||
|
case PNG_COLOR_TYPE_RGB_ALPHA:
|
||||||
|
channels = 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strcpy(info.szLastError,"unknown PNG color type");
|
||||||
|
longjmp(png_ptr->png_jmpbuf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//find the right pixel depth used for cximage
|
||||||
|
int32_t pixel_depth = info_ptr->pixel_depth;
|
||||||
|
if (channels == 1 && pixel_depth>8) pixel_depth=8;
|
||||||
|
if (channels == 2) pixel_depth=8;
|
||||||
|
if (channels >= 3) pixel_depth=24;
|
||||||
|
|
||||||
|
if (!Create(info_ptr->width, info_ptr->height, pixel_depth, CXIMAGE_FORMAT_PNG)){
|
||||||
|
longjmp(png_ptr->png_jmpbuf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get metrics */
|
||||||
|
switch (info_ptr->phys_unit_type)
|
||||||
|
{
|
||||||
|
case PNG_RESOLUTION_UNKNOWN:
|
||||||
|
SetXDPI(info_ptr->x_pixels_per_unit);
|
||||||
|
SetYDPI(info_ptr->y_pixels_per_unit);
|
||||||
|
break;
|
||||||
|
case PNG_RESOLUTION_METER:
|
||||||
|
SetXDPI((int32_t)floor(info_ptr->x_pixels_per_unit * 254.0 / 10000.0 + 0.5));
|
||||||
|
SetYDPI((int32_t)floor(info_ptr->y_pixels_per_unit * 254.0 / 10000.0 + 0.5));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info_ptr->num_palette>0){
|
||||||
|
SetPalette((rgb_color*)info_ptr->palette,info_ptr->num_palette);
|
||||||
|
SetClrImportant(info_ptr->num_palette);
|
||||||
|
} else if (info_ptr->bit_depth ==2) { //<DP> needed for 2 bpp grayscale PNGs
|
||||||
|
SetPaletteColor(0,0,0,0);
|
||||||
|
SetPaletteColor(1,85,85,85);
|
||||||
|
SetPaletteColor(2,170,170,170);
|
||||||
|
SetPaletteColor(3,255,255,255);
|
||||||
|
} else SetGrayPalette(); //<DP> needed for grayscale PNGs
|
||||||
|
|
||||||
|
int32_t nshift = max(0,(info_ptr->bit_depth>>3)-1)<<3;
|
||||||
|
|
||||||
|
if (info_ptr->num_trans!=0){ //palette transparency
|
||||||
|
if (info_ptr->num_trans==1){
|
||||||
|
if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE){
|
||||||
|
info.nBkgndIndex = info_ptr->trans_color.index;
|
||||||
|
} else{
|
||||||
|
info.nBkgndIndex = info_ptr->trans_color.gray>>nshift;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (info_ptr->num_trans>1){
|
||||||
|
RGBQUAD* pal=GetPalette();
|
||||||
|
if (pal){
|
||||||
|
uint32_t ip;
|
||||||
|
for (ip=0;ip<min(head.biClrUsed,(uint32_t)info_ptr->num_trans);ip++)
|
||||||
|
pal[ip].rgbReserved=info_ptr->trans_alpha[ip];
|
||||||
|
for (ip=info_ptr->num_trans;ip<head.biClrUsed;ip++){
|
||||||
|
pal[ip].rgbReserved=255;
|
||||||
|
}
|
||||||
|
info.bAlphaPaletteEnabled=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channels == 3){ //check RGB binary transparency
|
||||||
|
png_bytep trans;
|
||||||
|
int32_t num_trans;
|
||||||
|
png_color_16 *image_background;
|
||||||
|
if (png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &image_background)){
|
||||||
|
info.nBkgndColor.rgbRed = (uint8_t)(info_ptr->trans_color.red>>nshift);
|
||||||
|
info.nBkgndColor.rgbGreen = (uint8_t)(info_ptr->trans_color.green>>nshift);
|
||||||
|
info.nBkgndColor.rgbBlue = (uint8_t)(info_ptr->trans_color.blue>>nshift);
|
||||||
|
info.nBkgndColor.rgbReserved = 0;
|
||||||
|
info.nBkgndIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t alpha_present = (channels - 1) % 2;
|
||||||
|
if (alpha_present){
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA // <vho>
|
||||||
|
AlphaCreate();
|
||||||
|
#else
|
||||||
|
png_set_strip_alpha(png_ptr);
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
}
|
||||||
|
|
||||||
|
// <vho> - flip the RGB pixels to BGR (or RGBA to BGRA)
|
||||||
|
if (info_ptr->color_type & PNG_COLOR_MASK_COLOR){
|
||||||
|
png_set_bgr(png_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// <vho> - handle cancel
|
||||||
|
if (info.nEscape) longjmp(png_ptr->png_jmpbuf, 1);
|
||||||
|
|
||||||
|
// row_bytes is the width x number of channels x (bit-depth / 8)
|
||||||
|
row_pointers = new uint8_t[info_ptr->rowbytes + 8];
|
||||||
|
|
||||||
|
// turn on interlace handling
|
||||||
|
int32_t number_passes = png_set_interlace_handling(png_ptr);
|
||||||
|
|
||||||
|
if (number_passes>1){
|
||||||
|
SetCodecOption( (ENCODE_INTERLACE) | GetCodecOption(CXIMAGE_FORMAT_PNG));
|
||||||
|
} else {
|
||||||
|
SetCodecOption(~(ENCODE_INTERLACE) & GetCodecOption(CXIMAGE_FORMAT_PNG));
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t chan_offset = info_ptr->bit_depth >> 3;
|
||||||
|
int32_t pixel_offset = info_ptr->pixel_depth >> 3;
|
||||||
|
|
||||||
|
for (int32_t pass=0; pass < number_passes; pass++) {
|
||||||
|
iter.Upset();
|
||||||
|
int32_t y=0;
|
||||||
|
do {
|
||||||
|
|
||||||
|
// <vho> - handle cancel
|
||||||
|
if (info.nEscape) longjmp(png_ptr->png_jmpbuf, 1);
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA // <vho>
|
||||||
|
if (AlphaIsValid()) {
|
||||||
|
|
||||||
|
//compute the correct position of the line
|
||||||
|
int32_t ax,ay;
|
||||||
|
ay = head.biHeight-1-y;
|
||||||
|
uint8_t* prow= iter.GetRow(ay);
|
||||||
|
|
||||||
|
//recover data from previous scan
|
||||||
|
if (info_ptr->interlace_type && pass>0 && pass!=7){
|
||||||
|
for(ax=0;ax<head.biWidth;ax++){
|
||||||
|
int32_t px = ax * pixel_offset;
|
||||||
|
if (channels == 2){
|
||||||
|
row_pointers[px] = prow[ax];
|
||||||
|
row_pointers[px+chan_offset]=AlphaGet(ax,ay);
|
||||||
|
} else {
|
||||||
|
int32_t qx = ax * 3;
|
||||||
|
row_pointers[px] =prow[qx];
|
||||||
|
row_pointers[px+chan_offset] =prow[qx+1];
|
||||||
|
row_pointers[px+chan_offset*2]=prow[qx+2];
|
||||||
|
row_pointers[px+chan_offset*3]=AlphaGet(ax,ay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//read next row
|
||||||
|
png_read_row(png_ptr, row_pointers, NULL);
|
||||||
|
|
||||||
|
//RGBA -> RGB + A
|
||||||
|
for(ax=0;ax<head.biWidth;ax++){
|
||||||
|
int32_t px = ax * pixel_offset;
|
||||||
|
if (channels == 2){
|
||||||
|
prow[ax] = row_pointers[px];
|
||||||
|
AlphaSet(ax,ay,row_pointers[px+chan_offset]);
|
||||||
|
} else {
|
||||||
|
int32_t qx = ax * 3;
|
||||||
|
prow[qx] =row_pointers[px];
|
||||||
|
prow[qx+1]=row_pointers[px+chan_offset];
|
||||||
|
prow[qx+2]=row_pointers[px+chan_offset*2];
|
||||||
|
AlphaSet(ax,ay,row_pointers[px+chan_offset*3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif // CXIMAGE_SUPPORT_ALPHA // vho
|
||||||
|
{
|
||||||
|
//recover data from previous scan
|
||||||
|
if (info_ptr->interlace_type && pass>0){
|
||||||
|
iter.GetRow(row_pointers, info_ptr->rowbytes);
|
||||||
|
//re-expand buffer for images with bit depth > 8
|
||||||
|
if (info_ptr->bit_depth > 8){
|
||||||
|
for(int32_t ax=(head.biWidth*channels-1);ax>=0;ax--)
|
||||||
|
row_pointers[ax*chan_offset] = row_pointers[ax];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//read next row
|
||||||
|
png_read_row(png_ptr, row_pointers, NULL);
|
||||||
|
|
||||||
|
//shrink 16 bit depth images down to 8 bits
|
||||||
|
if (info_ptr->bit_depth > 8){
|
||||||
|
for(int32_t ax=0;ax<(head.biWidth*channels);ax++)
|
||||||
|
row_pointers[ax] = row_pointers[ax*chan_offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
//copy the pixels
|
||||||
|
iter.SetRow(row_pointers, info_ptr->rowbytes);
|
||||||
|
//<DP> expand 2 bpp images only in the last pass
|
||||||
|
if (info_ptr->bit_depth==2 && pass==(number_passes-1))
|
||||||
|
expand2to4bpp(iter.GetRow());
|
||||||
|
|
||||||
|
//go on
|
||||||
|
iter.PrevRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
y++;
|
||||||
|
} while(y<head.biHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete [] row_pointers;
|
||||||
|
row_pointers = NULL;
|
||||||
|
|
||||||
|
/* read the rest of the file, getting any additional chunks in info_ptr - REQUIRED */
|
||||||
|
png_read_end(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
/* clean up after the read, and free any memory allocated - REQUIRED */
|
||||||
|
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
|
||||||
|
|
||||||
|
} cx_catch {
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_PNG) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* that's it */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImagePNG::Encode(CxFile *hFile)
|
||||||
|
{
|
||||||
|
if (EncodeSafeCheck(hFile)) return false;
|
||||||
|
|
||||||
|
CImageIterator iter(this);
|
||||||
|
uint8_t trans[256]; //for transparency (don't move)
|
||||||
|
png_struct *png_ptr;
|
||||||
|
png_info *info_ptr;
|
||||||
|
|
||||||
|
cx_try
|
||||||
|
{
|
||||||
|
/* Create and initialize the png_struct with the desired error handler
|
||||||
|
* functions. If you want to use the default stderr and longjump method,
|
||||||
|
* you can supply NULL for the last three parameters. We also check that
|
||||||
|
* the library version is compatible with the one used at compile time,
|
||||||
|
* in case we are using dynamically linked libraries. REQUIRED.
|
||||||
|
*/
|
||||||
|
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,(void *)NULL,NULL,NULL);
|
||||||
|
if (png_ptr == NULL) cx_throw("Failed to create PNG structure");
|
||||||
|
|
||||||
|
/* Allocate/initialize the image information data. REQUIRED */
|
||||||
|
info_ptr = png_create_info_struct(png_ptr);
|
||||||
|
if (info_ptr == NULL){
|
||||||
|
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
|
||||||
|
cx_throw("Failed to initialize PNG info structure");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set error handling. REQUIRED if you aren't supplying your own
|
||||||
|
* error hadnling functions in the png_create_write_struct() call.
|
||||||
|
*/
|
||||||
|
if (setjmp(png_ptr->png_jmpbuf)){
|
||||||
|
/* If we get here, we had a problem reading the file */
|
||||||
|
if (info_ptr->palette) free(info_ptr->palette);
|
||||||
|
png_destroy_write_struct(&png_ptr, (png_infopp)&info_ptr);
|
||||||
|
cx_throw("Error saving PNG file");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set up the output control */
|
||||||
|
//png_init_io(png_ptr, hFile);
|
||||||
|
|
||||||
|
// use custom I/O functions
|
||||||
|
png_set_write_fn(png_ptr,hFile,/*(png_rw_ptr)*/user_write_data,/*(png_flush_ptr)*/user_flush_data);
|
||||||
|
|
||||||
|
/* set the file information here */
|
||||||
|
info_ptr->width = GetWidth();
|
||||||
|
info_ptr->height = GetHeight();
|
||||||
|
info_ptr->pixel_depth = (uint8_t)GetBpp();
|
||||||
|
info_ptr->channels = (GetBpp()>8) ? (uint8_t)3: (uint8_t)1;
|
||||||
|
info_ptr->bit_depth = (uint8_t)(GetBpp()/info_ptr->channels);
|
||||||
|
info_ptr->compression_type = info_ptr->filter_type = 0;
|
||||||
|
info_ptr->valid = 0;
|
||||||
|
|
||||||
|
// set interlace type
|
||||||
|
DWORD codec_opt = GetCodecOption(CXIMAGE_FORMAT_PNG);
|
||||||
|
if (codec_opt & CxImagePNG::ENCODE_INTERLACE)
|
||||||
|
info_ptr->interlace_type = PNG_INTERLACE_ADAM7;
|
||||||
|
else
|
||||||
|
info_ptr->interlace_type = PNG_INTERLACE_NONE;
|
||||||
|
|
||||||
|
/* set compression level */
|
||||||
|
int32_t compress_level;
|
||||||
|
switch (codec_opt & CxImagePNG::ENCODE_COMPRESSION_MASK)
|
||||||
|
{
|
||||||
|
case ENCODE_NO_COMPRESSION:
|
||||||
|
compress_level = Z_NO_COMPRESSION;
|
||||||
|
break;
|
||||||
|
case ENCODE_BEST_SPEED:
|
||||||
|
compress_level = Z_BEST_SPEED;
|
||||||
|
break;
|
||||||
|
case ENCODE_BEST_COMPRESSION:
|
||||||
|
compress_level = Z_BEST_COMPRESSION;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
compress_level = Z_DEFAULT_COMPRESSION;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
png_set_compression_level(png_ptr, compress_level);
|
||||||
|
|
||||||
|
bool bGrayScale = IsGrayScale();
|
||||||
|
|
||||||
|
if (GetNumColors()){
|
||||||
|
if (bGrayScale){
|
||||||
|
info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
|
||||||
|
} else {
|
||||||
|
info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info_ptr->color_type = PNG_COLOR_TYPE_RGB;
|
||||||
|
}
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (AlphaIsValid()){
|
||||||
|
info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
|
||||||
|
info_ptr->channels++;
|
||||||
|
info_ptr->bit_depth = 8;
|
||||||
|
info_ptr->pixel_depth += 8;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* set background */
|
||||||
|
png_color_16 image_background={ 0, 255, 255, 255, 0 };
|
||||||
|
RGBQUAD tc = GetTransColor();
|
||||||
|
if (info.nBkgndIndex>=0) {
|
||||||
|
image_background.blue = tc.rgbBlue;
|
||||||
|
image_background.green = tc.rgbGreen;
|
||||||
|
image_background.red = tc.rgbRed;
|
||||||
|
}
|
||||||
|
png_set_bKGD(png_ptr, info_ptr, &image_background);
|
||||||
|
|
||||||
|
/* set metrics */
|
||||||
|
png_set_pHYs(png_ptr, info_ptr, head.biXPelsPerMeter, head.biYPelsPerMeter, PNG_RESOLUTION_METER);
|
||||||
|
|
||||||
|
png_set_IHDR(png_ptr, info_ptr, info_ptr->width, info_ptr->height, info_ptr->bit_depth,
|
||||||
|
info_ptr->color_type, info_ptr->interlace_type,
|
||||||
|
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||||
|
|
||||||
|
//<DP> simple transparency
|
||||||
|
if (info.nBkgndIndex >= 0){
|
||||||
|
info_ptr->num_trans = 1;
|
||||||
|
info_ptr->valid |= PNG_INFO_tRNS;
|
||||||
|
info_ptr->trans_alpha = trans;
|
||||||
|
info_ptr->trans_color.index = (uint8_t)info.nBkgndIndex;
|
||||||
|
info_ptr->trans_color.red = tc.rgbRed;
|
||||||
|
info_ptr->trans_color.green = tc.rgbGreen;
|
||||||
|
info_ptr->trans_color.blue = tc.rgbBlue;
|
||||||
|
info_ptr->trans_color.gray = info_ptr->trans_color.index;
|
||||||
|
|
||||||
|
// the transparency indexes start from 0 for non grayscale palette
|
||||||
|
if (!bGrayScale && head.biClrUsed && info.nBkgndIndex)
|
||||||
|
SwapIndex(0,(uint8_t)info.nBkgndIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set the palette if there is one */
|
||||||
|
if (GetPalette()){
|
||||||
|
if (!bGrayScale){
|
||||||
|
info_ptr->valid |= PNG_INFO_PLTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t nc = GetClrImportant();
|
||||||
|
if (nc==0) nc = GetNumColors();
|
||||||
|
|
||||||
|
if (info.bAlphaPaletteEnabled){
|
||||||
|
for(uint16_t ip=0; ip<nc;ip++)
|
||||||
|
trans[ip]=GetPaletteColor((uint8_t)ip).rgbReserved;
|
||||||
|
info_ptr->num_trans = (uint16_t)nc;
|
||||||
|
info_ptr->valid |= PNG_INFO_tRNS;
|
||||||
|
info_ptr->trans_alpha = trans;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy the palette colors
|
||||||
|
info_ptr->palette = new png_color[nc];
|
||||||
|
info_ptr->num_palette = (png_uint_16) nc;
|
||||||
|
for (int32_t i=0; i<nc; i++)
|
||||||
|
GetPaletteColor(i, &info_ptr->palette[i].red, &info_ptr->palette[i].green, &info_ptr->palette[i].blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA // <vho>
|
||||||
|
//Merge the transparent color with the alpha channel
|
||||||
|
if (AlphaIsValid() && head.biBitCount==24 && info.nBkgndIndex>=0){
|
||||||
|
for(int32_t y=0; y < head.biHeight; y++){
|
||||||
|
for(int32_t x=0; x < head.biWidth ; x++){
|
||||||
|
RGBQUAD c=GetPixelColor(x,y,false);
|
||||||
|
if (*(int32_t*)&c==*(int32_t*)&tc)
|
||||||
|
AlphaSet(x,y,0);
|
||||||
|
} } }
|
||||||
|
#endif // CXIMAGE_SUPPORT_ALPHA // <vho>
|
||||||
|
|
||||||
|
int32_t row_size = max(info.dwEffWidth, info_ptr->width*info_ptr->channels*(info_ptr->bit_depth/8));
|
||||||
|
info_ptr->rowbytes = row_size;
|
||||||
|
uint8_t *row_pointers = new uint8_t[row_size];
|
||||||
|
|
||||||
|
/* write the file information */
|
||||||
|
png_write_info(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
//interlace handling
|
||||||
|
int32_t num_pass = png_set_interlace_handling(png_ptr);
|
||||||
|
for (int32_t pass = 0; pass < num_pass; pass++){
|
||||||
|
//write image
|
||||||
|
iter.Upset();
|
||||||
|
int32_t ay=head.biHeight-1;
|
||||||
|
do {
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA // <vho>
|
||||||
|
RGBQUAD c;
|
||||||
|
if (AlphaIsValid()){
|
||||||
|
for (int32_t ax=head.biWidth-1; ax>=0;ax--){
|
||||||
|
c = BlindGetPixelColor(ax,ay);
|
||||||
|
int32_t px = ax * info_ptr->channels;
|
||||||
|
if (!bGrayScale){
|
||||||
|
row_pointers[px++]=c.rgbRed;
|
||||||
|
row_pointers[px++]=c.rgbGreen;
|
||||||
|
}
|
||||||
|
row_pointers[px++]=c.rgbBlue;
|
||||||
|
row_pointers[px] = AlphaGet(ax,ay);
|
||||||
|
}
|
||||||
|
png_write_row(png_ptr, row_pointers);
|
||||||
|
ay--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA // <vho>
|
||||||
|
{
|
||||||
|
iter.GetRow(row_pointers, row_size);
|
||||||
|
if (info_ptr->color_type == PNG_COLOR_TYPE_RGB) //HACK BY OP
|
||||||
|
RGBtoBGR(row_pointers, row_size);
|
||||||
|
png_write_row(png_ptr, row_pointers);
|
||||||
|
}
|
||||||
|
} while(iter.PrevRow());
|
||||||
|
}
|
||||||
|
|
||||||
|
delete [] row_pointers;
|
||||||
|
row_pointers = NULL;
|
||||||
|
|
||||||
|
//if necessary, restore the original palette
|
||||||
|
if (!bGrayScale && head.biClrUsed && info.nBkgndIndex>0)
|
||||||
|
SwapIndex((uint8_t)info.nBkgndIndex,0);
|
||||||
|
|
||||||
|
/* It is REQUIRED to call this to finish writing the rest of the file */
|
||||||
|
png_write_end(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
/* if you malloced the palette, free it here */
|
||||||
|
if (info_ptr->palette){
|
||||||
|
delete [] (info_ptr->palette);
|
||||||
|
info_ptr->palette = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clean up after the write, and free any memory allocated */
|
||||||
|
png_destroy_write_struct(&png_ptr, (png_infopp)&info_ptr);
|
||||||
|
|
||||||
|
} cx_catch {
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
/* that's it */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_PNG
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* File: ximapng.h
|
||||||
|
* Purpose: PNG Image Class Loader and Writer
|
||||||
|
*/
|
||||||
|
/* ==========================================================
|
||||||
|
* CxImagePNG (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it
|
||||||
|
* For conditions of distribution and use, see copyright notice in ximage.h
|
||||||
|
*
|
||||||
|
* Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes
|
||||||
|
*
|
||||||
|
* original CImagePNG and CImageIterator implementation are:
|
||||||
|
* Copyright: (c) 1995, Alejandro Aguilar Sierra <asierra(at)servidor(dot)unam(dot)mx>
|
||||||
|
*
|
||||||
|
* libpng Copyright (c) 1998-2003 Glenn Randers-Pehrson
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
#if !defined(__ximaPNG_h)
|
||||||
|
#define __ximaPNG_h
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_PNG
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#ifdef _LINUX
|
||||||
|
#undef _DLL
|
||||||
|
#include <png.h>
|
||||||
|
#include <pngstruct.h>
|
||||||
|
#include <pnginfo.h>
|
||||||
|
#else
|
||||||
|
#include "../png/png.h"
|
||||||
|
#include "../png/pngstruct.h"
|
||||||
|
#include "../png/pnginfo.h"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
class CxImagePNG: public CxImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CxImagePNG(): CxImage(CXIMAGE_FORMAT_PNG) {}
|
||||||
|
|
||||||
|
// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_PNG);}
|
||||||
|
// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_PNG);}
|
||||||
|
bool Decode(CxFile * hFile);
|
||||||
|
bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
bool Encode(CxFile * hFile);
|
||||||
|
bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
|
||||||
|
enum CODEC_OPTION
|
||||||
|
{
|
||||||
|
ENCODE_INTERLACE = 0x01,
|
||||||
|
// Exclusive compression types : 3 bit wide field
|
||||||
|
ENCODE_COMPRESSION_MASK = 0x0E,
|
||||||
|
ENCODE_NO_COMPRESSION = 1 << 1,
|
||||||
|
ENCODE_BEST_SPEED = 2 << 1,
|
||||||
|
ENCODE_BEST_COMPRESSION = 3 << 1,
|
||||||
|
ENCODE_DEFAULT_COMPRESSION = 4 << 1
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void ima_png_error(png_struct *png_ptr, char *message);
|
||||||
|
void expand2to4bpp(uint8_t* prow);
|
||||||
|
|
||||||
|
static void PNGAPI user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||||
|
{
|
||||||
|
CxFile* hFile = (CxFile*)png_get_io_ptr(png_ptr);
|
||||||
|
if (hFile == NULL || hFile->Read(data,1,length) != length) png_error(png_ptr, "Read Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PNGAPI user_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||||
|
{
|
||||||
|
CxFile* hFile = (CxFile*)png_get_io_ptr(png_ptr);
|
||||||
|
if (hFile == NULL || hFile->Write(data,1,length) != length) png_error(png_ptr, "Write Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PNGAPI user_flush_data(png_structp png_ptr)
|
||||||
|
{
|
||||||
|
CxFile* hFile = (CxFile*)png_get_io_ptr(png_ptr);
|
||||||
|
if (hFile == NULL || !hFile->Flush()) png_error(png_ptr, "Flush Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PNGAPI user_error_fn(png_structp png_ptr,png_const_charp error_msg)
|
||||||
|
{
|
||||||
|
strncpy((char*)png_ptr->error_ptr,error_msg,255);
|
||||||
|
longjmp(png_ptr->png_jmpbuf, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* File: ximapsd.h
|
||||||
|
* Purpose: PSD Image Class Loader and Writer
|
||||||
|
*/
|
||||||
|
/* ==========================================================
|
||||||
|
* CxImagePSD (c) Dec/2010
|
||||||
|
* For conditions of distribution and use, see copyright notice in ximage.h
|
||||||
|
*
|
||||||
|
* libpsd (c) 2004-2007 Graphest Software
|
||||||
|
*
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
#if !defined(__ximaPSD_h)
|
||||||
|
#define __ximaPSD_h
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_PSD
|
||||||
|
|
||||||
|
#define CXIMAGE_USE_LIBPSD 1
|
||||||
|
|
||||||
|
#if CXIMAGE_USE_LIBPSD
|
||||||
|
extern "C" {
|
||||||
|
#include "../libpsd/libpsd.h"
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CxImagePSD: public CxImage
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
CxImagePSD(): CxImage(CXIMAGE_FORMAT_PSD) {}
|
||||||
|
|
||||||
|
// bool Load(const char * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_PSD);}
|
||||||
|
// bool Save(const char * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_PSD);}
|
||||||
|
bool Decode(CxFile * hFile);
|
||||||
|
bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }
|
||||||
|
|
||||||
|
//#if CXIMAGE_SUPPORT_EXIF
|
||||||
|
// bool GetExifThumbnail(const TCHAR *filename, const TCHAR *outname, int32_t type);
|
||||||
|
//#endif //CXIMAGE_SUPPORT_EXIF
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
bool Encode(CxFile * hFile);
|
||||||
|
bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
|
||||||
|
#if CXIMAGE_USE_LIBPSD
|
||||||
|
protected:
|
||||||
|
class CxFilePsd
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CxFilePsd(CxFile* pFile,psd_context *context)
|
||||||
|
{
|
||||||
|
context->file = pFile;
|
||||||
|
|
||||||
|
psd_CxFile_ops.size_ = psd_file_size;
|
||||||
|
psd_CxFile_ops.seek_ = psd_file_seek;
|
||||||
|
psd_CxFile_ops.read_ = psd_file_read;
|
||||||
|
// psd_CxFile_ops.write_ = psd_file_write;
|
||||||
|
// psd_CxFile_ops.close_ = psd_file_close;
|
||||||
|
// psd_CxFile_ops.gets_ = psd_file_gets;
|
||||||
|
// psd_CxFile_ops.eof_ = psd_file_eof;
|
||||||
|
// psd_CxFile_ops.tell_ = psd_file_tell;
|
||||||
|
// psd_CxFile_ops.getc_ = psd_file_getc;
|
||||||
|
// psd_CxFile_ops.scanf_ = psd_file_scanf;
|
||||||
|
|
||||||
|
context->ops_ = &psd_CxFile_ops;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t psd_file_size(psd_file_obj *obj)
|
||||||
|
{ return ((CxFile*)obj)->Size(); }
|
||||||
|
|
||||||
|
static int32_t psd_file_seek(psd_file_obj *obj, int32_t offset, int32_t origin)
|
||||||
|
{ return ((CxFile*)obj)->Seek(offset,origin); }
|
||||||
|
|
||||||
|
static int32_t psd_file_read(psd_file_obj *obj, void *buf, int32_t size, int32_t cnt)
|
||||||
|
{ return ((CxFile*)obj)->Read(buf,size,cnt); }
|
||||||
|
|
||||||
|
// static int32_t psd_file_write(psd_file_obj *obj, void *buf, int32_t size, int32_t cnt)
|
||||||
|
// { return ((CxFile*)obj)->Write(buf,size,cnt); }
|
||||||
|
|
||||||
|
// static int32_t psd_file_close(psd_file_obj *obj)
|
||||||
|
// { return 1; /*((CxFile*)obj)->Close();*/ }
|
||||||
|
|
||||||
|
// static char* psd_file_gets(psd_file_obj *obj, char *string, int32_t n)
|
||||||
|
// { return ((CxFile*)obj)->GetS(string,n); }
|
||||||
|
|
||||||
|
// static int32_t psd_file_eof(psd_file_obj *obj)
|
||||||
|
// { return ((CxFile*)obj)->Eof(); }
|
||||||
|
|
||||||
|
// static long psd_file_tell(psd_file_obj *obj)
|
||||||
|
// { return ((CxFile*)obj)->Tell(); }
|
||||||
|
|
||||||
|
// static int32_t psd_file_getc(psd_file_obj *obj)
|
||||||
|
// { return ((CxFile*)obj)->GetC(); }
|
||||||
|
|
||||||
|
// static int32_t psd_file_scanf(psd_file_obj *obj,const char *format, void* output)
|
||||||
|
// { return ((CxFile*)obj)->Scanf(format, output); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
psd_file_ops psd_CxFile_ops;
|
||||||
|
};
|
||||||
|
#endif //CXIMAGE_USE_LIBPSD
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,333 @@
|
|||||||
|
/*
|
||||||
|
* File: ximaraw.cpp
|
||||||
|
* Purpose: Platform Independent RAW Image Class Loader
|
||||||
|
* 16/Dec/2007 Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*
|
||||||
|
* CxImageRAW (c) May/2006 pdw63
|
||||||
|
*
|
||||||
|
* based on dcraw.c -- Dave Coffin's raw photo decoder
|
||||||
|
* Copyright 1997-2007 by Dave Coffin, dcoffin a cybercom o net
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximaraw.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_RAW
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageRAW::Decode(CxFile *hFile)
|
||||||
|
{
|
||||||
|
if (hFile==NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DCRAW dcr;
|
||||||
|
|
||||||
|
cx_try
|
||||||
|
{
|
||||||
|
// initialization
|
||||||
|
dcr_init_dcraw(&dcr);
|
||||||
|
|
||||||
|
dcr.opt.user_qual = GetCodecOption(CXIMAGE_FORMAT_RAW) & 0x03;
|
||||||
|
|
||||||
|
// setup variables for debugging
|
||||||
|
char szClass[] = "CxImageRAW";
|
||||||
|
dcr.ifname = szClass;
|
||||||
|
dcr.sz_error = info.szLastError;
|
||||||
|
|
||||||
|
// setup library options, see dcr_print_manual for the available switches
|
||||||
|
// call dcr_parse_command_line_options(&dcr,0,0,0) to set default options
|
||||||
|
// if (dcr_parse_command_line_options(&dcr,argc,argv,&arg))
|
||||||
|
if (dcr_parse_command_line_options(&dcr,0,0,0)){
|
||||||
|
cx_throw("CxImageRAW: unknown option");
|
||||||
|
}
|
||||||
|
|
||||||
|
// set return point for error handling
|
||||||
|
if (setjmp (dcr.failure)) {
|
||||||
|
cx_throw("");
|
||||||
|
}
|
||||||
|
|
||||||
|
// install file manager
|
||||||
|
CxFileRaw src(hFile,&dcr);
|
||||||
|
|
||||||
|
// check file header
|
||||||
|
dcr_identify(&dcr);
|
||||||
|
|
||||||
|
if(!dcr.is_raw){
|
||||||
|
cx_throw("CxImageRAW: not a raw image");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dcr.load_raw == NULL) {
|
||||||
|
cx_throw("CxImageRAW: missing raw decoder");
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify special case
|
||||||
|
if (dcr.load_raw == dcr_kodak_ycbcr_load_raw) {
|
||||||
|
dcr.height += dcr.height & 1;
|
||||||
|
dcr.width += dcr.width & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.nEscape == -1){
|
||||||
|
head.biWidth = dcr.width;
|
||||||
|
head.biHeight= dcr.height;
|
||||||
|
info.dwType = CXIMAGE_FORMAT_RAW;
|
||||||
|
cx_throw("output dimensions returned");
|
||||||
|
}
|
||||||
|
|
||||||
|
// shrinked decoding available and requested?
|
||||||
|
dcr.shrink = dcr.filters && (dcr.opt.half_size || dcr.opt.threshold || dcr.opt.aber[0] != 1 || dcr.opt.aber[2] != 1);
|
||||||
|
dcr.iheight = (dcr.height + dcr.shrink) >> dcr.shrink;
|
||||||
|
dcr.iwidth = (dcr.width + dcr.shrink) >> dcr.shrink;
|
||||||
|
|
||||||
|
// install custom camera matrix
|
||||||
|
if (dcr.opt.use_camera_matrix && dcr.cmatrix[0][0] > 0.25) {
|
||||||
|
memcpy (dcr.rgb_cam, dcr.cmatrix, sizeof dcr.cmatrix);
|
||||||
|
dcr.raw_color = 0;
|
||||||
|
} else {
|
||||||
|
dcr.opt.use_camera_wb = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate memory for the image
|
||||||
|
dcr.image = (ushort (*)[4]) calloc (dcr.iheight*dcr.iwidth, sizeof *dcr.image);
|
||||||
|
dcr_merror (&dcr, dcr.image, szClass);
|
||||||
|
|
||||||
|
if (dcr.meta_length) {
|
||||||
|
dcr.meta_data = (char *) malloc (dcr.meta_length);
|
||||||
|
dcr_merror (&dcr, dcr.meta_data, szClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
// start image decoder
|
||||||
|
hFile->Seek(dcr.data_offset, SEEK_SET);
|
||||||
|
(*dcr.load_raw)(&dcr);
|
||||||
|
|
||||||
|
// post processing
|
||||||
|
if (dcr.zero_is_bad) dcr_remove_zeroes(&dcr);
|
||||||
|
|
||||||
|
dcr_bad_pixels(&dcr,dcr.opt.bpfile);
|
||||||
|
|
||||||
|
if (dcr.opt.dark_frame) dcr_subtract (&dcr,dcr.opt.dark_frame);
|
||||||
|
|
||||||
|
dcr.quality = 2 + !dcr.fuji_width;
|
||||||
|
|
||||||
|
if (dcr.opt.user_qual >= 0) dcr.quality = dcr.opt.user_qual;
|
||||||
|
|
||||||
|
if (dcr.opt.user_black >= 0) dcr.black = dcr.opt.user_black;
|
||||||
|
|
||||||
|
if (dcr.opt.user_sat >= 0) dcr.maximum = dcr.opt.user_sat;
|
||||||
|
|
||||||
|
#ifdef COLORCHECK
|
||||||
|
dcr_colorcheck(&dcr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RESTRICTED
|
||||||
|
if (dcr.is_foveon && !dcr.opt.document_mode) dcr_foveon_interpolate(&dcr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!dcr.is_foveon && dcr.opt.document_mode < 2) dcr_scale_colors(&dcr);
|
||||||
|
|
||||||
|
// pixel interpolation and filters
|
||||||
|
dcr_pre_interpolate(&dcr);
|
||||||
|
|
||||||
|
if (dcr.filters && !dcr.opt.document_mode) {
|
||||||
|
if (dcr.quality == 0)
|
||||||
|
dcr_lin_interpolate(&dcr);
|
||||||
|
else if (dcr.quality == 1 || dcr.colors > 3)
|
||||||
|
dcr_vng_interpolate(&dcr);
|
||||||
|
else if (dcr.quality == 2)
|
||||||
|
dcr_ppg_interpolate(&dcr);
|
||||||
|
else
|
||||||
|
dcr_ahd_interpolate(&dcr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dcr.mix_green) {
|
||||||
|
int32_t i;
|
||||||
|
for (dcr.colors=3, i=0; i < dcr.height*dcr.width; i++) {
|
||||||
|
dcr.image[i][1] = (dcr.image[i][1] + dcr.image[i][3]) >> 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dcr.is_foveon && dcr.colors == 3) dcr_median_filter(&dcr);
|
||||||
|
|
||||||
|
if (!dcr.is_foveon && dcr.opt.highlight == 2) dcr_blend_highlights(&dcr);
|
||||||
|
|
||||||
|
if (!dcr.is_foveon && dcr.opt.highlight > 2) dcr_recover_highlights(&dcr);
|
||||||
|
|
||||||
|
if (dcr.opt.use_fuji_rotate) dcr_fuji_rotate(&dcr);
|
||||||
|
|
||||||
|
#ifndef NO_LCMS
|
||||||
|
if (dcr.opt.cam_profile) dcr_apply_profile (dcr.opt.cam_profile, dcr.opt.out_profile);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// final conversion
|
||||||
|
dcr_convert_to_rgb(&dcr);
|
||||||
|
|
||||||
|
if (dcr.opt.use_fuji_rotate) dcr_stretch(&dcr);
|
||||||
|
|
||||||
|
dcr.iheight = dcr.height;
|
||||||
|
dcr.iwidth = dcr.width;
|
||||||
|
if (dcr.flip & 4) SWAP(dcr.height,dcr.width);
|
||||||
|
|
||||||
|
// ready to transfer data from dcr.image
|
||||||
|
if (!Create(dcr.width,dcr.height,24,CXIMAGE_FORMAT_RAW)){
|
||||||
|
cx_throw("");
|
||||||
|
}
|
||||||
|
|
||||||
|
uchar *ppm = (uchar *) calloc (dcr.width, dcr.colors*dcr.opt.output_bps/8);
|
||||||
|
ushort *ppm2 = (ushort *) ppm;
|
||||||
|
dcr_merror (&dcr, ppm, szClass);
|
||||||
|
|
||||||
|
uchar lut[0x10000];
|
||||||
|
if (dcr.opt.output_bps == 8) dcr_gamma_lut (&dcr, lut);
|
||||||
|
|
||||||
|
int32_t c, row, col, soff, rstep, cstep;
|
||||||
|
soff = dcr_flip_index (&dcr, 0, 0);
|
||||||
|
cstep = dcr_flip_index (&dcr, 0, 1) - soff;
|
||||||
|
rstep = dcr_flip_index (&dcr, 1, 0) - dcr_flip_index (&dcr, 0, dcr.width);
|
||||||
|
for (row=0; row < dcr.height; row++, soff += rstep) {
|
||||||
|
for (col=0; col < dcr.width; col++, soff += cstep) {
|
||||||
|
if (dcr.opt.output_bps == 8)
|
||||||
|
for (c=0; c < dcr.colors; c++) ppm [col*dcr.colors+c] = lut[dcr.image[soff][c]];
|
||||||
|
else
|
||||||
|
for (c=0; c < dcr.colors; c++) ppm2[col*dcr.colors+c] = dcr.image[soff][c];
|
||||||
|
}
|
||||||
|
if (dcr.opt.output_bps == 16 && !dcr.opt.output_tiff && htons(0x55aa) != 0x55aa)
|
||||||
|
#if defined(_LINUX) || defined(__APPLE__)
|
||||||
|
swab ((char*)ppm2, (char*)ppm2, dcr.width*dcr.colors*2);
|
||||||
|
#else
|
||||||
|
_swab ((char*)ppm2, (char*)ppm2, dcr.width*dcr.colors*2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t size = dcr.width * (dcr.colors*dcr.opt.output_bps/8);
|
||||||
|
RGBtoBGR(ppm,size);
|
||||||
|
memcpy(GetBits(dcr.height - 1 - row), ppm, min(size,GetEffWidth()));
|
||||||
|
}
|
||||||
|
free (ppm);
|
||||||
|
|
||||||
|
|
||||||
|
dcr_cleanup_dcraw(&dcr);
|
||||||
|
|
||||||
|
} cx_catch {
|
||||||
|
|
||||||
|
dcr_cleanup_dcraw(&dcr);
|
||||||
|
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_RAW) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* that's it */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_EXIF
|
||||||
|
bool CxImageRAW::GetExifThumbnail(const TCHAR *filename, const TCHAR *outname, int32_t type)
|
||||||
|
{
|
||||||
|
DCRAW dcr;
|
||||||
|
|
||||||
|
CxIOFile file;
|
||||||
|
if (!file.Open(filename, _T("rb")))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
cx_try
|
||||||
|
{
|
||||||
|
// initialization
|
||||||
|
dcr_init_dcraw(&dcr);
|
||||||
|
|
||||||
|
dcr.opt.user_qual = GetCodecOption(CXIMAGE_FORMAT_RAW) & 0x03;
|
||||||
|
|
||||||
|
// setup variables for debugging
|
||||||
|
char szClass[] = "CxImageRAW";
|
||||||
|
dcr.ifname = szClass;
|
||||||
|
dcr.sz_error = info.szLastError;
|
||||||
|
|
||||||
|
// setup library options, see dcr_print_manual for the available switches
|
||||||
|
// call dcr_parse_command_line_options(&dcr,0,0,0) to set default options
|
||||||
|
// if (dcr_parse_command_line_options(&dcr,argc,argv,&arg))
|
||||||
|
if (dcr_parse_command_line_options(&dcr,0,0,0)){
|
||||||
|
cx_throw("CxImageRAW: unknown option");
|
||||||
|
}
|
||||||
|
|
||||||
|
// set return point for error handling
|
||||||
|
if (setjmp (dcr.failure)) {
|
||||||
|
cx_throw("");
|
||||||
|
}
|
||||||
|
|
||||||
|
// install file manager
|
||||||
|
CxFileRaw src(&file,&dcr);
|
||||||
|
|
||||||
|
// check file header
|
||||||
|
dcr_identify(&dcr);
|
||||||
|
|
||||||
|
if(!dcr.is_raw){
|
||||||
|
cx_throw("CxImageRAW: not a raw image");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dcr.load_raw == NULL) {
|
||||||
|
cx_throw("CxImageRAW: missing raw decoder");
|
||||||
|
}
|
||||||
|
|
||||||
|
// THUMB.
|
||||||
|
if (dcr.thumb_offset != 0)
|
||||||
|
{
|
||||||
|
FILE* file = _tfopen(outname, _T("wb"));
|
||||||
|
DCRAW* p = &dcr;
|
||||||
|
dcr_fseek(dcr.obj_, dcr.thumb_offset, SEEK_SET);
|
||||||
|
dcr.write_thumb(&dcr, file);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
// Read in the thumbnail to resize and rotate.
|
||||||
|
CxImage image(outname, CXIMAGE_FORMAT_UNKNOWN);
|
||||||
|
if (image.IsValid())
|
||||||
|
{
|
||||||
|
#if CXIMAGE_SUPPORT_TRANSFORMATION
|
||||||
|
// Resizing.
|
||||||
|
if (image.GetWidth() > 256 || image.GetHeight() > 256)
|
||||||
|
{
|
||||||
|
float amount = 256.0f / max(image.GetWidth(), image.GetHeight());
|
||||||
|
image.Resample((int32_t)(image.GetWidth() * amount), (int32_t)(image.GetHeight() * amount), 0);
|
||||||
|
}
|
||||||
|
// Rotation.
|
||||||
|
if (p->flip != 0)
|
||||||
|
image.RotateExif(p->flip);
|
||||||
|
#endif
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE && CXIMAGE_SUPPORT_JPG
|
||||||
|
return image.Save(outname, CXIMAGE_FORMAT_JPG);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cx_throw("No thumbnail!");
|
||||||
|
}
|
||||||
|
|
||||||
|
dcr_cleanup_dcraw(&dcr);
|
||||||
|
|
||||||
|
} cx_catch {
|
||||||
|
|
||||||
|
dcr_cleanup_dcraw(&dcr);
|
||||||
|
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_RAW) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* that's it */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif //CXIMAGE_SUPPORT_EXIF
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageRAW::Encode(CxFile * hFile)
|
||||||
|
{
|
||||||
|
if (hFile == NULL) return false;
|
||||||
|
strcpy(info.szLastError, "Save RAW not supported");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_RAW
|
||||||
|
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* File: ximaraw.h
|
||||||
|
* Purpose: RAW Image Class Loader and Writer
|
||||||
|
*/
|
||||||
|
/* ==========================================================
|
||||||
|
* CxImageRAW (c) May/2006 pdw63
|
||||||
|
* For conditions of distribution and use, see copyright notice in ximage.h
|
||||||
|
* Special thanks to David Coffin for dcraw without which this class would not exist
|
||||||
|
*
|
||||||
|
* libdcr (c) Dec/2007 Davide Pizzolato - www.xdp.it
|
||||||
|
*
|
||||||
|
* based on dcraw.c -- Dave Coffin's raw photo decoder
|
||||||
|
* Copyright 1997-2007 by Dave Coffin, dcoffin a cybercom o net
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
#if !defined(__ximaRAW_h)
|
||||||
|
#define __ximaRAW_h
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_RAW
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "../raw/libdcr.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
class CxImageRAW: public CxImage
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
CxImageRAW(): CxImage(CXIMAGE_FORMAT_RAW) {}
|
||||||
|
|
||||||
|
// bool Load(const char * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_ICO);}
|
||||||
|
// bool Save(const char * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_ICO);}
|
||||||
|
bool Decode(CxFile * hFile);
|
||||||
|
bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_EXIF
|
||||||
|
bool GetExifThumbnail(const TCHAR *filename, const TCHAR *outname, int32_t type);
|
||||||
|
#endif //CXIMAGE_SUPPORT_EXIF
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
bool Encode(CxFile * hFile);
|
||||||
|
bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
|
||||||
|
enum CODEC_OPTION
|
||||||
|
{
|
||||||
|
DECODE_QUALITY_LIN = 0x00,
|
||||||
|
DECODE_QUALITY_VNG = 0x01,
|
||||||
|
DECODE_QUALITY_PPG = 0x02,
|
||||||
|
DECODE_QUALITY_AHD = 0x03,
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
class CxFileRaw
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CxFileRaw(CxFile* pFile,DCRAW *stream)
|
||||||
|
{
|
||||||
|
stream->obj_ = pFile;
|
||||||
|
|
||||||
|
ras_stream_CxFile.read_ = raw_sfile_read;
|
||||||
|
ras_stream_CxFile.write_ = raw_sfile_write;
|
||||||
|
ras_stream_CxFile.seek_ = raw_sfile_seek;
|
||||||
|
ras_stream_CxFile.close_ = raw_sfile_close;
|
||||||
|
ras_stream_CxFile.gets_ = raw_sfile_gets;
|
||||||
|
ras_stream_CxFile.eof_ = raw_sfile_eof;
|
||||||
|
ras_stream_CxFile.tell_ = raw_sfile_tell;
|
||||||
|
ras_stream_CxFile.getc_ = raw_sfile_getc;
|
||||||
|
ras_stream_CxFile.scanf_ = raw_sfile_scanf;
|
||||||
|
|
||||||
|
stream->ops_ = &ras_stream_CxFile;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t raw_sfile_read(dcr_stream_obj *obj, void *buf, int32_t size, int32_t cnt)
|
||||||
|
{ return ((CxFile*)obj)->Read(buf,size,cnt); }
|
||||||
|
|
||||||
|
static int32_t raw_sfile_write(dcr_stream_obj *obj, void *buf, int32_t size, int32_t cnt)
|
||||||
|
{ return ((CxFile*)obj)->Write(buf,size,cnt); }
|
||||||
|
|
||||||
|
static long raw_sfile_seek(dcr_stream_obj *obj, long offset, int32_t origin)
|
||||||
|
{ return ((CxFile*)obj)->Seek(offset,origin); }
|
||||||
|
|
||||||
|
static int32_t raw_sfile_close(dcr_stream_obj *obj)
|
||||||
|
{ return 1; /*((CxFile*)obj)->Close();*/ }
|
||||||
|
|
||||||
|
static char* raw_sfile_gets(dcr_stream_obj *obj, char *string, int32_t n)
|
||||||
|
{ return ((CxFile*)obj)->GetS(string,n); }
|
||||||
|
|
||||||
|
static int32_t raw_sfile_eof(dcr_stream_obj *obj)
|
||||||
|
{ return ((CxFile*)obj)->Eof(); }
|
||||||
|
|
||||||
|
static long raw_sfile_tell(dcr_stream_obj *obj)
|
||||||
|
{ return ((CxFile*)obj)->Tell(); }
|
||||||
|
|
||||||
|
static int32_t raw_sfile_getc(dcr_stream_obj *obj)
|
||||||
|
{ return ((CxFile*)obj)->GetC(); }
|
||||||
|
|
||||||
|
static int32_t raw_sfile_scanf(dcr_stream_obj *obj,const char *format, void* output)
|
||||||
|
{ return ((CxFile*)obj)->Scanf(format, output); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
dcr_stream_ops ras_stream_CxFile;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,698 @@
|
|||||||
|
// xImaSel.cpp : Selection functions
|
||||||
|
/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Checks if the image has a valid selection.
|
||||||
|
*/
|
||||||
|
bool CxImage::SelectionIsValid()
|
||||||
|
{
|
||||||
|
return pSelection!=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_SELECTION
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Gets the smallest rectangle that contains the selection
|
||||||
|
*/
|
||||||
|
void CxImage::SelectionGetBox(RECT& r)
|
||||||
|
{
|
||||||
|
memcpy(&r,&info.rSelectionBox,sizeof(RECT));
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Empties the selection.
|
||||||
|
*/
|
||||||
|
bool CxImage::SelectionClear(uint8_t level)
|
||||||
|
{
|
||||||
|
if (pSelection){
|
||||||
|
if (level==0){
|
||||||
|
memset(pSelection,0,head.biWidth * head.biHeight);
|
||||||
|
info.rSelectionBox.left = head.biWidth;
|
||||||
|
info.rSelectionBox.bottom = head.biHeight;
|
||||||
|
info.rSelectionBox.right = info.rSelectionBox.top = 0;
|
||||||
|
} else {
|
||||||
|
memset(pSelection,level,head.biWidth * head.biHeight);
|
||||||
|
info.rSelectionBox.right = head.biWidth;
|
||||||
|
info.rSelectionBox.top = head.biHeight;
|
||||||
|
info.rSelectionBox.left = info.rSelectionBox.bottom = 0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Allocates an empty selection.
|
||||||
|
*/
|
||||||
|
bool CxImage::SelectionCreate()
|
||||||
|
{
|
||||||
|
SelectionDelete();
|
||||||
|
pSelection = (uint8_t*)calloc(head.biWidth * head.biHeight, 1);
|
||||||
|
return (pSelection!=0);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Deallocates the selction.
|
||||||
|
*/
|
||||||
|
bool CxImage::SelectionDelete()
|
||||||
|
{
|
||||||
|
if (pSelection){
|
||||||
|
free(pSelection);
|
||||||
|
pSelection=NULL;
|
||||||
|
}
|
||||||
|
info.rSelectionBox.left = head.biWidth;
|
||||||
|
info.rSelectionBox.bottom = head.biHeight;
|
||||||
|
info.rSelectionBox.right = info.rSelectionBox.top = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Checks if the coordinates are inside the selection.
|
||||||
|
*/
|
||||||
|
bool CxImage::SelectionIsInside(int32_t x, int32_t y)
|
||||||
|
{
|
||||||
|
if (IsInside(x,y)){
|
||||||
|
if (pSelection==NULL) return true;
|
||||||
|
return pSelection[x+y*head.biWidth]!=0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Checks if the coordinates are inside the selection.
|
||||||
|
* "blind" version assumes that (x,y) is inside to the image.
|
||||||
|
*/
|
||||||
|
bool CxImage::BlindSelectionIsInside(int32_t x, int32_t y)
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
if (!IsInside(x,y))
|
||||||
|
#if CXIMAGE_SUPPORT_EXCEPTION_HANDLING
|
||||||
|
throw 0;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
if (pSelection==NULL) return true;
|
||||||
|
return pSelection[x+y*head.biWidth]!=0;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Adds a rectangle to the existing selection.
|
||||||
|
*/
|
||||||
|
bool CxImage::SelectionAddRect(RECT r, uint8_t level)
|
||||||
|
{
|
||||||
|
if (pSelection==NULL) SelectionCreate();
|
||||||
|
if (pSelection==NULL) return false;
|
||||||
|
|
||||||
|
RECT r2;
|
||||||
|
if (r.left<r.right) {r2.left=r.left; r2.right=r.right; } else {r2.left=r.right ; r2.right=r.left; }
|
||||||
|
if (r.bottom<r.top) {r2.bottom=r.bottom; r2.top=r.top; } else {r2.bottom=r.top ; r2.top=r.bottom; }
|
||||||
|
|
||||||
|
if (info.rSelectionBox.top <= r2.top) info.rSelectionBox.top = max(0L,min(head.biHeight,r2.top+1));
|
||||||
|
if (info.rSelectionBox.left > r2.left) info.rSelectionBox.left = max(0L,min(head.biWidth,r2.left));
|
||||||
|
if (info.rSelectionBox.right <= r2.right) info.rSelectionBox.right = max(0L,min(head.biWidth,r2.right+1));
|
||||||
|
if (info.rSelectionBox.bottom > r2.bottom) info.rSelectionBox.bottom = max(0L,min(head.biHeight,r2.bottom));
|
||||||
|
|
||||||
|
int32_t ymin = max(0L,min(head.biHeight,r2.bottom));
|
||||||
|
int32_t ymax = max(0L,min(head.biHeight,r2.top+1));
|
||||||
|
int32_t xmin = max(0L,min(head.biWidth,r2.left));
|
||||||
|
int32_t xmax = max(0L,min(head.biWidth,r2.right+1));
|
||||||
|
|
||||||
|
for (int32_t y=ymin; y<ymax; y++)
|
||||||
|
memset(pSelection + xmin + y * head.biWidth, level, xmax-xmin);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Adds an ellipse to the existing selection.
|
||||||
|
*/
|
||||||
|
bool CxImage::SelectionAddEllipse(RECT r, uint8_t level)
|
||||||
|
{
|
||||||
|
if (pSelection==NULL) SelectionCreate();
|
||||||
|
if (pSelection==NULL) return false;
|
||||||
|
|
||||||
|
int32_t xradius = abs(r.right - r.left)/2;
|
||||||
|
int32_t yradius = abs(r.top - r.bottom)/2;
|
||||||
|
if (xradius==0 || yradius==0) return false;
|
||||||
|
|
||||||
|
int32_t xcenter = (r.right + r.left)/2;
|
||||||
|
int32_t ycenter = (r.top + r.bottom)/2;
|
||||||
|
|
||||||
|
if (info.rSelectionBox.left > (xcenter - xradius)) info.rSelectionBox.left = max(0L,min(head.biWidth,(xcenter - xradius)));
|
||||||
|
if (info.rSelectionBox.right <= (xcenter + xradius)) info.rSelectionBox.right = max(0L,min(head.biWidth,(xcenter + xradius + 1)));
|
||||||
|
if (info.rSelectionBox.bottom > (ycenter - yradius)) info.rSelectionBox.bottom = max(0L,min(head.biHeight,(ycenter - yradius)));
|
||||||
|
if (info.rSelectionBox.top <= (ycenter + yradius)) info.rSelectionBox.top = max(0L,min(head.biHeight,(ycenter + yradius + 1)));
|
||||||
|
|
||||||
|
int32_t xmin = max(0L,min(head.biWidth,xcenter - xradius));
|
||||||
|
int32_t xmax = max(0L,min(head.biWidth,xcenter + xradius + 1));
|
||||||
|
int32_t ymin = max(0L,min(head.biHeight,ycenter - yradius));
|
||||||
|
int32_t ymax = max(0L,min(head.biHeight,ycenter + yradius + 1));
|
||||||
|
|
||||||
|
int32_t y,yo;
|
||||||
|
for (y=ymin; y<min(ycenter,ymax); y++){
|
||||||
|
for (int32_t x=xmin; x<xmax; x++){
|
||||||
|
yo = (int32_t)(ycenter - yradius * sqrt(1-pow((float)(x - xcenter)/(float)xradius,2)));
|
||||||
|
if (yo<y) pSelection[x + y * head.biWidth] = level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (y=ycenter; y<ymax; y++){
|
||||||
|
for (int32_t x=xmin; x<xmax; x++){
|
||||||
|
yo = (int32_t)(ycenter + yradius * sqrt(1-pow((float)(x - xcenter)/(float)xradius,2)));
|
||||||
|
if (yo>y) pSelection[x + y * head.biWidth] = level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Inverts the selection.
|
||||||
|
* Note: the SelectionBox is set to "full image", call SelectionGetBox before (if necessary)
|
||||||
|
*/
|
||||||
|
bool CxImage::SelectionInvert()
|
||||||
|
{
|
||||||
|
if (pSelection) {
|
||||||
|
uint8_t *iSrc=pSelection;
|
||||||
|
int32_t n=head.biHeight*head.biWidth;
|
||||||
|
for(int32_t i=0; i < n; i++){
|
||||||
|
*iSrc=(uint8_t)~(*(iSrc));
|
||||||
|
iSrc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectionRebuildBox();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Imports an existing region from another image with the same width and height.
|
||||||
|
*/
|
||||||
|
bool CxImage::SelectionCopy(CxImage &from)
|
||||||
|
{
|
||||||
|
if (from.pSelection == NULL || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight) return false;
|
||||||
|
if (pSelection==NULL) pSelection = (uint8_t*)malloc(head.biWidth * head.biHeight);
|
||||||
|
if (pSelection==NULL) return false;
|
||||||
|
memcpy(pSelection,from.pSelection,head.biWidth * head.biHeight);
|
||||||
|
memcpy(&info.rSelectionBox,&from.info.rSelectionBox,sizeof(RECT));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Adds a polygonal region to the existing selection. points points to an array of POINT structures.
|
||||||
|
* Each structure specifies the x-coordinate and y-coordinate of one vertex of the polygon.
|
||||||
|
* npoints specifies the number of POINT structures in the array pointed to by points.
|
||||||
|
*/
|
||||||
|
bool CxImage::SelectionAddPolygon(POINT *points, int32_t npoints, uint8_t level)
|
||||||
|
{
|
||||||
|
if (points==NULL || npoints<3) return false;
|
||||||
|
|
||||||
|
if (pSelection==NULL) SelectionCreate();
|
||||||
|
if (pSelection==NULL) return false;
|
||||||
|
|
||||||
|
uint8_t* plocal = (uint8_t*)calloc(head.biWidth*head.biHeight, 1);
|
||||||
|
RECT localbox = {head.biWidth,0,0,head.biHeight};
|
||||||
|
|
||||||
|
int32_t x,y,i=0;
|
||||||
|
POINT *current;
|
||||||
|
POINT *next = NULL;
|
||||||
|
POINT *start = NULL;
|
||||||
|
//trace contour
|
||||||
|
while (i < npoints){
|
||||||
|
current = &points[i];
|
||||||
|
if (current->x!=-1){
|
||||||
|
if (i==0 || (i>0 && points[i-1].x==-1)) start = &points[i];
|
||||||
|
|
||||||
|
if ((i+1)==npoints || points[i+1].x==-1)
|
||||||
|
next = start;
|
||||||
|
else
|
||||||
|
next = &points[i+1];
|
||||||
|
|
||||||
|
float beta;
|
||||||
|
if (current->x != next->x){
|
||||||
|
beta = (float)(next->y - current->y)/(float)(next->x - current->x);
|
||||||
|
if (current->x < next->x){
|
||||||
|
for (x=current->x; x<=next->x; x++){
|
||||||
|
y = (int32_t)(current->y + (x - current->x) * beta);
|
||||||
|
if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (x=current->x; x>=next->x; x--){
|
||||||
|
y = (int32_t)(current->y + (x - current->x) * beta);
|
||||||
|
if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (current->y != next->y){
|
||||||
|
beta = (float)(next->x - current->x)/(float)(next->y - current->y);
|
||||||
|
if (current->y < next->y){
|
||||||
|
for (y=current->y; y<=next->y; y++){
|
||||||
|
x = (int32_t)(current->x + (y - current->y) * beta);
|
||||||
|
if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (y=current->y; y>=next->y; y--){
|
||||||
|
x = (int32_t)(current->x + (y - current->y) * beta);
|
||||||
|
if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RECT r2;
|
||||||
|
if (current->x < next->x) {r2.left=current->x; r2.right=next->x; } else {r2.left=next->x ; r2.right=current->x; }
|
||||||
|
if (current->y < next->y) {r2.bottom=current->y; r2.top=next->y; } else {r2.bottom=next->y ; r2.top=current->y; }
|
||||||
|
if (localbox.top < r2.top) localbox.top = max(0L,min(head.biHeight-1,r2.top+1));
|
||||||
|
if (localbox.left > r2.left) localbox.left = max(0L,min(head.biWidth-1,r2.left-1));
|
||||||
|
if (localbox.right < r2.right) localbox.right = max(0L,min(head.biWidth-1,r2.right+1));
|
||||||
|
if (localbox.bottom > r2.bottom) localbox.bottom = max(0L,min(head.biHeight-1,r2.bottom-1));
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//fill the outer region
|
||||||
|
int32_t npix=(localbox.right - localbox.left)*(localbox.top - localbox.bottom);
|
||||||
|
POINT* pix = (POINT*)calloc(npix,sizeof(POINT));
|
||||||
|
uint8_t back=0, mark=1;
|
||||||
|
int32_t fx, fy, fxx, fyy, first, last;
|
||||||
|
int32_t xmin = 0;
|
||||||
|
int32_t xmax = 0;
|
||||||
|
int32_t ymin = 0;
|
||||||
|
int32_t ymax = 0;
|
||||||
|
|
||||||
|
for (int32_t side=0; side<4; side++){
|
||||||
|
switch(side){
|
||||||
|
case 0:
|
||||||
|
xmin=localbox.left; xmax=localbox.right+1; ymin=localbox.bottom; ymax=localbox.bottom+1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
xmin=localbox.right; xmax=localbox.right+1; ymin=localbox.bottom; ymax=localbox.top+1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
xmin=localbox.left; xmax=localbox.right+1; ymin=localbox.top; ymax=localbox.top+1;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
xmin=localbox.left; xmax=localbox.left+1; ymin=localbox.bottom; ymax=localbox.top+1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//fill from the border points
|
||||||
|
for(y=ymin;y<ymax;y++){
|
||||||
|
for(x=xmin;x<xmax;x++){
|
||||||
|
if (plocal[x+y*head.biWidth]==0){
|
||||||
|
// Subject: FLOOD FILL ROUTINE Date: 12-23-97 (00:57)
|
||||||
|
// Author: Petter Holmberg Code: QB, QBasic, PDS
|
||||||
|
// Origin: petter.holmberg@usa.net Packet: GRAPHICS.ABC
|
||||||
|
first=0;
|
||||||
|
last=1;
|
||||||
|
while(first!=last){
|
||||||
|
fx = pix[first].x;
|
||||||
|
fy = pix[first].y;
|
||||||
|
fxx = fx + x;
|
||||||
|
fyy = fy + y;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
if ((plocal[fxx + fyy*head.biWidth] == back) &&
|
||||||
|
fxx>=localbox.left && fxx<=localbox.right && fyy>=localbox.bottom && fyy<=localbox.top )
|
||||||
|
{
|
||||||
|
plocal[fxx + fyy*head.biWidth] = mark;
|
||||||
|
if (fyy > 0 && plocal[fxx + (fyy - 1)*head.biWidth] == back){
|
||||||
|
pix[last].x = fx;
|
||||||
|
pix[last].y = fy - 1;
|
||||||
|
last++;
|
||||||
|
if (last == npix) last = 0;
|
||||||
|
}
|
||||||
|
if ((fyy + 1)<head.biHeight && plocal[fxx + (fyy + 1)*head.biWidth] == back){
|
||||||
|
pix[last].x = fx;
|
||||||
|
pix[last].y = fy + 1;
|
||||||
|
last++;
|
||||||
|
if (last == npix) last = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fx++;
|
||||||
|
fxx++;
|
||||||
|
};
|
||||||
|
|
||||||
|
fx = pix[first].x - 1;
|
||||||
|
fy = pix[first].y;
|
||||||
|
fxx = fx + x;
|
||||||
|
fyy = fy + y;
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
if ((plocal[fxx + fyy*head.biWidth] == back) &&
|
||||||
|
fxx>=localbox.left && fxx<=localbox.right && fyy>=localbox.bottom && fyy<=localbox.top )
|
||||||
|
{
|
||||||
|
plocal[fxx + (y + fy)*head.biWidth] = mark;
|
||||||
|
if (fyy > 0 && plocal[fxx + (fyy - 1)*head.biWidth] == back){
|
||||||
|
pix[last].x = fx;
|
||||||
|
pix[last].y = fy - 1;
|
||||||
|
last++;
|
||||||
|
if (last == npix) last = 0;
|
||||||
|
}
|
||||||
|
if ((fyy + 1)<head.biHeight && plocal[fxx + (fyy + 1)*head.biWidth] == back){
|
||||||
|
pix[last].x = fx;
|
||||||
|
pix[last].y = fy + 1;
|
||||||
|
last++;
|
||||||
|
if (last == npix) last = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fx--;
|
||||||
|
fxx--;
|
||||||
|
}
|
||||||
|
|
||||||
|
first++;
|
||||||
|
if (first == npix) first = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//transfer the region
|
||||||
|
int32_t yoffset;
|
||||||
|
for (y=localbox.bottom; y<=localbox.top; y++){
|
||||||
|
yoffset = y * head.biWidth;
|
||||||
|
for (x=localbox.left; x<=localbox.right; x++)
|
||||||
|
if (plocal[x + yoffset]!=1) pSelection[x + yoffset]=level;
|
||||||
|
}
|
||||||
|
if (info.rSelectionBox.top <= localbox.top) info.rSelectionBox.top = min(head.biHeight,localbox.top + 1);
|
||||||
|
if (info.rSelectionBox.left > localbox.left) info.rSelectionBox.left = min(head.biWidth,localbox.left);
|
||||||
|
if (info.rSelectionBox.right <= localbox.right) info.rSelectionBox.right = min(head.biWidth,localbox.right + 1);
|
||||||
|
if (info.rSelectionBox.bottom > localbox.bottom) info.rSelectionBox.bottom = min(head.biHeight,localbox.bottom);
|
||||||
|
|
||||||
|
free(plocal);
|
||||||
|
free(pix);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Adds to the selection all the pixels matching the specified color.
|
||||||
|
*/
|
||||||
|
bool CxImage::SelectionAddColor(RGBQUAD c, uint8_t level)
|
||||||
|
{
|
||||||
|
if (pSelection==NULL) SelectionCreate();
|
||||||
|
if (pSelection==NULL) return false;
|
||||||
|
|
||||||
|
RECT localbox = {head.biWidth,0,0,head.biHeight};
|
||||||
|
|
||||||
|
for (int32_t y = 0; y < head.biHeight; y++){
|
||||||
|
for (int32_t x = 0; x < head.biWidth; x++){
|
||||||
|
RGBQUAD color = BlindGetPixelColor(x, y);
|
||||||
|
if (color.rgbRed == c.rgbRed &&
|
||||||
|
color.rgbGreen == c.rgbGreen &&
|
||||||
|
color.rgbBlue == c.rgbBlue)
|
||||||
|
{
|
||||||
|
pSelection[x + y * head.biWidth] = level;
|
||||||
|
|
||||||
|
if (localbox.top < y) localbox.top = y;
|
||||||
|
if (localbox.left > x) localbox.left = x;
|
||||||
|
if (localbox.right < x) localbox.right = x;
|
||||||
|
if (localbox.bottom > y) localbox.bottom = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.rSelectionBox.top <= localbox.top) info.rSelectionBox.top = localbox.top + 1;
|
||||||
|
if (info.rSelectionBox.left > localbox.left) info.rSelectionBox.left = localbox.left;
|
||||||
|
if (info.rSelectionBox.right <= localbox.right) info.rSelectionBox.right = localbox.right + 1;
|
||||||
|
if (info.rSelectionBox.bottom > localbox.bottom) info.rSelectionBox.bottom = localbox.bottom;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Adds a single pixel to the existing selection.
|
||||||
|
*/
|
||||||
|
bool CxImage::SelectionAddPixel(int32_t x, int32_t y, uint8_t level)
|
||||||
|
{
|
||||||
|
if (pSelection==NULL) SelectionCreate();
|
||||||
|
if (pSelection==NULL) return false;
|
||||||
|
|
||||||
|
if (IsInside(x,y)) {
|
||||||
|
pSelection[x + y * head.biWidth] = level; // set the correct mask bit
|
||||||
|
|
||||||
|
if (info.rSelectionBox.top <= y) info.rSelectionBox.top = y+1;
|
||||||
|
if (info.rSelectionBox.left > x) info.rSelectionBox.left = x;
|
||||||
|
if (info.rSelectionBox.right <= x) info.rSelectionBox.right = x+1;
|
||||||
|
if (info.rSelectionBox.bottom > y) info.rSelectionBox.bottom = y;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Exports the selection channel in a 8bpp grayscale image.
|
||||||
|
*/
|
||||||
|
bool CxImage::SelectionSplit(CxImage *dest)
|
||||||
|
{
|
||||||
|
if (!pSelection || !dest) return false;
|
||||||
|
|
||||||
|
CxImage tmp(head.biWidth,head.biHeight,8);
|
||||||
|
if (!tmp.IsValid()){
|
||||||
|
strcpy(info.szLastError,tmp.GetLastError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int32_t y=0; y<head.biHeight; y++){
|
||||||
|
for(int32_t x=0; x<head.biWidth; x++){
|
||||||
|
tmp.BlindSetPixelIndex(x,y,pSelection[x+y*head.biWidth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp.SetGrayPalette();
|
||||||
|
dest->Transfer(tmp);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Creates the selection channel from a gray scale image.
|
||||||
|
* black = unselected
|
||||||
|
*/
|
||||||
|
bool CxImage::SelectionSet(CxImage &from)
|
||||||
|
{
|
||||||
|
if (!from.IsGrayScale() || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight){
|
||||||
|
strcpy(info.szLastError,"CxImage::SelectionSet: wrong width or height, or image is not gray scale");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pSelection==NULL) pSelection = (uint8_t*)malloc(head.biWidth * head.biHeight);
|
||||||
|
|
||||||
|
uint8_t* src = from.info.pImage;
|
||||||
|
uint8_t* dst = pSelection;
|
||||||
|
if (src==NULL || dst==NULL){
|
||||||
|
strcpy(info.szLastError,"CxImage::SelectionSet: null pointer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32_t y=0; y<head.biHeight; y++){
|
||||||
|
memcpy(dst,src,head.biWidth);
|
||||||
|
dst += head.biWidth;
|
||||||
|
src += from.info.dwEffWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectionRebuildBox();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Sets the Selection level for a single pixel
|
||||||
|
* internal use only: doesn't set SelectionBox. Use SelectionAddPixel
|
||||||
|
*/
|
||||||
|
void CxImage::SelectionSet(const int32_t x,const int32_t y,const uint8_t level)
|
||||||
|
{
|
||||||
|
if (pSelection && IsInside(x,y)) pSelection[x+y*head.biWidth]=level;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Gets the Selection level for a single pixel
|
||||||
|
*/
|
||||||
|
uint8_t CxImage::SelectionGet(const int32_t x,const int32_t y)
|
||||||
|
{
|
||||||
|
if (pSelection && IsInside(x,y)) return pSelection[x+y*head.biWidth];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Rebuilds the SelectionBox
|
||||||
|
*/
|
||||||
|
void CxImage::SelectionRebuildBox()
|
||||||
|
{
|
||||||
|
info.rSelectionBox.left = head.biWidth;
|
||||||
|
info.rSelectionBox.bottom = head.biHeight;
|
||||||
|
info.rSelectionBox.right = info.rSelectionBox.top = 0;
|
||||||
|
|
||||||
|
if (!pSelection)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int32_t x,y;
|
||||||
|
|
||||||
|
for (y=0; y<head.biHeight; y++){
|
||||||
|
for (x=0; x<info.rSelectionBox.left; x++){
|
||||||
|
if (pSelection[x+y*head.biWidth]){
|
||||||
|
info.rSelectionBox.left = x;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (y=0; y<head.biHeight; y++){
|
||||||
|
for (x=head.biWidth-1; x>=info.rSelectionBox.right; x--){
|
||||||
|
if (pSelection[x+y*head.biWidth]){
|
||||||
|
info.rSelectionBox.right = x+1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (x=0; x<head.biWidth; x++){
|
||||||
|
for (y=0; y<info.rSelectionBox.bottom; y++){
|
||||||
|
if (pSelection[x+y*head.biWidth]){
|
||||||
|
info.rSelectionBox.bottom = y;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (x=0; x<head.biWidth; x++){
|
||||||
|
for (y=head.biHeight-1; y>=info.rSelectionBox.top; y--){
|
||||||
|
if (pSelection[x+y*head.biWidth]){
|
||||||
|
info.rSelectionBox.top = y+1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Gets the Selection level for a single pixel
|
||||||
|
* "blind" version assumes that (x,y) is inside to the image.
|
||||||
|
*/
|
||||||
|
uint8_t CxImage::BlindSelectionGet(const int32_t x,const int32_t y)
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
if (!IsInside(x,y) || (pSelection==0))
|
||||||
|
#if CXIMAGE_SUPPORT_EXCEPTION_HANDLING
|
||||||
|
throw 0;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return pSelection[x+y*head.biWidth];
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Returns pointer to selection data for pixel (x,y).
|
||||||
|
*/
|
||||||
|
uint8_t* CxImage::SelectionGetPointer(const int32_t x,const int32_t y)
|
||||||
|
{
|
||||||
|
if (pSelection && IsInside(x,y)) return pSelection+x+y*head.biWidth;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImage::SelectionFlip()
|
||||||
|
{
|
||||||
|
if (!pSelection) return false;
|
||||||
|
|
||||||
|
uint8_t *buff = (uint8_t*)malloc(head.biWidth);
|
||||||
|
if (!buff) return false;
|
||||||
|
|
||||||
|
uint8_t *iSrc,*iDst;
|
||||||
|
iSrc = pSelection + (head.biHeight-1)*head.biWidth;
|
||||||
|
iDst = pSelection;
|
||||||
|
for (int32_t i=0; i<(head.biHeight/2); ++i)
|
||||||
|
{
|
||||||
|
memcpy(buff, iSrc, head.biWidth);
|
||||||
|
memcpy(iSrc, iDst, head.biWidth);
|
||||||
|
memcpy(iDst, buff, head.biWidth);
|
||||||
|
iSrc-=head.biWidth;
|
||||||
|
iDst+=head.biWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buff);
|
||||||
|
|
||||||
|
int32_t top = info.rSelectionBox.top;
|
||||||
|
info.rSelectionBox.top = head.biHeight - info.rSelectionBox.bottom;
|
||||||
|
info.rSelectionBox.bottom = head.biHeight - top;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImage::SelectionMirror()
|
||||||
|
{
|
||||||
|
if (!pSelection) return false;
|
||||||
|
uint8_t* pSelection2 = (uint8_t*)malloc(head.biWidth * head.biHeight);
|
||||||
|
if (!pSelection2) return false;
|
||||||
|
|
||||||
|
uint8_t *iSrc,*iDst;
|
||||||
|
int32_t wdt=head.biWidth-1;
|
||||||
|
iSrc=pSelection + wdt;
|
||||||
|
iDst=pSelection2;
|
||||||
|
for(int32_t y=0; y < head.biHeight; y++){
|
||||||
|
for(int32_t x=0; x <= wdt; x++)
|
||||||
|
*(iDst+x)=*(iSrc-x);
|
||||||
|
iSrc+=head.biWidth;
|
||||||
|
iDst+=head.biWidth;
|
||||||
|
}
|
||||||
|
free(pSelection);
|
||||||
|
pSelection=pSelection2;
|
||||||
|
|
||||||
|
int32_t left = info.rSelectionBox.left;
|
||||||
|
info.rSelectionBox.left = head.biWidth - info.rSelectionBox.right;
|
||||||
|
info.rSelectionBox.right = head.biWidth - left;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_WINDOWS
|
||||||
|
/**
|
||||||
|
* Converts the selection in a HRGN object.
|
||||||
|
*/
|
||||||
|
bool CxImage::SelectionToHRGN(HRGN& region)
|
||||||
|
{
|
||||||
|
if (pSelection && region){
|
||||||
|
for(int32_t y = 0; y < head.biHeight; y++){
|
||||||
|
HRGN hTemp = NULL;
|
||||||
|
int32_t iStart = -1;
|
||||||
|
int32_t x = 0;
|
||||||
|
for(; x < head.biWidth; x++){
|
||||||
|
if (pSelection[x + y * head.biWidth] != 0){
|
||||||
|
if (iStart == -1) iStart = x;
|
||||||
|
continue;
|
||||||
|
}else{
|
||||||
|
if (iStart >= 0){
|
||||||
|
hTemp = CreateRectRgn(iStart, y, x, y + 1);
|
||||||
|
CombineRgn(region, hTemp, region, RGN_OR);
|
||||||
|
DeleteObject(hTemp);
|
||||||
|
iStart = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (iStart >= 0){
|
||||||
|
hTemp = CreateRectRgn(iStart, y, x, y + 1);
|
||||||
|
CombineRgn(region, hTemp, region, RGN_OR);
|
||||||
|
DeleteObject(hTemp);
|
||||||
|
iStart = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif //CXIMAGE_SUPPORT_WINDOWS
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_SELECTION
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* File: ximaska.cpp
|
||||||
|
* Purpose: Platform Independent SKA Image Class Loader and Writer
|
||||||
|
* 25/Sep/2007 Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximaska.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_SKA
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageSKA::Decode(CxFile *hFile)
|
||||||
|
{
|
||||||
|
if (hFile==NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// read the header
|
||||||
|
SKAHEADER ska_header;
|
||||||
|
hFile->Read(&ska_header,sizeof(SKAHEADER),1);
|
||||||
|
|
||||||
|
ska_header.Width = m_ntohs(ska_header.Width);
|
||||||
|
ska_header.Height = m_ntohs(ska_header.Height);
|
||||||
|
ska_header.dwUnknown = m_ntohl(ska_header.dwUnknown);
|
||||||
|
|
||||||
|
// check header
|
||||||
|
if (ska_header.dwUnknown != 0x01000000 ||
|
||||||
|
ska_header.Width > 0x7FFF || ska_header.Height > 0x7FFF ||
|
||||||
|
ska_header.BppExp != 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (info.nEscape == -1){
|
||||||
|
head.biWidth = ska_header.Width ;
|
||||||
|
head.biHeight= ska_header.Height;
|
||||||
|
info.dwType = CXIMAGE_FORMAT_SKA;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t bpp = 1<<ska_header.BppExp;
|
||||||
|
|
||||||
|
Create(ska_header.Width,ska_header.Height,bpp,CXIMAGE_FORMAT_SKA);
|
||||||
|
if (!IsValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// read the palette
|
||||||
|
int32_t nColors = 1<<bpp;
|
||||||
|
rgb_color* ppal = (rgb_color*)malloc(nColors*sizeof(rgb_color));
|
||||||
|
if (!ppal) return false;
|
||||||
|
hFile->Read(ppal,nColors*sizeof(rgb_color),1);
|
||||||
|
SetPalette(ppal,nColors);
|
||||||
|
free(ppal);
|
||||||
|
|
||||||
|
//read the image
|
||||||
|
hFile->Read(GetBits(),ska_header.Width*ska_header.Height,1);
|
||||||
|
|
||||||
|
//reorder rows
|
||||||
|
if (GetEffWidth() != ska_header.Width){
|
||||||
|
uint8_t *src,*dst;
|
||||||
|
src = GetBits() + ska_header.Width*(ska_header.Height-1);
|
||||||
|
dst = GetBits(ska_header.Height-1);
|
||||||
|
for(int32_t y=0;y<ska_header.Height;y++){
|
||||||
|
memcpy(dst,src,ska_header.Width);
|
||||||
|
src -= ska_header.Width;
|
||||||
|
dst -= GetEffWidth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Flip();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageSKA::Encode(CxFile * hFile)
|
||||||
|
{
|
||||||
|
if (EncodeSafeCheck(hFile)) return false;
|
||||||
|
|
||||||
|
if(head.biBitCount > 8) {
|
||||||
|
strcpy(info.szLastError,"SKA Images must be 8 bit or less");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SKAHEADER ska_header;
|
||||||
|
|
||||||
|
ska_header.Width = (uint16_t)GetWidth();
|
||||||
|
ska_header.Height = (uint16_t)GetHeight();
|
||||||
|
ska_header.BppExp = 3;
|
||||||
|
ska_header.dwUnknown = 0x01000000;
|
||||||
|
|
||||||
|
ska_header.Width = m_ntohs(ska_header.Width);
|
||||||
|
ska_header.Height = m_ntohs(ska_header.Height);
|
||||||
|
ska_header.dwUnknown = m_ntohl(ska_header.dwUnknown);
|
||||||
|
|
||||||
|
hFile->Write(&ska_header,sizeof(SKAHEADER),1);
|
||||||
|
|
||||||
|
ska_header.Width = m_ntohs(ska_header.Width);
|
||||||
|
ska_header.Height = m_ntohs(ska_header.Height);
|
||||||
|
ska_header.dwUnknown = m_ntohl(ska_header.dwUnknown);
|
||||||
|
|
||||||
|
if (head.biBitCount<8) IncreaseBpp(8);
|
||||||
|
|
||||||
|
rgb_color pal[256];
|
||||||
|
for(int32_t idx=0; idx<256; idx++){
|
||||||
|
GetPaletteColor(idx,&(pal[idx].r),&(pal[idx].g),&(pal[idx].b));
|
||||||
|
}
|
||||||
|
|
||||||
|
hFile->Write(pal,256*sizeof(rgb_color),1);
|
||||||
|
|
||||||
|
uint8_t* src = GetBits(ska_header.Height-1);
|
||||||
|
for(int32_t y=0;y<ska_header.Height;y++){
|
||||||
|
hFile->Write(src,ska_header.Width,1);
|
||||||
|
src -= GetEffWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_SKA
|
||||||
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* File: ximaska.h
|
||||||
|
* Purpose: SKA Image Class Loader and Writer
|
||||||
|
*/
|
||||||
|
/* ==========================================================
|
||||||
|
* CxImageSKA (c) 25/Sep/2007 Davide Pizzolato - www.xdp.it
|
||||||
|
* For conditions of distribution and use, see copyright notice in ximage.h
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
#if !defined(__ximaSKA_h)
|
||||||
|
#define __ximaSKA_h
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_SKA
|
||||||
|
|
||||||
|
class CxImageSKA: public CxImage
|
||||||
|
{
|
||||||
|
#pragma pack(1)
|
||||||
|
typedef struct tagSkaHeader {
|
||||||
|
uint16_t Width;
|
||||||
|
uint16_t Height;
|
||||||
|
uint8_t BppExp;
|
||||||
|
uint32_t dwUnknown;
|
||||||
|
} SKAHEADER;
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
public:
|
||||||
|
CxImageSKA(): CxImage(CXIMAGE_FORMAT_SKA) {}
|
||||||
|
|
||||||
|
// bool Load(const char * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_ICO);}
|
||||||
|
// bool Save(const char * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_ICO);}
|
||||||
|
bool Decode(CxFile * hFile);
|
||||||
|
bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
bool Encode(CxFile * hFile);
|
||||||
|
bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,320 @@
|
|||||||
|
/*
|
||||||
|
* File: ximatga.cpp
|
||||||
|
* Purpose: Platform Independent TGA Image Class Loader and Writer
|
||||||
|
* 05/Jan/2001 Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximatga.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_TGA
|
||||||
|
|
||||||
|
#include "ximaiter.h"
|
||||||
|
|
||||||
|
// Definitions for image types.
|
||||||
|
#define TGA_Null 0
|
||||||
|
#define TGA_Map 1
|
||||||
|
#define TGA_RGB 2
|
||||||
|
#define TGA_Mono 3
|
||||||
|
#define TGA_RLEMap 9
|
||||||
|
#define TGA_RLERGB 10
|
||||||
|
#define TGA_RLEMono 11
|
||||||
|
#define TGA_CompMap 32
|
||||||
|
#define TGA_CompMap4 33
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageTGA::Decode(CxFile *hFile)
|
||||||
|
{
|
||||||
|
if (hFile == NULL) return false;
|
||||||
|
|
||||||
|
TGAHEADER tgaHead;
|
||||||
|
|
||||||
|
cx_try
|
||||||
|
{
|
||||||
|
if (hFile->Read(&tgaHead,sizeof(tgaHead),1)==0)
|
||||||
|
cx_throw("Not a TGA");
|
||||||
|
|
||||||
|
tga_toh(&tgaHead);
|
||||||
|
|
||||||
|
bool bCompressed;
|
||||||
|
switch (tgaHead.ImageType){
|
||||||
|
case TGA_Map:
|
||||||
|
case TGA_RGB:
|
||||||
|
case TGA_Mono:
|
||||||
|
bCompressed = false;
|
||||||
|
break;
|
||||||
|
case TGA_RLEMap:
|
||||||
|
case TGA_RLERGB:
|
||||||
|
case TGA_RLEMono:
|
||||||
|
bCompressed = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cx_throw("Unknown TGA image type");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tgaHead.ImageWidth==0 || tgaHead.ImageHeight==0 || tgaHead.PixelDepth==0 || tgaHead.CmapLength>256)
|
||||||
|
cx_throw("bad TGA header");
|
||||||
|
|
||||||
|
if (tgaHead.PixelDepth!=8 && tgaHead.PixelDepth!=15 && tgaHead.PixelDepth!=16 && tgaHead.PixelDepth!=24 && tgaHead.PixelDepth!=32)
|
||||||
|
cx_throw("bad TGA header");
|
||||||
|
|
||||||
|
if (info.nEscape == -1){
|
||||||
|
head.biWidth = tgaHead.ImageWidth ;
|
||||||
|
head.biHeight= tgaHead.ImageHeight;
|
||||||
|
info.dwType = CXIMAGE_FORMAT_TGA;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tgaHead.IdLength>0) hFile->Seek(tgaHead.IdLength,SEEK_CUR); //skip descriptor
|
||||||
|
|
||||||
|
Create(tgaHead.ImageWidth, tgaHead.ImageHeight, tgaHead.PixelDepth, CXIMAGE_FORMAT_TGA);
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA // <vho>
|
||||||
|
if (tgaHead.PixelDepth==32) AlphaCreate(); // Image has alpha channel
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
|
||||||
|
if (!IsValid()) cx_throw("TGA Create failed");
|
||||||
|
|
||||||
|
if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding
|
||||||
|
|
||||||
|
if (tgaHead.CmapType != 0){ // read the palette
|
||||||
|
rgb_color pal[256];
|
||||||
|
hFile->Read(pal,tgaHead.CmapLength*sizeof(rgb_color), 1);
|
||||||
|
for (int32_t i=0;i<tgaHead.CmapLength; i++) SetPaletteColor((uint8_t)i,pal[i].b,pal[i].g,pal[i].r);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tgaHead.ImageType == TGA_Mono || tgaHead.ImageType == TGA_RLEMono)
|
||||||
|
SetGrayPalette();
|
||||||
|
|
||||||
|
// Bits 4 & 5 of the Image Descriptor byte control the ordering of the pixels.
|
||||||
|
bool bXReversed = ((tgaHead.ImagDesc & 16) == 16);
|
||||||
|
bool bYReversed = ((tgaHead.ImagDesc & 32) == 32);
|
||||||
|
|
||||||
|
CImageIterator iter(this);
|
||||||
|
uint8_t rleLeftover = 255; //for images with illegal packet boundary
|
||||||
|
uint8_t* pDest;
|
||||||
|
for (int32_t y=0; y < tgaHead.ImageHeight; y++){
|
||||||
|
|
||||||
|
if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding
|
||||||
|
|
||||||
|
if (hFile == NULL || hFile->Eof()) cx_throw("corrupted TGA");
|
||||||
|
|
||||||
|
if (bYReversed) pDest = iter.GetRow(tgaHead.ImageHeight-y-1);
|
||||||
|
else pDest = iter.GetRow(y);
|
||||||
|
|
||||||
|
if (bCompressed) rleLeftover = ExpandCompressedLine(pDest,&tgaHead,hFile,tgaHead.ImageWidth,y,rleLeftover);
|
||||||
|
else ExpandUncompressedLine (pDest,&tgaHead,hFile,tgaHead.ImageWidth,y,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bXReversed) Mirror();
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (bYReversed && tgaHead.PixelDepth==32) AlphaFlip(); //<lioucr>
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
|
||||||
|
} cx_catch {
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageTGA::Encode(CxFile * hFile)
|
||||||
|
{
|
||||||
|
if (EncodeSafeCheck(hFile)) return false;
|
||||||
|
|
||||||
|
if (head.biBitCount<8){
|
||||||
|
strcpy(info.szLastError,"Bit depth must be 8 or 24");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TGAHEADER tgaHead;
|
||||||
|
|
||||||
|
tgaHead.IdLength = 0; // Image ID Field Length
|
||||||
|
tgaHead.CmapType = GetPalette()!=0; // Color Map Type
|
||||||
|
tgaHead.ImageType = (head.biBitCount == 8) ? (uint8_t)TGA_Map : (uint8_t)TGA_RGB; // Image Type
|
||||||
|
|
||||||
|
tgaHead.CmapIndex=0; // First Entry Index
|
||||||
|
tgaHead.CmapLength=(head.biBitCount == 8) ? 256 : 0; // Color Map Length
|
||||||
|
tgaHead.CmapEntrySize=(head.biBitCount == 8) ? (uint8_t)24 : (uint8_t)0; // Color Map Entry Size
|
||||||
|
|
||||||
|
tgaHead.X_Origin=0; // X-origin of Image
|
||||||
|
tgaHead.Y_Origin=0; // Y-origin of Image
|
||||||
|
tgaHead.ImageWidth=(uint16_t)head.biWidth; // Image Width
|
||||||
|
tgaHead.ImageHeight=(uint16_t)head.biHeight; // Image Height
|
||||||
|
tgaHead.PixelDepth=(uint8_t)head.biBitCount; // Pixel Depth
|
||||||
|
tgaHead.ImagDesc=0; // Image Descriptor
|
||||||
|
|
||||||
|
if (pAlpha && head.biBitCount==24) tgaHead.PixelDepth=32;
|
||||||
|
|
||||||
|
tga_toh(&tgaHead);
|
||||||
|
hFile->Write(&tgaHead,sizeof(TGAHEADER),1);
|
||||||
|
tga_toh(&tgaHead);
|
||||||
|
|
||||||
|
if (head.biBitCount==8){
|
||||||
|
rgb_color pal[256];
|
||||||
|
RGBQUAD* ppal = GetPalette();
|
||||||
|
for (int32_t i=0;i<256; i++){
|
||||||
|
pal[i].r = ppal[i].rgbBlue;
|
||||||
|
pal[i].g = ppal[i].rgbGreen;
|
||||||
|
pal[i].b = ppal[i].rgbRed;
|
||||||
|
}
|
||||||
|
hFile->Write(&pal,256*sizeof(rgb_color),1);
|
||||||
|
}
|
||||||
|
|
||||||
|
CImageIterator iter(this);
|
||||||
|
uint8_t* pDest;
|
||||||
|
if (pAlpha==0 || head.biBitCount==8){
|
||||||
|
for (int32_t y=0; y < tgaHead.ImageHeight; y++){
|
||||||
|
pDest = iter.GetRow(y);
|
||||||
|
hFile->Write(pDest,tgaHead.ImageWidth * (head.biBitCount >> 3),1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pDest = (uint8_t*)malloc(4*tgaHead.ImageWidth);
|
||||||
|
RGBQUAD c;
|
||||||
|
for (int32_t y=0; y < tgaHead.ImageHeight; y++){
|
||||||
|
for(int32_t x=0, x4=0;x<tgaHead.ImageWidth;x++, x4+=4){
|
||||||
|
c = BlindGetPixelColor(x,y);
|
||||||
|
pDest[x4+0]=c.rgbBlue;
|
||||||
|
pDest[x4+1]=c.rgbGreen;
|
||||||
|
pDest[x4+2]=c.rgbRed;
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA // <vho>
|
||||||
|
pDest[x4+3]=AlphaGet(x,y);
|
||||||
|
#else
|
||||||
|
pDest[x4+3]=0;
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
}
|
||||||
|
hFile->Write(pDest,4*tgaHead.ImageWidth,1);
|
||||||
|
}
|
||||||
|
free(pDest);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
uint8_t CxImageTGA::ExpandCompressedLine(uint8_t* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int32_t width, int32_t y, uint8_t rleLeftover)
|
||||||
|
{
|
||||||
|
uint8_t rle;
|
||||||
|
int32_t filePos=0;
|
||||||
|
for (int32_t x=0; x<width; ){
|
||||||
|
if (rleLeftover != 255){
|
||||||
|
rle = rleLeftover;
|
||||||
|
rleLeftover = 255;
|
||||||
|
} else {
|
||||||
|
hFile->Read(&rle,1,1);
|
||||||
|
}
|
||||||
|
if (rle & 128) { // RLE-Encoded packet
|
||||||
|
rle -= 127; // Calculate real repeat count.
|
||||||
|
if ((x+rle)>width){
|
||||||
|
rleLeftover = (uint8_t)(128 + (rle - (width - x) - 1));
|
||||||
|
filePos = hFile->Tell();
|
||||||
|
rle = (uint8_t)(width - x);
|
||||||
|
}
|
||||||
|
switch (ptgaHead->PixelDepth)
|
||||||
|
{
|
||||||
|
case 32: {
|
||||||
|
RGBQUAD color;
|
||||||
|
hFile->Read(&color,4,1);
|
||||||
|
for (int32_t ix = 0; ix < rle; ix++){
|
||||||
|
memcpy(&pDest[3*ix],&color,3);
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA // <vho>
|
||||||
|
AlphaSet(ix+x,y,color.rgbReserved);
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 24: {
|
||||||
|
rgb_color triple;
|
||||||
|
hFile->Read(&triple,3,1);
|
||||||
|
for (int32_t ix = 0; ix < rle; ix++) memcpy(&pDest[3*ix],&triple,3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 15:
|
||||||
|
case 16: {
|
||||||
|
uint16_t pixel;
|
||||||
|
hFile->Read(&pixel,2,1);
|
||||||
|
rgb_color triple;
|
||||||
|
triple.r = (uint8_t)(( pixel & 0x1F ) * 8); // red
|
||||||
|
triple.g = (uint8_t)(( pixel >> 2 ) & 0x0F8); // green
|
||||||
|
triple.b = (uint8_t)(( pixel >> 7 ) & 0x0F8); // blue
|
||||||
|
for (int32_t ix = 0; ix < rle; ix++){
|
||||||
|
memcpy(&pDest[3*ix],&triple,3);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 8: {
|
||||||
|
uint8_t pixel;
|
||||||
|
hFile->Read(&pixel,1,1);
|
||||||
|
for (int32_t ix = 0; ix < rle; ix++) pDest[ix] = pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rleLeftover!=255) hFile->Seek(filePos, SEEK_SET);
|
||||||
|
} else { // Raw packet
|
||||||
|
rle += 1; // Calculate real repeat count.
|
||||||
|
if ((x+rle)>width){
|
||||||
|
rleLeftover = (uint8_t)(rle - (width - x) - 1);
|
||||||
|
rle = (uint8_t)(width - x);
|
||||||
|
}
|
||||||
|
ExpandUncompressedLine(pDest,ptgaHead,hFile,rle,y,x);
|
||||||
|
}
|
||||||
|
if (head.biBitCount == 24) pDest += rle*3; else pDest += rle;
|
||||||
|
x += rle;
|
||||||
|
}
|
||||||
|
return rleLeftover;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImageTGA::ExpandUncompressedLine(uint8_t* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int32_t width, int32_t y, int32_t xoffset)
|
||||||
|
{
|
||||||
|
switch (ptgaHead->PixelDepth){
|
||||||
|
case 8:
|
||||||
|
hFile->Read(pDest,width,1);
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
case 16:{
|
||||||
|
uint8_t* dst=pDest;
|
||||||
|
uint16_t pixel;
|
||||||
|
for (int32_t x=0; x<width; x++){
|
||||||
|
hFile->Read(&pixel,2,1);
|
||||||
|
*dst++ = (uint8_t)(( pixel & 0x1F ) * 8); // blue
|
||||||
|
*dst++ = (uint8_t)(( pixel >> 2 ) & 0x0F8); // green
|
||||||
|
*dst++ = (uint8_t)(( pixel >> 7 ) & 0x0F8); // red
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 24:
|
||||||
|
hFile->Read(pDest,3*width,1);
|
||||||
|
break;
|
||||||
|
case 32:{
|
||||||
|
uint8_t* dst=pDest;
|
||||||
|
for (int32_t x=0; x<width; x++){
|
||||||
|
RGBQUAD pixel;
|
||||||
|
hFile->Read(&pixel,4,1);
|
||||||
|
*dst++ = pixel.rgbBlue;
|
||||||
|
*dst++ = pixel.rgbGreen;
|
||||||
|
*dst++ = pixel.rgbRed;
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA // <vho>
|
||||||
|
AlphaSet(x+xoffset,y,pixel.rgbReserved); //alpha
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImageTGA::tga_toh(TGAHEADER* p)
|
||||||
|
{
|
||||||
|
p->CmapIndex = m_ntohs(p->CmapIndex);
|
||||||
|
p->CmapLength = m_ntohs(p->CmapLength);
|
||||||
|
p->X_Origin = m_ntohs(p->X_Origin);
|
||||||
|
p->Y_Origin = m_ntohs(p->Y_Origin);
|
||||||
|
p->ImageWidth = m_ntohs(p->ImageWidth);
|
||||||
|
p->ImageHeight = m_ntohs(p->ImageHeight);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_TGA
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* File: ximatga.h
|
||||||
|
* Purpose: TARGA Image Class Loader and Writer
|
||||||
|
*/
|
||||||
|
/* ==========================================================
|
||||||
|
* CxImageTGA (c) 05/Jan/2002 Davide Pizzolato - www.xdp.it
|
||||||
|
* For conditions of distribution and use, see copyright notice in ximage.h
|
||||||
|
*
|
||||||
|
* Parts of the code come from Paintlib : Copyright (c) 1996-1998 Ulrich von Zadow
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
#if !defined(__ximaTGA_h)
|
||||||
|
#define __ximaTGA_h
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_TGA
|
||||||
|
|
||||||
|
class CxImageTGA: public CxImage
|
||||||
|
{
|
||||||
|
#pragma pack(1)
|
||||||
|
typedef struct tagTgaHeader
|
||||||
|
{
|
||||||
|
uint8_t IdLength; // Image ID Field Length
|
||||||
|
uint8_t CmapType; // Color Map Type
|
||||||
|
uint8_t ImageType; // Image Type
|
||||||
|
|
||||||
|
uint16_t CmapIndex; // First Entry Index
|
||||||
|
uint16_t CmapLength; // Color Map Length
|
||||||
|
uint8_t CmapEntrySize; // Color Map Entry Size
|
||||||
|
|
||||||
|
uint16_t X_Origin; // X-origin of Image
|
||||||
|
uint16_t Y_Origin; // Y-origin of Image
|
||||||
|
uint16_t ImageWidth; // Image Width
|
||||||
|
uint16_t ImageHeight; // Image Height
|
||||||
|
uint8_t PixelDepth; // Pixel Depth
|
||||||
|
uint8_t ImagDesc; // Image Descriptor
|
||||||
|
} TGAHEADER;
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
public:
|
||||||
|
CxImageTGA(): CxImage(CXIMAGE_FORMAT_TGA) {}
|
||||||
|
|
||||||
|
// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_TGA);}
|
||||||
|
// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_TGA);}
|
||||||
|
bool Decode(CxFile * hFile);
|
||||||
|
bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
bool Encode(CxFile * hFile);
|
||||||
|
bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
protected:
|
||||||
|
uint8_t ExpandCompressedLine(uint8_t* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int32_t width, int32_t y, uint8_t rleLeftover);
|
||||||
|
void ExpandUncompressedLine(uint8_t* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int32_t width, int32_t y, int32_t xoffset);
|
||||||
|
void tga_toh(TGAHEADER* p);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
#include "ximage.h"
|
||||||
|
#include "ximath.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
//this module should contain some classes for geometrical transformations
|
||||||
|
//usable with selections, etc... once it's done, that is. :)
|
||||||
|
|
||||||
|
CxPoint2::CxPoint2()
|
||||||
|
{
|
||||||
|
x=y=0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
CxPoint2::CxPoint2(float const x_, float const y_)
|
||||||
|
{
|
||||||
|
x=x_;
|
||||||
|
y=y_;
|
||||||
|
}
|
||||||
|
|
||||||
|
CxPoint2::CxPoint2(CxPoint2 const &p)
|
||||||
|
{
|
||||||
|
x=p.x;
|
||||||
|
y=p.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
float CxPoint2::Distance(CxPoint2 const p2)
|
||||||
|
{
|
||||||
|
return (float)sqrt((x-p2.x)*(x-p2.x)+(y-p2.y)*(y-p2.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
float CxPoint2::Distance(float const x_, float const y_)
|
||||||
|
{
|
||||||
|
return (float)sqrt((x-x_)*(x-x_)+(y-y_)*(y-y_));
|
||||||
|
}
|
||||||
|
|
||||||
|
CxRect2::CxRect2()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CxRect2::CxRect2(float const x1_, float const y1_, float const x2_, float const y2_)
|
||||||
|
{
|
||||||
|
botLeft.x=x1_;
|
||||||
|
botLeft.y=y1_;
|
||||||
|
topRight.x=x2_;
|
||||||
|
topRight.y=y2_;
|
||||||
|
}
|
||||||
|
|
||||||
|
CxRect2::CxRect2(CxRect2 const &p)
|
||||||
|
{
|
||||||
|
botLeft=p.botLeft;
|
||||||
|
topRight=p.topRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
float CxRect2::Surface() const
|
||||||
|
/*
|
||||||
|
* Returns the surface of rectangle.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
return (topRight.x-botLeft.x)*(topRight.y-botLeft.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
CxRect2 CxRect2::CrossSection(CxRect2 const &r2) const
|
||||||
|
/*
|
||||||
|
* Returns crossection with another rectangle.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
CxRect2 cs;
|
||||||
|
cs.botLeft.x=max(botLeft.x, r2.botLeft.x);
|
||||||
|
cs.botLeft.y=max(botLeft.y, r2.botLeft.y);
|
||||||
|
cs.topRight.x=min(topRight.x, r2.topRight.x);
|
||||||
|
cs.topRight.y=min(topRight.y, r2.topRight.y);
|
||||||
|
if (cs.botLeft.x<=cs.topRight.x && cs.botLeft.y<=cs.topRight.y) {
|
||||||
|
return cs;
|
||||||
|
} else {
|
||||||
|
return CxRect2(0,0,0,0);
|
||||||
|
}//if
|
||||||
|
}
|
||||||
|
|
||||||
|
CxPoint2 CxRect2::Center() const
|
||||||
|
/*
|
||||||
|
* Returns the center point of rectangle.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
return CxPoint2((topRight.x+botLeft.x)/2.0f, (topRight.y+botLeft.y)/2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float CxRect2::Width() const
|
||||||
|
//returns rectangle width
|
||||||
|
{
|
||||||
|
return topRight.x-botLeft.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
float CxRect2::Height() const
|
||||||
|
//returns rectangle height
|
||||||
|
{
|
||||||
|
return topRight.y-botLeft.y;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#if !defined(__ximath_h)
|
||||||
|
#define __ximath_h
|
||||||
|
|
||||||
|
#include "ximadef.h"
|
||||||
|
|
||||||
|
//***bd*** simple floating point point
|
||||||
|
class DLL_EXP CxPoint2
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CxPoint2();
|
||||||
|
CxPoint2(float const x_, float const y_);
|
||||||
|
CxPoint2(CxPoint2 const &p);
|
||||||
|
|
||||||
|
float Distance(CxPoint2 const p2);
|
||||||
|
float Distance(float const x_, float const y_);
|
||||||
|
|
||||||
|
float x,y;
|
||||||
|
};
|
||||||
|
|
||||||
|
//and simple rectangle
|
||||||
|
class DLL_EXP CxRect2
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CxRect2();
|
||||||
|
CxRect2(float const x1_, float const y1_, float const x2_, float const y2_);
|
||||||
|
CxRect2(CxPoint2 const &bl, CxPoint2 const &tr);
|
||||||
|
CxRect2(CxRect2 const &p);
|
||||||
|
|
||||||
|
float Surface() const;
|
||||||
|
CxRect2 CrossSection(CxRect2 const &r2) const;
|
||||||
|
CxPoint2 Center() const;
|
||||||
|
float Width() const;
|
||||||
|
float Height() const;
|
||||||
|
|
||||||
|
CxPoint2 botLeft;
|
||||||
|
CxPoint2 topRight;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,982 @@
|
|||||||
|
/*
|
||||||
|
* File: ximatif.cpp
|
||||||
|
* Purpose: Platform Independent TIFF Image Class Loader and Writer
|
||||||
|
* 07/Aug/2001 Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximatif.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_TIF
|
||||||
|
|
||||||
|
#define FIX_16BPP_DARKIMG // + VK: if uncomment, dark 16bpp images are fixed
|
||||||
|
|
||||||
|
#include "../tiff/tiffio.h"
|
||||||
|
|
||||||
|
#define CVT(x) (((x) * 255L) / ((1L<<16)-1))
|
||||||
|
#define SCALE(x) (((x)*((1L<<16)-1))/255)
|
||||||
|
#define CalculateLine(width,bitdepth) (((width * bitdepth) + 7) / 8)
|
||||||
|
#define CalculatePitch(line) (line + 3 & ~3)
|
||||||
|
|
||||||
|
extern "C" TIFF* _TIFFOpenEx(CxFile* stream, const char* mode);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CxImageTIF::~CxImageTIF()
|
||||||
|
{
|
||||||
|
if (m_tif2) TIFFClose(m_tif2);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageTIF::Decode(CxFile * hFile)
|
||||||
|
{
|
||||||
|
//Comment this line if you need more information on errors
|
||||||
|
// TIFFSetErrorHandler(NULL); //<Patrick Hoffmann>
|
||||||
|
|
||||||
|
//Open file and fill the TIFF structure
|
||||||
|
// m_tif = TIFFOpen(imageFileName,"rb");
|
||||||
|
TIFF* m_tif = _TIFFOpenEx(hFile, "rb");
|
||||||
|
|
||||||
|
uint32 height=0;
|
||||||
|
uint32 width=0;
|
||||||
|
uint16 bitspersample=1;
|
||||||
|
uint16 samplesperpixel=1;
|
||||||
|
uint32 rowsperstrip=(uint32_t)-1;
|
||||||
|
uint16 photometric=0;
|
||||||
|
uint16 compression=1;
|
||||||
|
uint16 orientation=ORIENTATION_TOPLEFT; //<vho>
|
||||||
|
uint16 res_unit; //<Trifon>
|
||||||
|
uint32 x, y;
|
||||||
|
float resolution, offset;
|
||||||
|
BOOL isRGB;
|
||||||
|
uint8_t *bits; //pointer to source data
|
||||||
|
uint8_t *bits2; //pointer to destination data
|
||||||
|
|
||||||
|
cx_try
|
||||||
|
{
|
||||||
|
//check if it's a tiff file
|
||||||
|
if (!m_tif)
|
||||||
|
cx_throw("Error encountered while opening TIFF file");
|
||||||
|
|
||||||
|
// <Robert Abram> - 12/2002 : get NumFrames directly, instead of looping
|
||||||
|
// info.nNumFrames=0;
|
||||||
|
// while(TIFFSetDirectory(m_tif,(uint16)info.nNumFrames)) info.nNumFrames++;
|
||||||
|
info.nNumFrames = TIFFNumberOfDirectories(m_tif);
|
||||||
|
|
||||||
|
if (!TIFFSetDirectory(m_tif, (uint16)info.nFrame))
|
||||||
|
cx_throw("Error: page not present in TIFF file");
|
||||||
|
|
||||||
|
//get image info
|
||||||
|
TIFFGetField(m_tif, TIFFTAG_IMAGEWIDTH, &width);
|
||||||
|
TIFFGetField(m_tif, TIFFTAG_IMAGELENGTH, &height);
|
||||||
|
TIFFGetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
|
||||||
|
TIFFGetField(m_tif, TIFFTAG_BITSPERSAMPLE, &bitspersample);
|
||||||
|
TIFFGetField(m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
|
||||||
|
TIFFGetField(m_tif, TIFFTAG_PHOTOMETRIC, &photometric);
|
||||||
|
TIFFGetField(m_tif, TIFFTAG_ORIENTATION, &orientation);
|
||||||
|
|
||||||
|
if (info.nEscape == -1) {
|
||||||
|
// Return output dimensions only
|
||||||
|
head.biWidth = width;
|
||||||
|
head.biHeight = height;
|
||||||
|
info.dwType = CXIMAGE_FORMAT_TIF;
|
||||||
|
cx_throw("output dimensions returned");
|
||||||
|
}
|
||||||
|
|
||||||
|
TIFFGetFieldDefaulted(m_tif, TIFFTAG_RESOLUTIONUNIT, &res_unit);
|
||||||
|
if (TIFFGetField(m_tif, TIFFTAG_XRESOLUTION, &resolution))
|
||||||
|
{
|
||||||
|
if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f);
|
||||||
|
SetXDPI((int32_t)resolution);
|
||||||
|
}
|
||||||
|
if (TIFFGetField(m_tif, TIFFTAG_YRESOLUTION, &resolution))
|
||||||
|
{
|
||||||
|
if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f);
|
||||||
|
SetYDPI((int32_t)resolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TIFFGetField(m_tif, TIFFTAG_XPOSITION, &offset)) info.xOffset = (int32_t)offset;
|
||||||
|
if (TIFFGetField(m_tif, TIFFTAG_YPOSITION, &offset)) info.yOffset = (int32_t)offset;
|
||||||
|
|
||||||
|
head.biClrUsed=0;
|
||||||
|
info.nBkgndIndex =-1;
|
||||||
|
|
||||||
|
if (rowsperstrip>height){
|
||||||
|
rowsperstrip=height;
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
|
||||||
|
}
|
||||||
|
|
||||||
|
isRGB = /*(bitspersample >= 8) && (VK: it is possible so for RGB to have < 8 bpp!)*/
|
||||||
|
(photometric == PHOTOMETRIC_RGB) ||
|
||||||
|
(photometric == PHOTOMETRIC_YCBCR) ||
|
||||||
|
(photometric == PHOTOMETRIC_SEPARATED) ||
|
||||||
|
(photometric == PHOTOMETRIC_LOGL) ||
|
||||||
|
(photometric == PHOTOMETRIC_LOGLUV);
|
||||||
|
|
||||||
|
if (isRGB){
|
||||||
|
head.biBitCount=24;
|
||||||
|
}else{
|
||||||
|
if ((photometric==PHOTOMETRIC_MINISBLACK)||(photometric==PHOTOMETRIC_MINISWHITE)||(photometric==PHOTOMETRIC_PALETTE)){
|
||||||
|
if (bitspersample == 1){
|
||||||
|
head.biBitCount=1; //B&W image
|
||||||
|
head.biClrUsed =2;
|
||||||
|
} else if (bitspersample == 4) {
|
||||||
|
head.biBitCount=4; //16 colors gray scale
|
||||||
|
head.biClrUsed =16;
|
||||||
|
} else {
|
||||||
|
head.biBitCount=8; //gray scale
|
||||||
|
head.biClrUsed =256;
|
||||||
|
}
|
||||||
|
} else if (bitspersample == 4) {
|
||||||
|
head.biBitCount=4; // 16 colors
|
||||||
|
head.biClrUsed=16;
|
||||||
|
} else {
|
||||||
|
head.biBitCount=8; //256 colors
|
||||||
|
head.biClrUsed=256;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((bitspersample > 8) && (photometric==PHOTOMETRIC_PALETTE)) // + VK + (BIG palette! => convert to RGB)
|
||||||
|
{ head.biBitCount=24;
|
||||||
|
head.biClrUsed =0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding
|
||||||
|
|
||||||
|
Create(width,height,head.biBitCount,CXIMAGE_FORMAT_TIF); //image creation
|
||||||
|
if (!pDib) cx_throw("CxImageTIF can't create image");
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (samplesperpixel==4) AlphaCreate(); //add alpha support for 32bpp tiffs
|
||||||
|
if (samplesperpixel==2 && bitspersample==8) AlphaCreate(); //add alpha support for 8bpp + alpha
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
|
||||||
|
TIFFGetField(m_tif, TIFFTAG_COMPRESSION, &compression);
|
||||||
|
SetCodecOption(compression); // <DPR> save original compression type
|
||||||
|
|
||||||
|
if (isRGB) {
|
||||||
|
// Read the whole image into one big RGBA buffer using
|
||||||
|
// the traditional TIFFReadRGBAImage() API that we trust.
|
||||||
|
uint32* raster; // retrieve RGBA image
|
||||||
|
uint32 *row;
|
||||||
|
|
||||||
|
raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32));
|
||||||
|
if (raster == NULL) cx_throw("No space for raster buffer");
|
||||||
|
|
||||||
|
// Read the image in one chunk into an RGBA array
|
||||||
|
if(!TIFFReadRGBAImage(m_tif, width, height, raster, 1)) {
|
||||||
|
_TIFFfree(raster);
|
||||||
|
cx_throw("Corrupted TIFF file!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the raster lines and save them in the DIB
|
||||||
|
// with RGB mode, we have to change the order of the 3 samples RGB
|
||||||
|
row = &raster[0];
|
||||||
|
bits2 = info.pImage;
|
||||||
|
for (y = 0; y < height; y++) {
|
||||||
|
|
||||||
|
if (info.nEscape){ // <vho> - cancel decoding
|
||||||
|
_TIFFfree(raster);
|
||||||
|
cx_throw("Cancelled");
|
||||||
|
}
|
||||||
|
|
||||||
|
bits = bits2;
|
||||||
|
for (x = 0; x < width; x++) {
|
||||||
|
*bits++ = (uint8_t)TIFFGetB(row[x]);
|
||||||
|
*bits++ = (uint8_t)TIFFGetG(row[x]);
|
||||||
|
*bits++ = (uint8_t)TIFFGetR(row[x]);
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (samplesperpixel==4) AlphaSet(x,y,(uint8_t)TIFFGetA(row[x]));
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
}
|
||||||
|
row += width;
|
||||||
|
bits2 += info.dwEffWidth;
|
||||||
|
}
|
||||||
|
_TIFFfree(raster);
|
||||||
|
} else {
|
||||||
|
int32_t BIG_palette = (bitspersample > 8) && // + VK
|
||||||
|
(photometric==PHOTOMETRIC_PALETTE);
|
||||||
|
if (BIG_palette && (bitspersample > 24)) // + VK
|
||||||
|
cx_throw("Too big palette to handle"); // + VK
|
||||||
|
|
||||||
|
RGBQUAD *pal;
|
||||||
|
pal=(RGBQUAD*)calloc(BIG_palette ? 1<<bitspersample : 256,sizeof(RGBQUAD));
|
||||||
|
// ! VK: it coasts nothing but more correct to use 256 as temp palette storage
|
||||||
|
// ! VK: but for case of BIG palette it just copied
|
||||||
|
if (pal==NULL) cx_throw("Unable to allocate TIFF palette");
|
||||||
|
|
||||||
|
int32_t bpp = bitspersample <= 8 ? bitspersample : 8; // + VK (to use instead of bitspersample for case of > 8)
|
||||||
|
|
||||||
|
// set up the colormap based on photometric
|
||||||
|
switch(photometric) {
|
||||||
|
case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types
|
||||||
|
case PHOTOMETRIC_MINISWHITE:
|
||||||
|
if (bitspersample == 1) { // Monochrome image
|
||||||
|
if (photometric == PHOTOMETRIC_MINISBLACK) {
|
||||||
|
pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
|
||||||
|
} else {
|
||||||
|
pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255;
|
||||||
|
}
|
||||||
|
} else { // need to build the scale for greyscale images
|
||||||
|
if (photometric == PHOTOMETRIC_MINISBLACK) {
|
||||||
|
for (int32_t i=0; i<(1<<bpp); i++){
|
||||||
|
pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (uint8_t)(i*(255/((1<<bpp)-1)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int32_t i=0; i<(1<<bpp); i++){
|
||||||
|
pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (uint8_t)(255-i*(255/((1<<bpp)-1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PHOTOMETRIC_PALETTE: // color map indexed
|
||||||
|
uint16 *red;
|
||||||
|
uint16 *green;
|
||||||
|
uint16 *blue;
|
||||||
|
TIFFGetField(m_tif, TIFFTAG_COLORMAP, &red, &green, &blue);
|
||||||
|
|
||||||
|
// Is the palette 16 or 8 bits ?
|
||||||
|
BOOL Palette16Bits = /*FALSE*/ BIG_palette;
|
||||||
|
if (!BIG_palette) {
|
||||||
|
int32_t n= 1<<bpp;
|
||||||
|
while (n-- > 0) {
|
||||||
|
if (red[n] >= 256 || green[n] >= 256 || blue[n] >= 256) {
|
||||||
|
Palette16Bits=TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the palette in the DIB
|
||||||
|
for (int32_t i = (1 << ( BIG_palette ? bitspersample : bpp )) - 1; i >= 0; i--) {
|
||||||
|
if (Palette16Bits) {
|
||||||
|
pal[i].rgbRed =(uint8_t) CVT(red[i]);
|
||||||
|
pal[i].rgbGreen = (uint8_t) CVT(green[i]);
|
||||||
|
pal[i].rgbBlue = (uint8_t) CVT(blue[i]);
|
||||||
|
} else {
|
||||||
|
pal[i].rgbRed = (uint8_t) red[i];
|
||||||
|
pal[i].rgbGreen = (uint8_t) green[i];
|
||||||
|
pal[i].rgbBlue = (uint8_t) blue[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!BIG_palette) { // + VK (BIG palette is stored until image is ready)
|
||||||
|
SetPalette(pal,/*head.biClrUsed*/ 1<<bpp); //palette assign // * VK
|
||||||
|
free(pal);
|
||||||
|
pal = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the tiff lines and save them in the DIB
|
||||||
|
uint32 nrow;
|
||||||
|
uint32 ys;
|
||||||
|
int32_t line = CalculateLine(width, bitspersample * samplesperpixel);
|
||||||
|
|
||||||
|
int32_t bitsize = TIFFStripSize(m_tif);
|
||||||
|
//verify bitsize: could be wrong if StripByteCounts is missing.
|
||||||
|
if (bitsize>(int32_t)(head.biSizeImage*samplesperpixel))
|
||||||
|
bitsize = head.biSizeImage*samplesperpixel;
|
||||||
|
if (bitsize<(int32_t)(info.dwEffWidth*rowsperstrip))
|
||||||
|
bitsize = info.dwEffWidth*rowsperstrip;
|
||||||
|
|
||||||
|
if ((bitspersample > 8) && (bitspersample != 16)) // + VK (for bitspersample == 9..15,17..32..64
|
||||||
|
bitsize *= (bitspersample + 7)/8;
|
||||||
|
|
||||||
|
int32_t tiled_image = TIFFIsTiled(m_tif);
|
||||||
|
uint32 tw=0, tl=0;
|
||||||
|
uint8_t* tilebuf=NULL;
|
||||||
|
if (tiled_image){
|
||||||
|
TIFFGetField(m_tif, TIFFTAG_TILEWIDTH, &tw);
|
||||||
|
TIFFGetField(m_tif, TIFFTAG_TILELENGTH, &tl);
|
||||||
|
rowsperstrip = tl;
|
||||||
|
bitsize = TIFFTileSize(m_tif) * (int32_t)(1+width/tw);
|
||||||
|
tilebuf = (uint8_t*)malloc(TIFFTileSize(m_tif));
|
||||||
|
}
|
||||||
|
|
||||||
|
bits = (uint8_t*)malloc(bitspersample==16? bitsize*2 : bitsize); // * VK
|
||||||
|
uint8_t * bits16 = NULL; // + VK
|
||||||
|
int32_t line16 = 0; // + VK
|
||||||
|
|
||||||
|
if (!tiled_image && bitspersample==16) { // + VK +
|
||||||
|
line16 = line;
|
||||||
|
line = CalculateLine(width, 8 * samplesperpixel);
|
||||||
|
bits16 = bits;
|
||||||
|
bits = (uint8_t*)malloc(bitsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bits==NULL){
|
||||||
|
if (bits16) free(bits16); // + VK
|
||||||
|
if (pal) free(pal); // + VK
|
||||||
|
if (tilebuf)free(tilebuf); // + VK
|
||||||
|
cx_throw("CxImageTIF can't allocate memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef FIX_16BPP_DARKIMG // + VK: for each line, store shift count bits used to fix it
|
||||||
|
uint8_t* row_shifts = NULL;
|
||||||
|
if (bits16) row_shifts = (uint8_t*)malloc(height);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (ys = 0; ys < height; ys += rowsperstrip) {
|
||||||
|
|
||||||
|
if (info.nEscape){ // <vho> - cancel decoding
|
||||||
|
free(bits);
|
||||||
|
cx_throw("Cancelled");
|
||||||
|
}
|
||||||
|
|
||||||
|
nrow = (ys + rowsperstrip > height ? height - ys : rowsperstrip);
|
||||||
|
|
||||||
|
if (tiled_image){
|
||||||
|
uint32 imagew = TIFFScanlineSize(m_tif);
|
||||||
|
uint32 tilew = TIFFTileRowSize(m_tif);
|
||||||
|
int32_t iskew = imagew - tilew;
|
||||||
|
uint8* bufp = (uint8*) bits;
|
||||||
|
|
||||||
|
uint32 colb = 0;
|
||||||
|
for (uint32 col = 0; col < width; col += tw) {
|
||||||
|
if (TIFFReadTile(m_tif, tilebuf, col, ys, 0, 0) < 0){
|
||||||
|
free(tilebuf);
|
||||||
|
free(bits);
|
||||||
|
cx_throw("Corrupted tiled TIFF file!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colb + tw > imagew) {
|
||||||
|
uint32 owidth = imagew - colb;
|
||||||
|
uint32 oskew = tilew - owidth;
|
||||||
|
TileToStrip(bufp + colb, tilebuf, nrow, owidth, oskew + iskew, oskew );
|
||||||
|
} else {
|
||||||
|
TileToStrip(bufp + colb, tilebuf, nrow, tilew, iskew, 0);
|
||||||
|
}
|
||||||
|
colb += tilew;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (TIFFReadEncodedStrip(m_tif, TIFFComputeStrip(m_tif, ys, 0),
|
||||||
|
(bits16? bits16 : bits), nrow * (bits16 ? line16 : line)) == -1) { // * VK
|
||||||
|
|
||||||
|
#ifdef NOT_IGNORE_CORRUPTED
|
||||||
|
free(bits);
|
||||||
|
if (bits16) free(bits16); // + VK
|
||||||
|
cx_throw("Corrupted TIFF file!");
|
||||||
|
#else
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (y = 0; y < nrow; y++) {
|
||||||
|
int32_t offset=(nrow-y-1)*line;
|
||||||
|
if ((bitspersample==16) && !BIG_palette) { // * VK
|
||||||
|
int32_t offset16 = (nrow-y-1)*line16; // + VK
|
||||||
|
if (bits16) { // + VK +
|
||||||
|
#ifdef FIX_16BPP_DARKIMG
|
||||||
|
int32_t the_shift;
|
||||||
|
uint8_t hi_byte, hi_max=0;
|
||||||
|
uint32_t xi;
|
||||||
|
for (xi=0;xi<(uint32)line;xi++) {
|
||||||
|
hi_byte = bits16[xi*2+offset16+1];
|
||||||
|
if(hi_byte>hi_max)
|
||||||
|
hi_max = hi_byte;
|
||||||
|
}
|
||||||
|
the_shift = (hi_max == 0) ? 8 : 0;
|
||||||
|
if (!the_shift)
|
||||||
|
while( ! (hi_max & 0x80) ) {
|
||||||
|
the_shift++;
|
||||||
|
hi_max <<= 1;
|
||||||
|
}
|
||||||
|
row_shifts[height-ys-nrow+y] = the_shift;
|
||||||
|
the_shift = 8 - the_shift;
|
||||||
|
for (xi=0;xi<(uint32)line;xi++)
|
||||||
|
bits[xi+offset]= ((bits16[xi*2+offset16+1]<<8) | bits16[xi*2+offset16]) >> the_shift;
|
||||||
|
#else
|
||||||
|
for (uint32_t xi=0;xi<(uint32)line;xi++)
|
||||||
|
bits[xi+offset]=bits16[xi*2+offset16+1];
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
for (uint32_t xi=0;xi<width;xi++)
|
||||||
|
bits[xi+offset]=bits[xi*2+offset+1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (samplesperpixel==1) {
|
||||||
|
if (BIG_palette)
|
||||||
|
if (bits16) {
|
||||||
|
int32_t offset16 = (nrow-y-1)*line16; // + VK
|
||||||
|
MoveBitsPal( info.pImage + info.dwEffWidth * (height-ys-nrow+y),
|
||||||
|
bits16 + offset16, width, bitspersample, pal );
|
||||||
|
} else
|
||||||
|
MoveBitsPal( info.pImage + info.dwEffWidth * (height-ys-nrow+y),
|
||||||
|
bits + offset, width, bitspersample, pal );
|
||||||
|
else if ((bitspersample == head.biBitCount) ||
|
||||||
|
(bitspersample == 16)) //simple 8bpp, 4bpp image or 16bpp
|
||||||
|
memcpy(info.pImage+info.dwEffWidth*(height-ys-nrow+y),bits+offset,min((unsigned)line, info.dwEffWidth));
|
||||||
|
else
|
||||||
|
MoveBits( info.pImage + info.dwEffWidth * (height-ys-nrow+y),
|
||||||
|
bits + offset, width, bitspersample );
|
||||||
|
} else if (samplesperpixel==2) { //8bpp image with alpha layer
|
||||||
|
int32_t xi=0;
|
||||||
|
int32_t ii=0;
|
||||||
|
int32_t yi=height-ys-nrow+y;
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (!pAlpha) AlphaCreate(); // + VK
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
while (ii<line){
|
||||||
|
SetPixelIndex(xi,yi,bits[ii+offset]);
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
AlphaSet(xi,yi,bits[ii+offset+1]);
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
ii+=2;
|
||||||
|
xi++;
|
||||||
|
if (xi>=(int32_t)width){
|
||||||
|
yi--;
|
||||||
|
xi=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { //photometric==PHOTOMETRIC_CIELAB
|
||||||
|
if (head.biBitCount!=24){ //fix image
|
||||||
|
Create(width,height,24,CXIMAGE_FORMAT_TIF);
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (samplesperpixel==4) AlphaCreate();
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t xi=0;
|
||||||
|
uint32 ii=0;
|
||||||
|
int32_t yi=height-ys-nrow+y;
|
||||||
|
RGBQUAD c;
|
||||||
|
int32_t l,a,b,bitsoffset;
|
||||||
|
double p,cx,cy,cz,cr,cg,cb;
|
||||||
|
while (ii</*line*/width){ // * VK
|
||||||
|
bitsoffset = ii*samplesperpixel+offset;
|
||||||
|
l=bits[bitsoffset];
|
||||||
|
a=bits[bitsoffset+1];
|
||||||
|
b=bits[bitsoffset+2];
|
||||||
|
if (a>127) a-=256;
|
||||||
|
if (b>127) b-=256;
|
||||||
|
// lab to xyz
|
||||||
|
p = (l/2.55 + 16) / 116.0;
|
||||||
|
cx = pow( p + a * 0.002, 3);
|
||||||
|
cy = pow( p, 3);
|
||||||
|
cz = pow( p - b * 0.005, 3);
|
||||||
|
// white point
|
||||||
|
cx*=0.95047;
|
||||||
|
//cy*=1.000;
|
||||||
|
cz*=1.0883;
|
||||||
|
// xyz to rgb
|
||||||
|
cr = 3.240479 * cx - 1.537150 * cy - 0.498535 * cz;
|
||||||
|
cg = -0.969256 * cx + 1.875992 * cy + 0.041556 * cz;
|
||||||
|
cb = 0.055648 * cx - 0.204043 * cy + 1.057311 * cz;
|
||||||
|
|
||||||
|
if ( cr > 0.00304 ) cr = 1.055 * pow(cr,0.41667) - 0.055;
|
||||||
|
else cr = 12.92 * cr;
|
||||||
|
if ( cg > 0.00304 ) cg = 1.055 * pow(cg,0.41667) - 0.055;
|
||||||
|
else cg = 12.92 * cg;
|
||||||
|
if ( cb > 0.00304 ) cb = 1.055 * pow(cb,0.41667) - 0.055;
|
||||||
|
else cb = 12.92 * cb;
|
||||||
|
|
||||||
|
c.rgbRed =(uint8_t)max(0,min(255,(int32_t)(cr*255)));
|
||||||
|
c.rgbGreen=(uint8_t)max(0,min(255,(int32_t)(cg*255)));
|
||||||
|
c.rgbBlue =(uint8_t)max(0,min(255,(int32_t)(cb*255)));
|
||||||
|
|
||||||
|
SetPixelColor(xi,yi,c);
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (samplesperpixel==4) AlphaSet(xi,yi,bits[bitsoffset+3]);
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
ii++;
|
||||||
|
xi++;
|
||||||
|
if (xi>=(int32_t)width){
|
||||||
|
yi--;
|
||||||
|
xi=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(bits);
|
||||||
|
if (bits16) free(bits16);
|
||||||
|
|
||||||
|
#ifdef FIX_16BPP_DARKIMG
|
||||||
|
if (row_shifts && (samplesperpixel == 1) && (bitspersample==16) && !BIG_palette) {
|
||||||
|
// 1. calculate maximum necessary shift
|
||||||
|
int32_t min_row_shift = 8;
|
||||||
|
for( y=0; y<height; y++ ) {
|
||||||
|
if (min_row_shift > row_shifts[y]) min_row_shift = row_shifts[y];
|
||||||
|
}
|
||||||
|
// 2. for rows having less shift value, correct such rows:
|
||||||
|
for( y=0; y<height; y++ ) {
|
||||||
|
if (min_row_shift < row_shifts[y]) {
|
||||||
|
int32_t need_shift = row_shifts[y] - min_row_shift;
|
||||||
|
uint8_t* data = info.pImage + info.dwEffWidth * y;
|
||||||
|
for( x=0; x<width; x++, data++ )
|
||||||
|
*data >>= need_shift;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (row_shifts) free( row_shifts );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (tiled_image) free(tilebuf);
|
||||||
|
if (pal) free(pal);
|
||||||
|
|
||||||
|
switch(orientation){
|
||||||
|
case ORIENTATION_TOPRIGHT: /* row 0 top, col 0 rhs */
|
||||||
|
Mirror();
|
||||||
|
break;
|
||||||
|
case ORIENTATION_BOTRIGHT: /* row 0 bottom, col 0 rhs */
|
||||||
|
Flip();
|
||||||
|
Mirror();
|
||||||
|
break;
|
||||||
|
case ORIENTATION_BOTLEFT: /* row 0 bottom, col 0 lhs */
|
||||||
|
Flip();
|
||||||
|
break;
|
||||||
|
case ORIENTATION_LEFTTOP: /* row 0 lhs, col 0 top */
|
||||||
|
RotateRight();
|
||||||
|
Mirror();
|
||||||
|
break;
|
||||||
|
case ORIENTATION_RIGHTTOP: /* row 0 rhs, col 0 top */
|
||||||
|
RotateLeft();
|
||||||
|
break;
|
||||||
|
case ORIENTATION_RIGHTBOT: /* row 0 rhs, col 0 bottom */
|
||||||
|
RotateLeft();
|
||||||
|
Mirror();
|
||||||
|
break;
|
||||||
|
case ORIENTATION_LEFTBOT: /* row 0 lhs, col 0 bottom */
|
||||||
|
RotateRight();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} cx_catch {
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
if (m_tif) TIFFClose(m_tif);
|
||||||
|
if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_TIF) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
TIFFClose(m_tif);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageTIF::Encode(CxFile * hFile, bool bAppend)
|
||||||
|
{
|
||||||
|
cx_try
|
||||||
|
{
|
||||||
|
if (hFile==NULL) cx_throw(CXIMAGE_ERR_NOFILE);
|
||||||
|
if (pDib==NULL) cx_throw(CXIMAGE_ERR_NOIMAGE);
|
||||||
|
|
||||||
|
// <RJ> replaced "w+b" with "a", to append an image directly on an existing file
|
||||||
|
if (m_tif2==NULL) m_tif2=_TIFFOpenEx(hFile, "a");
|
||||||
|
if (m_tif2==NULL) cx_throw("initialization fail");
|
||||||
|
|
||||||
|
if (bAppend || m_pages) m_multipage=true;
|
||||||
|
m_pages++;
|
||||||
|
|
||||||
|
if (!EncodeBody(m_tif2,m_multipage,m_pages,m_pages)) cx_throw("Error saving TIFF file");
|
||||||
|
if (bAppend) {
|
||||||
|
if (!TIFFWriteDirectory(m_tif2)) cx_throw("Error saving TIFF directory");
|
||||||
|
}
|
||||||
|
} cx_catch {
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
if (m_tif2){
|
||||||
|
TIFFClose(m_tif2);
|
||||||
|
m_tif2=NULL;
|
||||||
|
m_multipage=false;
|
||||||
|
m_pages=0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!bAppend){
|
||||||
|
TIFFClose(m_tif2);
|
||||||
|
m_tif2=NULL;
|
||||||
|
m_multipage=false;
|
||||||
|
m_pages=0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Thanks to Abe <God(dot)bless(at)marihuana(dot)com>
|
||||||
|
bool CxImageTIF::Encode(CxFile * hFile, CxImage ** pImages, int32_t pagecount)
|
||||||
|
{
|
||||||
|
cx_try
|
||||||
|
{
|
||||||
|
if (hFile==NULL) cx_throw("invalid file pointer");
|
||||||
|
if (pImages==NULL || pagecount<=0) cx_throw("multipage TIFF, no images!");
|
||||||
|
|
||||||
|
int32_t i;
|
||||||
|
for (i=0; i<pagecount; i++){
|
||||||
|
if (pImages[i]==NULL)
|
||||||
|
cx_throw("Bad image pointer");
|
||||||
|
if (!(pImages[i]->IsValid()))
|
||||||
|
cx_throw("Empty image");
|
||||||
|
}
|
||||||
|
|
||||||
|
CxImageTIF ghost;
|
||||||
|
for (i=0; i<pagecount; i++){
|
||||||
|
ghost.Ghost(pImages[i]);
|
||||||
|
if (!ghost.Encode(hFile,true)) cx_throw("Error saving TIFF file");
|
||||||
|
}
|
||||||
|
} cx_catch {
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageTIF::EncodeBody(TIFF *m_tif, bool multipage, int32_t page, int32_t pagecount)
|
||||||
|
{
|
||||||
|
uint32 height=head.biHeight;
|
||||||
|
uint32 width=head.biWidth;
|
||||||
|
uint16 bitcount=head.biBitCount;
|
||||||
|
uint16 bitspersample;
|
||||||
|
uint16 samplesperpixel;
|
||||||
|
uint16 photometric=0;
|
||||||
|
uint16 compression;
|
||||||
|
// uint16 pitch;
|
||||||
|
// int32_t line;
|
||||||
|
uint32 x, y;
|
||||||
|
|
||||||
|
samplesperpixel = ((bitcount == 24) || (bitcount == 32)) ? (uint8_t)3 : (uint8_t)1;
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (bitcount==24 && AlphaIsValid()) { bitcount=32; samplesperpixel=4; }
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
|
||||||
|
bitspersample = bitcount / samplesperpixel;
|
||||||
|
|
||||||
|
//set the PHOTOMETRIC tag
|
||||||
|
RGBQUAD *rgb = GetPalette();
|
||||||
|
switch (bitcount) {
|
||||||
|
case 1:
|
||||||
|
if (CompareColors(&rgb[0],&rgb[1])<0) {
|
||||||
|
/* <abe> some viewers do not handle PHOTOMETRIC_MINISBLACK:
|
||||||
|
* let's transform the image in PHOTOMETRIC_MINISWHITE
|
||||||
|
*/
|
||||||
|
//invert the colors
|
||||||
|
RGBQUAD tempRGB=GetPaletteColor(0);
|
||||||
|
SetPaletteColor(0,GetPaletteColor(1));
|
||||||
|
SetPaletteColor(1,tempRGB);
|
||||||
|
//invert the pixels
|
||||||
|
uint8_t *iSrc=info.pImage;
|
||||||
|
for (uint32_t i=0;i<head.biSizeImage;i++){
|
||||||
|
*iSrc=(uint8_t)~(*(iSrc));
|
||||||
|
iSrc++;
|
||||||
|
}
|
||||||
|
photometric = PHOTOMETRIC_MINISWHITE;
|
||||||
|
//photometric = PHOTOMETRIC_MINISBLACK;
|
||||||
|
} else {
|
||||||
|
photometric = PHOTOMETRIC_MINISWHITE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4: // Check if the DIB has a color or a greyscale palette
|
||||||
|
case 8:
|
||||||
|
photometric = PHOTOMETRIC_MINISBLACK; //default to gray scale
|
||||||
|
for (x = 0; x < head.biClrUsed; x++) {
|
||||||
|
if ((rgb->rgbRed != x)||(rgb->rgbRed != rgb->rgbGreen)||(rgb->rgbRed != rgb->rgbBlue)){
|
||||||
|
photometric = PHOTOMETRIC_PALETTE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rgb++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
case 32:
|
||||||
|
photometric = PHOTOMETRIC_RGB;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
if (AlphaIsValid() && bitcount==8) samplesperpixel=2; //8bpp + alpha layer
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
|
||||||
|
// line = CalculateLine(width, bitspersample * samplesperpixel);
|
||||||
|
// pitch = (uint16)CalculatePitch(line);
|
||||||
|
|
||||||
|
//prepare the palette struct
|
||||||
|
RGBQUAD pal[256];
|
||||||
|
if (GetPalette()){
|
||||||
|
uint8_t b;
|
||||||
|
memcpy(pal,GetPalette(),GetPaletteSize());
|
||||||
|
for(uint16_t a=0;a<head.biClrUsed;a++){ //swap blue and red components
|
||||||
|
b=pal[a].rgbBlue; pal[a].rgbBlue=pal[a].rgbRed; pal[a].rgbRed=b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle standard width/height/bpp stuff
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_IMAGEWIDTH, width);
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_IMAGELENGTH, height);
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_BITSPERSAMPLE, bitspersample);
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_PHOTOMETRIC, photometric);
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); // single image plane
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
|
||||||
|
|
||||||
|
uint32 rowsperstrip = TIFFDefaultStripSize(m_tif, (uint32) -1); //<REC> gives better compression
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
|
||||||
|
|
||||||
|
// handle metrics
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_XRESOLUTION, (float)info.xDPI);
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_YRESOLUTION, (float)info.yDPI);
|
||||||
|
// TIFFSetField(m_tif, TIFFTAG_XPOSITION, (float)info.xOffset);
|
||||||
|
// TIFFSetField(m_tif, TIFFTAG_YPOSITION, (float)info.yOffset);
|
||||||
|
|
||||||
|
// multi-paging - Thanks to Abe <God(dot)bless(at)marihuana(dot)com>
|
||||||
|
if (multipage)
|
||||||
|
{
|
||||||
|
char page_number[20];
|
||||||
|
sprintf(page_number, "Page %d", page);
|
||||||
|
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_PAGENUMBER, page,pagecount);
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_PAGENAME, page_number);
|
||||||
|
} else {
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_SUBFILETYPE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// palettes (image colormaps are automatically scaled to 16-bits)
|
||||||
|
if (photometric == PHOTOMETRIC_PALETTE) {
|
||||||
|
uint16 *r, *g, *b;
|
||||||
|
r = (uint16 *) _TIFFmalloc(sizeof(uint16) * 3 * 256);
|
||||||
|
g = r + 256;
|
||||||
|
b = g + 256;
|
||||||
|
|
||||||
|
for (int32_t i = 255; i >= 0; i--) {
|
||||||
|
b[i] = (uint16)SCALE((uint16)pal[i].rgbRed);
|
||||||
|
g[i] = (uint16)SCALE((uint16)pal[i].rgbGreen);
|
||||||
|
r[i] = (uint16)SCALE((uint16)pal[i].rgbBlue);
|
||||||
|
}
|
||||||
|
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_COLORMAP, r, g, b);
|
||||||
|
_TIFFfree(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// compression
|
||||||
|
if (GetCodecOption(CXIMAGE_FORMAT_TIF)) {
|
||||||
|
compression = (uint16_t)GetCodecOption(CXIMAGE_FORMAT_TIF);
|
||||||
|
} else {
|
||||||
|
switch (bitcount) {
|
||||||
|
case 1 :
|
||||||
|
compression = COMPRESSION_CCITTFAX4;
|
||||||
|
break;
|
||||||
|
case 4 :
|
||||||
|
case 8 :
|
||||||
|
compression = COMPRESSION_LZW;
|
||||||
|
break;
|
||||||
|
case 24 :
|
||||||
|
case 32 :
|
||||||
|
compression = COMPRESSION_JPEG;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
compression = COMPRESSION_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_COMPRESSION, compression);
|
||||||
|
|
||||||
|
switch (compression) {
|
||||||
|
case COMPRESSION_JPEG:
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_JPEGQUALITY, GetJpegQuality());
|
||||||
|
TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, ((7+rowsperstrip)>>3)<<3);
|
||||||
|
break;
|
||||||
|
case COMPRESSION_LZW:
|
||||||
|
if (bitcount>=8) TIFFSetField(m_tif, TIFFTAG_PREDICTOR, 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the DIB lines from bottom to top and save them in the TIF
|
||||||
|
|
||||||
|
uint8_t *bits;
|
||||||
|
switch(bitcount) {
|
||||||
|
case 1 :
|
||||||
|
case 4 :
|
||||||
|
case 8 :
|
||||||
|
{
|
||||||
|
if (samplesperpixel==1){
|
||||||
|
bits = (uint8_t*)malloc(info.dwEffWidth);
|
||||||
|
if (!bits) return false;
|
||||||
|
for (y = 0; y < height; y++) {
|
||||||
|
memcpy(bits,info.pImage + (height - y - 1)*info.dwEffWidth,info.dwEffWidth);
|
||||||
|
if (TIFFWriteScanline(m_tif,bits, y, 0)==-1){
|
||||||
|
free(bits);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(bits);
|
||||||
|
}
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
else { //8bpp + alpha layer
|
||||||
|
bits = (uint8_t*)malloc(2*width);
|
||||||
|
if (!bits) return false;
|
||||||
|
for (y = 0; y < height; y++) {
|
||||||
|
for (x=0;x<width;x++){
|
||||||
|
bits[2*x]=BlindGetPixelIndex(x,height - y - 1);
|
||||||
|
bits[2*x+1]=AlphaGet(x,height - y - 1);
|
||||||
|
}
|
||||||
|
if (TIFFWriteScanline(m_tif,bits, y, 0)==-1) {
|
||||||
|
free(bits);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(bits);
|
||||||
|
}
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 24:
|
||||||
|
{
|
||||||
|
uint8_t *buffer = (uint8_t *)malloc(info.dwEffWidth);
|
||||||
|
if (!buffer) return false;
|
||||||
|
for (y = 0; y < height; y++) {
|
||||||
|
// get a pointer to the scanline
|
||||||
|
memcpy(buffer, info.pImage + (height - y - 1)*info.dwEffWidth, info.dwEffWidth);
|
||||||
|
// TIFFs store color data RGB instead of BGR
|
||||||
|
uint8_t *pBuf = buffer;
|
||||||
|
for (x = 0; x < width; x++) {
|
||||||
|
uint8_t tmp = pBuf[0];
|
||||||
|
pBuf[0] = pBuf[2];
|
||||||
|
pBuf[2] = tmp;
|
||||||
|
pBuf += 3;
|
||||||
|
}
|
||||||
|
// write the scanline to disc
|
||||||
|
if (TIFFWriteScanline(m_tif, buffer, y, 0)==-1){
|
||||||
|
free(buffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(buffer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 32 :
|
||||||
|
{
|
||||||
|
#if CXIMAGE_SUPPORT_ALPHA
|
||||||
|
uint8_t *buffer = (uint8_t *)malloc((info.dwEffWidth*4)/3);
|
||||||
|
if (!buffer) return false;
|
||||||
|
for (y = 0; y < height; y++) {
|
||||||
|
// get a pointer to the scanline
|
||||||
|
memcpy(buffer, info.pImage + (height - y - 1)*info.dwEffWidth, info.dwEffWidth);
|
||||||
|
// TIFFs store color data RGB instead of BGR
|
||||||
|
uint8_t *pSrc = buffer + 3 * width;
|
||||||
|
uint8_t *pDst = buffer + 4 * width;
|
||||||
|
for (x = 0; x < width; x++) {
|
||||||
|
pDst-=4;
|
||||||
|
pSrc-=3;
|
||||||
|
pDst[3] = AlphaGet(width-x-1,height-y-1);
|
||||||
|
pDst[2] = pSrc[0];
|
||||||
|
pDst[1] = pSrc[1];
|
||||||
|
pDst[0] = pSrc[2];
|
||||||
|
}
|
||||||
|
// write the scanline to disc
|
||||||
|
if (TIFFWriteScanline(m_tif, buffer, y, 0)==-1){
|
||||||
|
free(buffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(buffer);
|
||||||
|
#endif //CXIMAGE_SUPPORT_ALPHA
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImageTIF::TileToStrip(uint8* out, uint8* in, uint32 rows, uint32 cols, int32_t outskew, int32_t inskew)
|
||||||
|
{
|
||||||
|
while (rows-- > 0) {
|
||||||
|
uint32 j = cols;
|
||||||
|
while (j-- > 0)
|
||||||
|
*out++ = *in++;
|
||||||
|
out += outskew;
|
||||||
|
in += inskew;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TIFF* CxImageTIF::TIFFOpenEx(CxFile * hFile)
|
||||||
|
{
|
||||||
|
if (hFile) return _TIFFOpenEx(hFile, "rb");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImageTIF::TIFFCloseEx(TIFF* tif)
|
||||||
|
{
|
||||||
|
if (tif) TIFFClose(tif);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImageTIF::MoveBits( uint8_t* dest, uint8_t* from, int32_t count, int32_t bpp )
|
||||||
|
{ int32_t offbits = 0;
|
||||||
|
uint16 w;
|
||||||
|
uint32 d;
|
||||||
|
if (bpp <= 8) {
|
||||||
|
while (count-- > 0) {
|
||||||
|
if (offbits + bpp <= 8)
|
||||||
|
w = *from >> (8 - offbits - bpp);
|
||||||
|
else {
|
||||||
|
w = *from++ << (offbits + bpp - 8);
|
||||||
|
w |= *from >> (16 - offbits - bpp);
|
||||||
|
}
|
||||||
|
offbits += bpp;
|
||||||
|
if (offbits >= 8) {
|
||||||
|
offbits -= 8;
|
||||||
|
if (offbits == 0) from++;
|
||||||
|
}
|
||||||
|
*dest++ = (uint8_t)w & ((1 << bpp)-1);
|
||||||
|
}
|
||||||
|
} else if (bpp < 16) {
|
||||||
|
while (count-- > 0) {
|
||||||
|
d = (*from << 24) | (from[1]<<16) | (from[2]<<8) | from[3];
|
||||||
|
d >>= (24 - offbits);
|
||||||
|
*dest++ = (uint8_t) ( d );
|
||||||
|
offbits += bpp;
|
||||||
|
while (offbits >= 8) {
|
||||||
|
from++;
|
||||||
|
offbits -= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (bpp < 32) {
|
||||||
|
while (count-- > 0) {
|
||||||
|
d = (*from << 24) | (from[1]<<16) | (from[2]<<8) | from[3];
|
||||||
|
//d = *(uint32*)from;
|
||||||
|
*dest++ = (uint8_t) ( d >> (offbits + bpp - 8) );
|
||||||
|
offbits += bpp;
|
||||||
|
while (offbits >= 8) {
|
||||||
|
from++;
|
||||||
|
offbits -= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (count-- > 0) {
|
||||||
|
d = *(uint32*)from;
|
||||||
|
*dest++ = (uint8_t) (d >> 24);
|
||||||
|
from += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CxImageTIF::MoveBitsPal( uint8_t* dest, uint8_t*from, int32_t count, int32_t bpp, RGBQUAD* pal )
|
||||||
|
{ int32_t offbits = 0;
|
||||||
|
uint32 d;
|
||||||
|
uint16 palidx;
|
||||||
|
while (count-- > 0) {
|
||||||
|
d = (*from << 24) | ( *( from + 1 ) << 16 )
|
||||||
|
| ( *( from + 2 ) << 8 )
|
||||||
|
| ( *( from + 3 ) );
|
||||||
|
palidx = (uint16) (d >> (32 - offbits - bpp));
|
||||||
|
if (bpp < 16) {
|
||||||
|
palidx <<= 16-bpp;
|
||||||
|
palidx = (palidx >> 8) | (palidx <<8);
|
||||||
|
palidx >>= 16-bpp;
|
||||||
|
} else palidx = (palidx >> 8) | (palidx << 8);
|
||||||
|
*dest++ = pal[palidx].rgbBlue;
|
||||||
|
*dest++ = pal[palidx].rgbGreen;
|
||||||
|
*dest++ = pal[palidx].rgbRed;
|
||||||
|
offbits += bpp;
|
||||||
|
while (offbits >= 8) {
|
||||||
|
from++;
|
||||||
|
offbits -= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#endif // CXIMAGE_SUPPORT_TIF
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* File: ximatif.h
|
||||||
|
* Purpose: TIFF Image Class Loader and Writer
|
||||||
|
*/
|
||||||
|
/* ==========================================================
|
||||||
|
* CxImageTIF (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it
|
||||||
|
* For conditions of distribution and use, see copyright notice in ximage.h
|
||||||
|
*
|
||||||
|
* Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes
|
||||||
|
*
|
||||||
|
* Special thanks to Abe <God(dot)bless(at)marihuana(dot)com> for MultiPageTIFF code.
|
||||||
|
*
|
||||||
|
* LibTIFF is:
|
||||||
|
* Copyright (c) 1988-1997 Sam Leffler
|
||||||
|
* Copyright (c) 1991-1997 Silicon Graphics, Inc.
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(__ximatif_h)
|
||||||
|
#define __ximatif_h
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_TIF
|
||||||
|
|
||||||
|
#include "../tiff/tiffio.h"
|
||||||
|
|
||||||
|
class DLL_EXP CxImageTIF: public CxImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CxImageTIF(): CxImage(CXIMAGE_FORMAT_TIF) {m_tif2=NULL; m_multipage=false; m_pages=0;}
|
||||||
|
~CxImageTIF();
|
||||||
|
|
||||||
|
TIFF* TIFFOpenEx(CxFile * hFile);
|
||||||
|
void TIFFCloseEx(TIFF* tif);
|
||||||
|
|
||||||
|
// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_TIF);}
|
||||||
|
// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_TIF);}
|
||||||
|
bool Decode(CxFile * hFile);
|
||||||
|
bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
bool Encode(CxFile * hFile, bool bAppend=false);
|
||||||
|
bool Encode(CxFile * hFile, CxImage ** pImages, int32_t pagecount);
|
||||||
|
bool Encode(FILE *hFile, bool bAppend=false) { CxIOFile file(hFile); return Encode(&file,bAppend); }
|
||||||
|
bool Encode(FILE *hFile, CxImage ** pImages, int32_t pagecount)
|
||||||
|
{ CxIOFile file(hFile); return Encode(&file, pImages, pagecount); }
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void TileToStrip(uint8* out, uint8* in, uint32 rows, uint32 cols, int32_t outskew, int32_t inskew);
|
||||||
|
bool EncodeBody(TIFF *m_tif, bool multipage=false, int32_t page=0, int32_t pagecount=0);
|
||||||
|
TIFF *m_tif2;
|
||||||
|
bool m_multipage;
|
||||||
|
int32_t m_pages;
|
||||||
|
void MoveBits( uint8_t* dest, uint8_t* from, int32_t count, int32_t bpp );
|
||||||
|
void MoveBitsPal( uint8_t* dest, uint8_t*from, int32_t count, int32_t bpp, RGBQUAD* pal );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* File: ximawbmp.cpp
|
||||||
|
* Purpose: Platform Independent WBMP Image Class Loader and Writer
|
||||||
|
* 12/Jul/2002 Davide Pizzolato - www.xdp.it
|
||||||
|
* CxImage version 7.0.1 07/Jan/2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximawbmp.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_WBMP
|
||||||
|
|
||||||
|
#include "ximaiter.h"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageWBMP::Decode(CxFile *hFile)
|
||||||
|
{
|
||||||
|
if (hFile == NULL) return false;
|
||||||
|
|
||||||
|
WBMPHEADER wbmpHead;
|
||||||
|
|
||||||
|
cx_try
|
||||||
|
{
|
||||||
|
ReadOctet(hFile, &wbmpHead.Type);
|
||||||
|
|
||||||
|
uint32_t dat;
|
||||||
|
ReadOctet(hFile, &dat);
|
||||||
|
wbmpHead.FixHeader = (uint8_t)dat;
|
||||||
|
|
||||||
|
ReadOctet(hFile, &wbmpHead.ImageWidth);
|
||||||
|
ReadOctet(hFile, &wbmpHead.ImageHeight);
|
||||||
|
|
||||||
|
if (hFile->Eof())
|
||||||
|
cx_throw("Not a WBMP");
|
||||||
|
|
||||||
|
if (wbmpHead.Type != 0)
|
||||||
|
cx_throw("Unsupported WBMP type");
|
||||||
|
|
||||||
|
head.biWidth = wbmpHead.ImageWidth;
|
||||||
|
head.biHeight= wbmpHead.ImageHeight;
|
||||||
|
|
||||||
|
if (head.biWidth<=0 || head.biHeight<=0)
|
||||||
|
cx_throw("Corrupted WBMP");
|
||||||
|
|
||||||
|
if (info.nEscape == -1){
|
||||||
|
info.dwType = CXIMAGE_FORMAT_WBMP;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Create(head.biWidth, head.biHeight, 1, CXIMAGE_FORMAT_WBMP);
|
||||||
|
if (!IsValid()) cx_throw("WBMP Create failed");
|
||||||
|
SetGrayPalette();
|
||||||
|
|
||||||
|
int32_t linewidth=(head.biWidth+7)/8;
|
||||||
|
CImageIterator iter(this);
|
||||||
|
iter.Upset();
|
||||||
|
for (int32_t y=0; y < head.biHeight; y++){
|
||||||
|
hFile->Read(iter.GetRow(),linewidth,1);
|
||||||
|
iter.PrevRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
} cx_catch {
|
||||||
|
if (strcmp(message,"")) strncpy(info.szLastError,message,255);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageWBMP::ReadOctet(CxFile * hFile, uint32_t *data)
|
||||||
|
{
|
||||||
|
uint8_t c;
|
||||||
|
*data = 0;
|
||||||
|
do {
|
||||||
|
if (hFile->Eof()) return false;
|
||||||
|
c = (uint8_t)hFile->GetC();
|
||||||
|
*data <<= 7;
|
||||||
|
*data |= (c & 0x7F);
|
||||||
|
} while ((c&0x80)!=0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageWBMP::Encode(CxFile * hFile)
|
||||||
|
{
|
||||||
|
if (EncodeSafeCheck(hFile)) return false;
|
||||||
|
|
||||||
|
//check format limits
|
||||||
|
if (head.biBitCount!=1){
|
||||||
|
strcpy(info.szLastError,"Can't save this image as WBMP");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
WBMPHEADER wbmpHead;
|
||||||
|
wbmpHead.Type=0;
|
||||||
|
wbmpHead.FixHeader=0;
|
||||||
|
wbmpHead.ImageWidth=head.biWidth;
|
||||||
|
wbmpHead.ImageHeight=head.biHeight;
|
||||||
|
|
||||||
|
// Write the file header
|
||||||
|
hFile->PutC('\0');
|
||||||
|
hFile->PutC('\0');
|
||||||
|
WriteOctet(hFile,wbmpHead.ImageWidth);
|
||||||
|
WriteOctet(hFile,wbmpHead.ImageHeight);
|
||||||
|
// Write the pixels
|
||||||
|
int32_t linewidth=(wbmpHead.ImageWidth+7)/8;
|
||||||
|
CImageIterator iter(this);
|
||||||
|
iter.Upset();
|
||||||
|
for (uint32_t y=0; y < wbmpHead.ImageHeight; y++){
|
||||||
|
hFile->Write(iter.GetRow(),linewidth,1);
|
||||||
|
iter.PrevRow();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageWBMP::WriteOctet(CxFile * hFile, const uint32_t data)
|
||||||
|
{
|
||||||
|
int32_t ns = 0;
|
||||||
|
while (data>>(ns+7)) ns+=7;
|
||||||
|
while (ns>0){
|
||||||
|
if (!hFile->PutC(0x80 | (uint8_t)(data>>ns))) return false;
|
||||||
|
ns-=7;
|
||||||
|
}
|
||||||
|
if (!(hFile->PutC((uint8_t)(0x7F & data)))) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // CXIMAGE_SUPPORT_WBMP
|
||||||
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* File: ximawbmp.h
|
||||||
|
* Purpose: WBMP Image Class Loader and Writer
|
||||||
|
*/
|
||||||
|
/* ==========================================================
|
||||||
|
* CxImageWBMP (c) 12/Jul/2002 Davide Pizzolato - www.xdp.it
|
||||||
|
* For conditions of distribution and use, see copyright notice in ximage.h
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
#if !defined(__ximaWBMP_h)
|
||||||
|
#define __ximaWBMP_h
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_WBMP
|
||||||
|
|
||||||
|
class CxImageWBMP: public CxImage
|
||||||
|
{
|
||||||
|
#pragma pack(1)
|
||||||
|
typedef struct tagWbmpHeader
|
||||||
|
{
|
||||||
|
uint32_t Type; // 0
|
||||||
|
uint8_t FixHeader; // 0
|
||||||
|
uint32_t ImageWidth; // Image Width
|
||||||
|
uint32_t ImageHeight; // Image Height
|
||||||
|
} WBMPHEADER;
|
||||||
|
#pragma pack()
|
||||||
|
public:
|
||||||
|
CxImageWBMP(): CxImage(CXIMAGE_FORMAT_WBMP) {}
|
||||||
|
|
||||||
|
// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_WBMP);}
|
||||||
|
// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_WBMP);}
|
||||||
|
bool Decode(CxFile * hFile);
|
||||||
|
bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }
|
||||||
|
protected:
|
||||||
|
bool ReadOctet(CxFile * hFile, uint32_t *data);
|
||||||
|
|
||||||
|
public:
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
bool Encode(CxFile * hFile);
|
||||||
|
bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }
|
||||||
|
protected:
|
||||||
|
bool WriteOctet(CxFile * hFile, const uint32_t data);
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,483 @@
|
|||||||
|
/*
|
||||||
|
*********************************************************************
|
||||||
|
* File: ximawmf.cpp
|
||||||
|
* Purpose: Windows Metafile Class Loader and Writer
|
||||||
|
* Author: Volker Horch - vhorch@gmx.de
|
||||||
|
* created: 13-Jun-2002
|
||||||
|
*
|
||||||
|
* Note: If the code below works, i wrote it.
|
||||||
|
* If it doesn't work, i don't know who wrote it.
|
||||||
|
*********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*********************************************************************
|
||||||
|
Note by Author:
|
||||||
|
*********************************************************************
|
||||||
|
|
||||||
|
Metafile Formats:
|
||||||
|
=================
|
||||||
|
|
||||||
|
There are 2 kinds of Windows Metafiles:
|
||||||
|
- Standard Windows Metafile
|
||||||
|
- Placeable Windows Metafile
|
||||||
|
|
||||||
|
A StandardWindows Metafile looks like:
|
||||||
|
- Metafile Header (MEATAHEADER)
|
||||||
|
- Metafile Records
|
||||||
|
|
||||||
|
A Placeable Metafile looks like:
|
||||||
|
- Aldus Header (METAFILEHEADER)
|
||||||
|
- Metafile Header (METAHEADER)
|
||||||
|
- Metafile Records
|
||||||
|
|
||||||
|
The "Metafile Header" and the "Metafile Records" are the same
|
||||||
|
for both formats. However, the Standard Metafile does not contain any
|
||||||
|
information about the original dimensions or x/y ratio of the Metafile.
|
||||||
|
|
||||||
|
I decided, to allow only placeable Metafiles here. If you also want to
|
||||||
|
enable Standard Metafiles, you will have to guess the dimensions of
|
||||||
|
the image.
|
||||||
|
|
||||||
|
*********************************************************************
|
||||||
|
Limitations: see ximawmf.h
|
||||||
|
you may configure some stuff there
|
||||||
|
*********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ximawmf.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageWMF::Decode(CxFile *hFile, int32_t nForceWidth, int32_t nForceHeight)
|
||||||
|
{
|
||||||
|
if (hFile == NULL) return false;
|
||||||
|
|
||||||
|
HENHMETAFILE hMeta;
|
||||||
|
HDC hDC;
|
||||||
|
int32_t cx,cy;
|
||||||
|
|
||||||
|
//save the current position of the file
|
||||||
|
int32_t pos = hFile->Tell();
|
||||||
|
|
||||||
|
// Read the Metafile and convert to an Enhanced Metafile
|
||||||
|
METAFILEHEADER mfh;
|
||||||
|
hMeta = ConvertWmfFiletoEmf(hFile, &mfh);
|
||||||
|
if (hMeta) { // ok, it's a WMF
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// We use the original WMF size information, because conversion to
|
||||||
|
// EMF adjusts the Metafile to Full Screen or does not set rclBounds at all
|
||||||
|
// ENHMETAHEADER emh;
|
||||||
|
// uint32_t uRet;
|
||||||
|
// uRet = GetEnhMetaFileHeader(hMeta, // handle of enhanced metafile
|
||||||
|
// sizeof(ENHMETAHEADER), // size of buffer, in bytes
|
||||||
|
// &emh); // address of buffer to receive data
|
||||||
|
// if (!uRet){
|
||||||
|
// DeleteEnhMetaFile(hMeta);
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// // calculate size
|
||||||
|
// cx = emh.rclBounds.right - emh.rclBounds.left;
|
||||||
|
// cy = emh.rclBounds.bottom - emh.rclBounds.top;
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// calculate size
|
||||||
|
// scale the metafile (pixels/inch of metafile => pixels/inch of display)
|
||||||
|
// mfh.inch already checked to be <> 0
|
||||||
|
|
||||||
|
hDC = ::GetDC(0);
|
||||||
|
int32_t cx1 = ::GetDeviceCaps(hDC, LOGPIXELSX);
|
||||||
|
int32_t cy1 = ::GetDeviceCaps(hDC, LOGPIXELSY);
|
||||||
|
::ReleaseDC(0, hDC);
|
||||||
|
|
||||||
|
cx = (mfh.inch/2 + (mfh.bbox.right - mfh.bbox.left) * cx1) / mfh.inch;
|
||||||
|
cy = (mfh.inch/2 + (mfh.bbox.bottom - mfh.bbox.top) * cy1) / mfh.inch;
|
||||||
|
|
||||||
|
} else { // maybe it's an EMF...
|
||||||
|
|
||||||
|
hFile->Seek(pos,SEEK_SET);
|
||||||
|
|
||||||
|
ENHMETAHEADER emh;
|
||||||
|
hMeta = ConvertEmfFiletoEmf(hFile, &emh);
|
||||||
|
|
||||||
|
if (!hMeta){
|
||||||
|
strcpy(info.szLastError,"corrupted WMF");
|
||||||
|
return false; // definitively give up
|
||||||
|
}
|
||||||
|
|
||||||
|
// ok, it's an EMF; calculate canvas size
|
||||||
|
cx = emh.rclBounds.right - emh.rclBounds.left;
|
||||||
|
cy = emh.rclBounds.bottom - emh.rclBounds.top;
|
||||||
|
|
||||||
|
// alternative methods, sometime not so reliable... [DP]
|
||||||
|
//cx = emh.szlDevice.cx;
|
||||||
|
//cy = emh.szlDevice.cy;
|
||||||
|
//
|
||||||
|
//hDC = ::GetDC(0);
|
||||||
|
//float hscale = (float)GetDeviceCaps(hDC, HORZRES)/(100.0f * GetDeviceCaps(hDC, HORZSIZE));
|
||||||
|
//float vscale = (float)GetDeviceCaps(hDC, VERTRES)/(100.0f * GetDeviceCaps(hDC, VERTSIZE));
|
||||||
|
//::ReleaseDC(0, hDC);
|
||||||
|
//cx = (int32_t)((emh.rclFrame.right - emh.rclFrame.left) * hscale);
|
||||||
|
//cy = (int32_t)((emh.rclFrame.bottom - emh.rclFrame.top) * vscale);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.nEscape == -1) { // Check if cancelled
|
||||||
|
head.biWidth = cx;
|
||||||
|
head.biHeight= cy;
|
||||||
|
info.dwType = CXIMAGE_FORMAT_WMF;
|
||||||
|
DeleteEnhMetaFile(hMeta);
|
||||||
|
strcpy(info.szLastError,"output dimensions returned");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cx || !cy) {
|
||||||
|
DeleteEnhMetaFile(hMeta);
|
||||||
|
strcpy(info.szLastError,"empty WMF");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nForceWidth) cx=nForceWidth;
|
||||||
|
if (nForceHeight) cy=nForceHeight;
|
||||||
|
ShrinkMetafile(cx, cy); // !! Otherwise Bitmap may have bombastic size
|
||||||
|
|
||||||
|
HDC hDC0 = ::GetDC(0); // DC of screen
|
||||||
|
HBITMAP hBitmap = CreateCompatibleBitmap(hDC0, cx, cy); // has # colors of display
|
||||||
|
hDC = CreateCompatibleDC(hDC0); // memory dc compatible with screen
|
||||||
|
::ReleaseDC(0, hDC0); // don't need anymore. get rid of it.
|
||||||
|
|
||||||
|
if (hDC){
|
||||||
|
if (hBitmap){
|
||||||
|
RECT rc = {0,0,cx,cy};
|
||||||
|
int32_t bpp = ::GetDeviceCaps(hDC, BITSPIXEL);
|
||||||
|
|
||||||
|
HBITMAP hBitmapOld = (HBITMAP)SelectObject(hDC, hBitmap);
|
||||||
|
|
||||||
|
// clear out the entire bitmap with windows background
|
||||||
|
// because the MetaFile may not contain background information
|
||||||
|
uint32_t dwBack = XMF_COLOR_BACK;
|
||||||
|
#if XMF_SUPPORT_TRANSPARENCY
|
||||||
|
if (bpp == 24) dwBack = XMF_COLOR_TRANSPARENT;
|
||||||
|
#endif
|
||||||
|
uint32_t OldColor = SetBkColor(hDC, dwBack);
|
||||||
|
ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
|
||||||
|
SetBkColor(hDC, OldColor);
|
||||||
|
|
||||||
|
//retrieves optional palette entries from the specified enhanced metafile
|
||||||
|
PLOGPALETTE plogPal;
|
||||||
|
PBYTE pjTmp;
|
||||||
|
HPALETTE hPal;
|
||||||
|
int32_t iEntries = GetEnhMetaFilePaletteEntries(hMeta, 0, NULL);
|
||||||
|
if (iEntries) {
|
||||||
|
if ((plogPal = (PLOGPALETTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
|
||||||
|
sizeof(uint32_t) + sizeof(PALETTEENTRY)*iEntries )) == NULL) {
|
||||||
|
DeleteObject(hBitmap);
|
||||||
|
DeleteDC(hDC);
|
||||||
|
DeleteEnhMetaFile(hMeta);
|
||||||
|
strcpy(info.szLastError,"Cancelled");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
plogPal->palVersion = 0x300;
|
||||||
|
plogPal->palNumEntries = (uint16_t) iEntries;
|
||||||
|
pjTmp = (PBYTE) plogPal;
|
||||||
|
pjTmp += 4;
|
||||||
|
|
||||||
|
GetEnhMetaFilePaletteEntries(hMeta, iEntries, (PPALETTEENTRY)pjTmp);
|
||||||
|
hPal = CreatePalette(plogPal);
|
||||||
|
GlobalFree(plogPal);
|
||||||
|
|
||||||
|
SelectPalette(hDC, hPal, FALSE);
|
||||||
|
RealizePalette(hDC);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play the Metafile into Memory DC
|
||||||
|
BOOL bRet = PlayEnhMetaFile(hDC, // handle to a device context
|
||||||
|
hMeta, // handle to an enhanced metafile
|
||||||
|
&rc); // pointer to bounding rectangle
|
||||||
|
|
||||||
|
SelectObject(hDC, hBitmapOld);
|
||||||
|
DeleteEnhMetaFile(hMeta); // we are done with this one
|
||||||
|
|
||||||
|
if (info.nEscape) { // Check if cancelled
|
||||||
|
DeleteObject(hBitmap);
|
||||||
|
DeleteDC(hDC);
|
||||||
|
strcpy(info.szLastError,"Cancelled");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the Bitmap now has the image.
|
||||||
|
// Create our DIB and convert the DDB into DIB
|
||||||
|
if (!Create(cx, cy, bpp, CXIMAGE_FORMAT_WMF)) {
|
||||||
|
DeleteObject(hBitmap);
|
||||||
|
DeleteDC(hDC);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if XMF_SUPPORT_TRANSPARENCY
|
||||||
|
if (bpp == 24) {
|
||||||
|
RGBQUAD rgbTrans = { XMF_RGBQUAD_TRANSPARENT };
|
||||||
|
SetTransColor(rgbTrans);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// We're finally ready to get the DIB. Call the driver and let
|
||||||
|
// it party on our bitmap. It will fill in the color table,
|
||||||
|
// and bitmap bits of our global memory block.
|
||||||
|
bRet = GetDIBits(hDC, hBitmap, 0,
|
||||||
|
(uint32_t)cy, GetBits(), (LPBITMAPINFO)pDib, DIB_RGB_COLORS);
|
||||||
|
|
||||||
|
DeleteObject(hBitmap);
|
||||||
|
DeleteDC(hDC);
|
||||||
|
|
||||||
|
return (bRet!=0);
|
||||||
|
} else {
|
||||||
|
DeleteDC(hDC);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (hBitmap) DeleteObject(hBitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteEnhMetaFile(hMeta);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
Function: CheckMetafileHeader
|
||||||
|
Purpose: Check if the Metafileheader of a file is valid
|
||||||
|
**********************************************************************/
|
||||||
|
BOOL CxImageWMF::CheckMetafileHeader(METAFILEHEADER *metafileheader)
|
||||||
|
{
|
||||||
|
uint16_t *pw;
|
||||||
|
uint16_t cs;
|
||||||
|
int32_t i;
|
||||||
|
|
||||||
|
// check magic #
|
||||||
|
if (metafileheader->key != 0x9ac6cdd7L) return false;
|
||||||
|
|
||||||
|
// test checksum of header
|
||||||
|
pw = (uint16_t *)metafileheader;
|
||||||
|
cs = *pw;
|
||||||
|
pw++;
|
||||||
|
for (i = 0; i < 9; i++) {
|
||||||
|
cs ^= *pw;
|
||||||
|
pw++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cs != metafileheader->checksum) return false;
|
||||||
|
|
||||||
|
// check resolution
|
||||||
|
if ((metafileheader->inch <= 0) || (metafileheader->inch > 2540)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
Function: ConvertWmfFiletoEmf
|
||||||
|
Purpose: Converts a Windows Metafile into an Enhanced Metafile
|
||||||
|
**********************************************************************/
|
||||||
|
HENHMETAFILE CxImageWMF::ConvertWmfFiletoEmf(CxFile *fp, METAFILEHEADER *metafileheader)
|
||||||
|
{
|
||||||
|
HENHMETAFILE hMeta;
|
||||||
|
uint32_t lenFile;
|
||||||
|
uint32_t len;
|
||||||
|
uint8_t *p;
|
||||||
|
METAHEADER mfHeader;
|
||||||
|
uint32_t seekpos;
|
||||||
|
|
||||||
|
hMeta = 0;
|
||||||
|
|
||||||
|
// get length of the file
|
||||||
|
lenFile = fp->Size();
|
||||||
|
|
||||||
|
// a placeable metafile starts with a METAFILEHEADER
|
||||||
|
// read it and check metafileheader
|
||||||
|
len = fp->Read(metafileheader, 1, sizeof(METAFILEHEADER));
|
||||||
|
if (len < sizeof(METAFILEHEADER)) return (hMeta);
|
||||||
|
|
||||||
|
if (CheckMetafileHeader(metafileheader)) {
|
||||||
|
// This is a placeable metafile
|
||||||
|
// Convert the placeable format into something that can
|
||||||
|
// be used with GDI metafile functions
|
||||||
|
seekpos = sizeof(METAFILEHEADER);
|
||||||
|
} else {
|
||||||
|
// Not a placeable wmf. A windows metafile?
|
||||||
|
// at least not scaleable.
|
||||||
|
// we could try to convert, but would loose ratio. don't allow this
|
||||||
|
return (hMeta);
|
||||||
|
|
||||||
|
//metafileheader->bbox.right = ?;
|
||||||
|
//metafileheader->bbox.left = ?;
|
||||||
|
//metafileheader->bbox.bottom = ?;
|
||||||
|
//metafileheader->bbox.top = ?;
|
||||||
|
//metafileheader->inch = ?;
|
||||||
|
//
|
||||||
|
//seekpos = 0;
|
||||||
|
// fp->Seek(0, SEEK_SET); // rewind
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point we have a metaheader regardless of whether
|
||||||
|
// the metafile was a windows metafile or a placeable metafile
|
||||||
|
// so check to see if it is valid. There is really no good
|
||||||
|
// way to do this so just make sure that the mtType is either
|
||||||
|
// 1 or 2 (memory or disk file)
|
||||||
|
// in addition we compare the length of the METAHEADER against
|
||||||
|
// the length of the file. if filelength < len => no Metafile
|
||||||
|
|
||||||
|
len = fp->Read(&mfHeader, 1, sizeof(METAHEADER));
|
||||||
|
if (len < sizeof(METAHEADER)) return (hMeta);
|
||||||
|
|
||||||
|
if ((mfHeader.mtType != 1) && (mfHeader.mtType != 2)) return (hMeta);
|
||||||
|
|
||||||
|
// Length in Bytes from METAHEADER
|
||||||
|
len = mfHeader.mtSize * 2;
|
||||||
|
if (len > lenFile) return (hMeta);
|
||||||
|
|
||||||
|
// Allocate memory for the metafile bits
|
||||||
|
p = (uint8_t *)malloc(len);
|
||||||
|
if (!p) return (hMeta);
|
||||||
|
|
||||||
|
// seek back to METAHEADER and read all the stuff at once
|
||||||
|
fp->Seek(seekpos, SEEK_SET);
|
||||||
|
lenFile = fp->Read(p, 1, len);
|
||||||
|
if (lenFile != len) {
|
||||||
|
free(p);
|
||||||
|
return (hMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the following (commented code) works, but adjusts rclBound of the
|
||||||
|
// Enhanced Metafile to full screen.
|
||||||
|
// the METAFILEHEADER from above is needed to scale the image
|
||||||
|
|
||||||
|
// hMeta = SetWinMetaFileBits(len, p, NULL, NULL);
|
||||||
|
|
||||||
|
// scale the metafile (pixels/inch of metafile => pixels/inch of display)
|
||||||
|
|
||||||
|
METAFILEPICT mfp;
|
||||||
|
int32_t cx1, cy1;
|
||||||
|
HDC hDC;
|
||||||
|
|
||||||
|
hDC = ::GetDC(0);
|
||||||
|
cx1 = ::GetDeviceCaps(hDC, LOGPIXELSX);
|
||||||
|
cy1 = ::GetDeviceCaps(hDC, LOGPIXELSY);
|
||||||
|
|
||||||
|
memset(&mfp, 0, sizeof(mfp));
|
||||||
|
|
||||||
|
mfp.mm = MM_ANISOTROPIC;
|
||||||
|
mfp.xExt = 10000; //(metafileheader->bbox.right - metafileheader->bbox.left) * cx1 / metafileheader->inch;
|
||||||
|
mfp.yExt = 10000; //(metafileheader->bbox.bottom - metafileheader->bbox.top) * cy1 / metafileheader->inch;
|
||||||
|
mfp.hMF = 0;
|
||||||
|
|
||||||
|
// in MM_ANISOTROPIC mode xExt and yExt are in MM_HIENGLISH
|
||||||
|
// MM_HIENGLISH means: Each logical unit is converted to 0.001 inch
|
||||||
|
//mfp.xExt *= 1000;
|
||||||
|
//mfp.yExt *= 1000;
|
||||||
|
// ????
|
||||||
|
//int32_t k = 332800 / ::GetSystemMetrics(SM_CXSCREEN);
|
||||||
|
//mfp.xExt *= k; mfp.yExt *= k;
|
||||||
|
|
||||||
|
// fix for Win9x
|
||||||
|
while ((mfp.xExt < 6554) && (mfp.yExt < 6554))
|
||||||
|
{
|
||||||
|
mfp.xExt *= 10;
|
||||||
|
mfp.yExt *= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
hMeta = SetWinMetaFileBits(len, p, hDC, &mfp);
|
||||||
|
|
||||||
|
if (!hMeta){ //try 2nd conversion using a different mapping
|
||||||
|
mfp.mm = MM_TEXT;
|
||||||
|
hMeta = SetWinMetaFileBits(len, p, hDC, &mfp);
|
||||||
|
}
|
||||||
|
|
||||||
|
::ReleaseDC(0, hDC);
|
||||||
|
|
||||||
|
// Free Memory
|
||||||
|
free(p);
|
||||||
|
|
||||||
|
return (hMeta);
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
HENHMETAFILE CxImageWMF::ConvertEmfFiletoEmf(CxFile *pFile, ENHMETAHEADER *pemfh)
|
||||||
|
{
|
||||||
|
HENHMETAFILE hMeta;
|
||||||
|
int32_t iLen = pFile->Size();
|
||||||
|
|
||||||
|
// Check the header first: <km>
|
||||||
|
int32_t pos = pFile->Tell();
|
||||||
|
int32_t iLenRead = pFile->Read(pemfh, 1, sizeof(ENHMETAHEADER));
|
||||||
|
if (iLenRead < sizeof(ENHMETAHEADER)) return NULL;
|
||||||
|
if (pemfh->iType != EMR_HEADER) return NULL;
|
||||||
|
if (pemfh->dSignature != ENHMETA_SIGNATURE) return NULL;
|
||||||
|
//if (pemfh->nBytes != (uint32_t)iLen) return NULL;
|
||||||
|
pFile->Seek(pos,SEEK_SET);
|
||||||
|
|
||||||
|
uint8_t* pBuff = (uint8_t *)malloc(iLen);
|
||||||
|
if (!pBuff) return (FALSE);
|
||||||
|
|
||||||
|
// Read the Enhanced Metafile
|
||||||
|
iLenRead = pFile->Read(pBuff, 1, iLen);
|
||||||
|
if (iLenRead != iLen) {
|
||||||
|
free(pBuff);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make it a Memory Metafile
|
||||||
|
hMeta = SetEnhMetaFileBits(iLen, pBuff);
|
||||||
|
|
||||||
|
free(pBuff); // finished with this one
|
||||||
|
|
||||||
|
if (!hMeta) return NULL; // oops.
|
||||||
|
|
||||||
|
// Get the Enhanced Metafile Header
|
||||||
|
uint32_t uRet = GetEnhMetaFileHeader(hMeta, // handle of enhanced metafile
|
||||||
|
sizeof(ENHMETAHEADER), // size of buffer, in bytes
|
||||||
|
pemfh); // address of buffer to receive data
|
||||||
|
|
||||||
|
if (!uRet) {
|
||||||
|
DeleteEnhMetaFile(hMeta);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (hMeta);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif //CXIMAGE_SUPPORT_DECODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
bool CxImageWMF::Encode(CxFile * hFile)
|
||||||
|
{
|
||||||
|
if (hFile == NULL) return false;
|
||||||
|
strcpy(info.szLastError, "Save WMF not supported");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
Function: ShrinkMetafile
|
||||||
|
Purpose: Shrink the size of a metafile to be not larger than
|
||||||
|
the definition
|
||||||
|
**********************************************************************/
|
||||||
|
void CxImageWMF::ShrinkMetafile(int32_t &cx, int32_t &cy)
|
||||||
|
{
|
||||||
|
int32_t xScreen = XMF_MAXSIZE_CX;
|
||||||
|
int32_t yScreen = XMF_MAXSIZE_CY;
|
||||||
|
|
||||||
|
if (cx > xScreen){
|
||||||
|
cy = cy * xScreen / cx;
|
||||||
|
cx = xScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cy > yScreen){
|
||||||
|
cx = cx * yScreen / cy;
|
||||||
|
cy = yScreen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CIMAGE_SUPPORT_WMF
|
||||||
|
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
*********************************************************************
|
||||||
|
* File: ximawmf.h
|
||||||
|
* Purpose: Windows Metafile Class Loader and Writer
|
||||||
|
* Author: Volker Horch - vhorch@gmx.de
|
||||||
|
* created: 13-Jun-2002
|
||||||
|
*********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*********************************************************************
|
||||||
|
Notes by Author:
|
||||||
|
*********************************************************************
|
||||||
|
|
||||||
|
Limitations:
|
||||||
|
============
|
||||||
|
|
||||||
|
a) Transparency:
|
||||||
|
|
||||||
|
A Metafile is vector graphics, which has transparency by design.
|
||||||
|
This class always converts into a Bitmap format. Transparency is
|
||||||
|
supported, but there is no good way to find out, which parts
|
||||||
|
of the Metafile are transparent. There are two ways how we can
|
||||||
|
handle this:
|
||||||
|
|
||||||
|
- Clear the Background of the Bitmap with the background color
|
||||||
|
you like (i have used COLOR_WINDOW) and don't support transparency.
|
||||||
|
|
||||||
|
below #define XMF_SUPPORT_TRANSPARENCY 0
|
||||||
|
#define XMF_COLOR_BACK RGB(Background color you like)
|
||||||
|
|
||||||
|
- Clear the Background of the Bitmap with a very unusual color
|
||||||
|
(which one ?) and use this color as the transparent color
|
||||||
|
|
||||||
|
below #define XMF_SUPPORT_TRANSPARENCY 1
|
||||||
|
#define XMF_COLOR_TRANSPARENT_R ...
|
||||||
|
#define XMF_COLOR_TRANSPARENT_G ...
|
||||||
|
#define XMF_COLOR_TRANSPARENT_B ...
|
||||||
|
|
||||||
|
b) Resolution
|
||||||
|
|
||||||
|
Once we have converted the Metafile into a Bitmap and we zoom in
|
||||||
|
or out, the image may not look very good. If we still had the
|
||||||
|
original Metafile, zooming would produce good results always.
|
||||||
|
|
||||||
|
c) Size
|
||||||
|
|
||||||
|
Although the filesize of a Metafile may be very small, it might
|
||||||
|
produce a Bitmap with a bombastic size. Assume you have a Metafile
|
||||||
|
with an image size of 6000*4000, which contains just one Metafile
|
||||||
|
record ((e.g. a line from (0,0) to (6000, 4000)). The filesize
|
||||||
|
of this Metafile would be let's say 100kB. If we convert it to
|
||||||
|
a 6000*4000 Bitmap with 24 Bits/Pixes, the Bitmap would consume
|
||||||
|
about 68MB of memory.
|
||||||
|
|
||||||
|
I have choosen, to limit the size of the Bitmap to max.
|
||||||
|
screensize, to avoid memory problems.
|
||||||
|
|
||||||
|
If you want something else,
|
||||||
|
modify #define XMF_MAXSIZE_CX / XMF_MAXSIZE_CY below
|
||||||
|
|
||||||
|
*********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _XIMAWMF_H
|
||||||
|
#define _XIMAWMF_H
|
||||||
|
|
||||||
|
#include "ximage.h"
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS
|
||||||
|
|
||||||
|
class CxImageWMF: public CxImage
|
||||||
|
{
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
|
||||||
|
typedef struct tagRECT16
|
||||||
|
{
|
||||||
|
int16_t left;
|
||||||
|
int16_t top;
|
||||||
|
int16_t right;
|
||||||
|
int16_t bottom;
|
||||||
|
} RECT16;
|
||||||
|
|
||||||
|
// taken from Windos 3.11 SDK Documentation (Programmer's Reference Volume 4: Resources)
|
||||||
|
typedef struct tagMETAFILEHEADER
|
||||||
|
{
|
||||||
|
uint32_t key; // always 0x9ac6cdd7
|
||||||
|
uint16_t reserved1; // reserved = 0
|
||||||
|
RECT16 bbox; // bounding rectangle in metafile units as defined in "inch"
|
||||||
|
uint16_t inch; // number of metafile units per inch (should be < 1440)
|
||||||
|
uint32_t reserved2; // reserved = 0
|
||||||
|
uint16_t checksum; // sum of the first 10 WORDS (using XOR operator)
|
||||||
|
} METAFILEHEADER;
|
||||||
|
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
public:
|
||||||
|
CxImageWMF(): CxImage(CXIMAGE_FORMAT_WMF) { }
|
||||||
|
|
||||||
|
bool Decode(CxFile * hFile, int32_t nForceWidth=0, int32_t nForceHeight=0);
|
||||||
|
bool Decode(FILE *hFile, int32_t nForceWidth=0, int32_t nForceHeight=0)
|
||||||
|
{ CxIOFile file(hFile); return Decode(&file,nForceWidth,nForceHeight); }
|
||||||
|
|
||||||
|
#if CXIMAGE_SUPPORT_ENCODE
|
||||||
|
bool Encode(CxFile * hFile);
|
||||||
|
bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }
|
||||||
|
#endif // CXIMAGE_SUPPORT_ENCODE
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void ShrinkMetafile(int32_t &cx, int32_t &cy);
|
||||||
|
BOOL CheckMetafileHeader(METAFILEHEADER *pmetafileheader);
|
||||||
|
HENHMETAFILE ConvertWmfFiletoEmf(CxFile *pFile, METAFILEHEADER *pmetafileheader);
|
||||||
|
HENHMETAFILE ConvertEmfFiletoEmf(CxFile *pFile, ENHMETAHEADER *pemfh);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#define METAFILEKEY 0x9ac6cdd7L
|
||||||
|
|
||||||
|
// Background color definition (if no transparency). see Notes above
|
||||||
|
#define XMF_COLOR_BACK GetSysColor(COLOR_WINDOW)
|
||||||
|
// alternatives
|
||||||
|
//#define XMF_COLOR_BACK RGB(192, 192, 192) // lite gray
|
||||||
|
//#define XMF_COLOR_BACK RGB( 0, 0, 0) // black
|
||||||
|
//#define XMF_COLOR_BACK RGB(255, 255, 255) // white
|
||||||
|
|
||||||
|
|
||||||
|
// transparency support. see Notes above
|
||||||
|
#define XMF_SUPPORT_TRANSPARENCY 0
|
||||||
|
#define XMF_COLOR_TRANSPARENT_R 211
|
||||||
|
#define XMF_COLOR_TRANSPARENT_G 121
|
||||||
|
#define XMF_COLOR_TRANSPARENT_B 112
|
||||||
|
// don't change
|
||||||
|
#define XMF_COLOR_TRANSPARENT RGB (XMF_COLOR_TRANSPARENT_R, \
|
||||||
|
XMF_COLOR_TRANSPARENT_G, \
|
||||||
|
XMF_COLOR_TRANSPARENT_B)
|
||||||
|
// don't change
|
||||||
|
#define XMF_RGBQUAD_TRANSPARENT XMF_COLOR_TRANSPARENT_B, \
|
||||||
|
XMF_COLOR_TRANSPARENT_G, \
|
||||||
|
XMF_COLOR_TRANSPARENT_R, \
|
||||||
|
0
|
||||||
|
// max. size. see Notes above
|
||||||
|
// alternatives
|
||||||
|
//#define XMF_MAXSIZE_CX (GetSystemMetrics(SM_CXSCREEN)-10)
|
||||||
|
//#define XMF_MAXSIZE_CY (GetSystemMetrics(SM_CYSCREEN)-50)
|
||||||
|
//#define XMF_MAXSIZE_CX (2*GetSystemMetrics(SM_CXSCREEN)/3)
|
||||||
|
//#define XMF_MAXSIZE_CY (2*GetSystemMetrics(SM_CYSCREEN)/3)
|
||||||
|
#define XMF_MAXSIZE_CX 4000
|
||||||
|
#define XMF_MAXSIZE_CY 4000
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,125 @@
|
|||||||
|
#if !defined(__xiofile_h)
|
||||||
|
#define __xiofile_h
|
||||||
|
|
||||||
|
#include "xfile.h"
|
||||||
|
//#include <TCHAR.h>
|
||||||
|
|
||||||
|
class DLL_EXP CxIOFile : public CxFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CxIOFile(FILE* fp = NULL)
|
||||||
|
{
|
||||||
|
m_fp = fp;
|
||||||
|
m_bCloseFile = (bool)(fp==0);
|
||||||
|
}
|
||||||
|
|
||||||
|
~CxIOFile()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
bool Open(const TCHAR * filename, const TCHAR * mode)
|
||||||
|
{
|
||||||
|
if (m_fp) return false; // Can't re-open without closing first
|
||||||
|
|
||||||
|
m_fp = _tfopen(filename, mode);
|
||||||
|
if (!m_fp) return false;
|
||||||
|
|
||||||
|
m_bCloseFile = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
virtual bool Close()
|
||||||
|
{
|
||||||
|
int32_t iErr = 0;
|
||||||
|
if ( (m_fp) && (m_bCloseFile) ){
|
||||||
|
iErr = fclose(m_fp);
|
||||||
|
m_fp = NULL;
|
||||||
|
}
|
||||||
|
return (bool)(iErr==0);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
virtual size_t Read(void *buffer, size_t size, size_t count)
|
||||||
|
{
|
||||||
|
if (!m_fp) return 0;
|
||||||
|
return fread(buffer, size, count, m_fp);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
virtual size_t Write(const void *buffer, size_t size, size_t count)
|
||||||
|
{
|
||||||
|
if (!m_fp) return 0;
|
||||||
|
return fwrite(buffer, size, count, m_fp);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
virtual bool Seek(int32_t offset, int32_t origin)
|
||||||
|
{
|
||||||
|
if (!m_fp) return false;
|
||||||
|
return (bool)(fseek(m_fp, offset, origin) == 0);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
virtual int32_t Tell()
|
||||||
|
{
|
||||||
|
if (!m_fp) return 0;
|
||||||
|
return ftell(m_fp);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
virtual int32_t Size()
|
||||||
|
{
|
||||||
|
if (!m_fp) return -1;
|
||||||
|
int32_t pos,size;
|
||||||
|
pos = ftell(m_fp);
|
||||||
|
fseek(m_fp, 0, SEEK_END);
|
||||||
|
size = ftell(m_fp);
|
||||||
|
fseek(m_fp, pos,SEEK_SET);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
virtual bool Flush()
|
||||||
|
{
|
||||||
|
if (!m_fp) return false;
|
||||||
|
return (bool)(fflush(m_fp) == 0);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
virtual bool Eof()
|
||||||
|
{
|
||||||
|
if (!m_fp) return true;
|
||||||
|
return (bool)(feof(m_fp) != 0);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
virtual int32_t Error()
|
||||||
|
{
|
||||||
|
if (!m_fp) return -1;
|
||||||
|
return ferror(m_fp);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
virtual bool PutC(uint8_t c)
|
||||||
|
{
|
||||||
|
if (!m_fp) return false;
|
||||||
|
return (bool)(fputc(c, m_fp) == c);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
virtual int32_t GetC()
|
||||||
|
{
|
||||||
|
if (!m_fp) return EOF;
|
||||||
|
return getc(m_fp);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
virtual char * GetS(char *string, int32_t n)
|
||||||
|
{
|
||||||
|
if (!m_fp) return NULL;
|
||||||
|
return fgets(string,n,m_fp);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
virtual int32_t Scanf(const char *format, void* output)
|
||||||
|
{
|
||||||
|
if (!m_fp) return EOF;
|
||||||
|
return fscanf(m_fp, format, output);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
protected:
|
||||||
|
FILE *m_fp;
|
||||||
|
bool m_bCloseFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,213 @@
|
|||||||
|
#include "xmemfile.h"
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
CxMemFile::CxMemFile(uint8_t* pBuffer, uint32_t size)
|
||||||
|
{
|
||||||
|
m_pBuffer = pBuffer;
|
||||||
|
m_Position = 0;
|
||||||
|
m_Size = m_Edge = size;
|
||||||
|
m_bFreeOnClose = (bool)(pBuffer==0);
|
||||||
|
m_bEOF = false;
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
CxMemFile::~CxMemFile()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
bool CxMemFile::Close()
|
||||||
|
{
|
||||||
|
if ( (m_pBuffer) && (m_bFreeOnClose) ){
|
||||||
|
free(m_pBuffer);
|
||||||
|
m_pBuffer = NULL;
|
||||||
|
m_Size = 0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
bool CxMemFile::Open()
|
||||||
|
{
|
||||||
|
if (m_pBuffer) return false; // Can't re-open without closing first
|
||||||
|
|
||||||
|
m_Position = m_Size = m_Edge = 0;
|
||||||
|
m_pBuffer=(uint8_t*)malloc(1);
|
||||||
|
m_bFreeOnClose = true;
|
||||||
|
|
||||||
|
return (m_pBuffer!=0);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
uint8_t* CxMemFile::GetBuffer(bool bDetachBuffer)
|
||||||
|
{
|
||||||
|
//can only detach, avoid inadvertantly attaching to
|
||||||
|
// memory that may not be ours [Jason De Arte]
|
||||||
|
if( bDetachBuffer )
|
||||||
|
m_bFreeOnClose = false;
|
||||||
|
return m_pBuffer;
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
size_t CxMemFile::Read(void *buffer, size_t size, size_t count)
|
||||||
|
{
|
||||||
|
if (buffer==NULL) return 0;
|
||||||
|
|
||||||
|
if (m_pBuffer==NULL) return 0;
|
||||||
|
if (m_Position >= (int32_t)m_Size){
|
||||||
|
m_bEOF = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t nCount = (int32_t)(count*size);
|
||||||
|
if (nCount == 0) return 0;
|
||||||
|
|
||||||
|
int32_t nRead;
|
||||||
|
if (m_Position + nCount > (int32_t)m_Size){
|
||||||
|
m_bEOF = true;
|
||||||
|
nRead = (m_Size - m_Position);
|
||||||
|
} else
|
||||||
|
nRead = nCount;
|
||||||
|
|
||||||
|
memcpy(buffer, m_pBuffer + m_Position, nRead);
|
||||||
|
m_Position += nRead;
|
||||||
|
|
||||||
|
return (size_t)(nRead/size);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
size_t CxMemFile::Write(const void *buffer, size_t size, size_t count)
|
||||||
|
{
|
||||||
|
m_bEOF = false;
|
||||||
|
if (m_pBuffer==NULL) return 0;
|
||||||
|
if (buffer==NULL) return 0;
|
||||||
|
|
||||||
|
int32_t nCount = (int32_t)(count*size);
|
||||||
|
if (nCount == 0) return 0;
|
||||||
|
|
||||||
|
if (m_Position + nCount > m_Edge){
|
||||||
|
if (!Alloc(m_Position + nCount)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(m_pBuffer + m_Position, buffer, nCount);
|
||||||
|
|
||||||
|
m_Position += nCount;
|
||||||
|
|
||||||
|
if (m_Position > (int32_t)m_Size) m_Size = m_Position;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
bool CxMemFile::Seek(int32_t offset, int32_t origin)
|
||||||
|
{
|
||||||
|
m_bEOF = false;
|
||||||
|
if (m_pBuffer==NULL) return false;
|
||||||
|
int32_t lNewPos = m_Position;
|
||||||
|
|
||||||
|
if (origin == SEEK_SET) lNewPos = offset;
|
||||||
|
else if (origin == SEEK_CUR) lNewPos += offset;
|
||||||
|
else if (origin == SEEK_END) lNewPos = m_Size + offset;
|
||||||
|
else return false;
|
||||||
|
|
||||||
|
if (lNewPos < 0) lNewPos = 0;
|
||||||
|
|
||||||
|
m_Position = lNewPos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
int32_t CxMemFile::Tell()
|
||||||
|
{
|
||||||
|
if (m_pBuffer==NULL) return -1;
|
||||||
|
return m_Position;
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
int32_t CxMemFile::Size()
|
||||||
|
{
|
||||||
|
if (m_pBuffer==NULL) return -1;
|
||||||
|
return m_Size;
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
bool CxMemFile::Flush()
|
||||||
|
{
|
||||||
|
if (m_pBuffer==NULL) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
bool CxMemFile::Eof()
|
||||||
|
{
|
||||||
|
if (m_pBuffer==NULL) return true;
|
||||||
|
return m_bEOF;
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
int32_t CxMemFile::Error()
|
||||||
|
{
|
||||||
|
if (m_pBuffer==NULL) return -1;
|
||||||
|
return (m_Position > (int32_t)m_Size);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
bool CxMemFile::PutC(uint8_t c)
|
||||||
|
{
|
||||||
|
m_bEOF = false;
|
||||||
|
if (m_pBuffer==NULL) return false;
|
||||||
|
|
||||||
|
if (m_Position >= m_Edge){
|
||||||
|
if (!Alloc(m_Position + 1)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pBuffer[m_Position++] = c;
|
||||||
|
|
||||||
|
if (m_Position > (int32_t)m_Size) m_Size = m_Position;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
int32_t CxMemFile::GetC()
|
||||||
|
{
|
||||||
|
if (m_pBuffer==NULL || m_Position >= (int32_t)m_Size){
|
||||||
|
m_bEOF = true;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
return *(uint8_t*)((uint8_t*)m_pBuffer + m_Position++);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
char * CxMemFile::GetS(char *string, int32_t n)
|
||||||
|
{
|
||||||
|
n--;
|
||||||
|
int32_t c,i=0;
|
||||||
|
while (i<n){
|
||||||
|
c = GetC();
|
||||||
|
if (c == EOF) return 0;
|
||||||
|
string[i++] = (char)c;
|
||||||
|
if (c == '\n') break;
|
||||||
|
}
|
||||||
|
string[i] = 0;
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
int32_t CxMemFile::Scanf(const char *format, void* output)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
bool CxMemFile::Alloc(uint32_t dwNewLen)
|
||||||
|
{
|
||||||
|
if (dwNewLen > (uint32_t)m_Edge)
|
||||||
|
{
|
||||||
|
// find new buffer size
|
||||||
|
uint32_t dwNewBufferSize = (uint32_t)(((dwNewLen>>16)+1)<<16);
|
||||||
|
|
||||||
|
// allocate new buffer
|
||||||
|
if (m_pBuffer == NULL) m_pBuffer = (uint8_t*)malloc(dwNewBufferSize);
|
||||||
|
else m_pBuffer = (uint8_t*)realloc(m_pBuffer, dwNewBufferSize);
|
||||||
|
// I own this buffer now (caller knows nothing about it)
|
||||||
|
m_bFreeOnClose = true;
|
||||||
|
|
||||||
|
m_Edge = dwNewBufferSize;
|
||||||
|
}
|
||||||
|
return (m_pBuffer!=0);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
void CxMemFile::Free()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#if !defined(__xmemfile_h)
|
||||||
|
#define __xmemfile_h
|
||||||
|
|
||||||
|
#include "xfile.h"
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
class DLL_EXP CxMemFile : public CxFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CxMemFile(uint8_t* pBuffer = NULL, uint32_t size = 0);
|
||||||
|
~CxMemFile();
|
||||||
|
|
||||||
|
bool Open();
|
||||||
|
uint8_t* GetBuffer(bool bDetachBuffer = true);
|
||||||
|
|
||||||
|
virtual bool Close();
|
||||||
|
virtual size_t Read(void *buffer, size_t size, size_t count);
|
||||||
|
virtual size_t Write(const void *buffer, size_t size, size_t count);
|
||||||
|
virtual bool Seek(int32_t offset, int32_t origin);
|
||||||
|
virtual int32_t Tell();
|
||||||
|
virtual int32_t Size();
|
||||||
|
virtual bool Flush();
|
||||||
|
virtual bool Eof();
|
||||||
|
virtual int32_t Error();
|
||||||
|
virtual bool PutC(uint8_t c);
|
||||||
|
virtual int32_t GetC();
|
||||||
|
virtual char * GetS(char *string, int32_t n);
|
||||||
|
virtual int32_t Scanf(const char *format, void* output);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool Alloc(uint32_t nBytes);
|
||||||
|
void Free();
|
||||||
|
|
||||||
|
uint8_t* m_pBuffer;
|
||||||
|
uint32_t m_Size;
|
||||||
|
bool m_bFreeOnClose;
|
||||||
|
int32_t m_Position; //current position
|
||||||
|
int32_t m_Edge; //buffer size
|
||||||
|
bool m_bEOF;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 9.0 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
Binary file not shown.
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
// stdafx.cpp : 표준 포함 파일만 들어 있는 소스 파일입니다.
|
||||||
|
// Raw2Bmp_MFC.pch는 미리 컴파일된 헤더가 됩니다.
|
||||||
|
// stdafx.obj에는 미리 컴파일된 형식 정보가 포함됩니다.
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
|
||||||
|
// stdafx.h : 자주 사용하지만 자주 변경되지는 않는
|
||||||
|
// 표준 시스템 포함 파일 및 프로젝트 관련 포함 파일이
|
||||||
|
// 들어 있는 포함 파일입니다.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef _SECURE_ATL
|
||||||
|
#define _SECURE_ATL 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef VC_EXTRALEAN
|
||||||
|
#define VC_EXTRALEAN // 거의 사용되지 않는 내용은 Windows 헤더에서 제외합니다.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "targetver.h"
|
||||||
|
|
||||||
|
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 일부 CString 생성자는 명시적으로 선언됩니다.
|
||||||
|
|
||||||
|
// MFC의 공통 부분과 무시 가능한 경고 메시지에 대한 숨기기를 해제합니다.
|
||||||
|
#define _AFX_ALL_WARNINGS
|
||||||
|
|
||||||
|
#include <afxwin.h> // MFC 핵심 및 표준 구성 요소입니다.
|
||||||
|
#include <afxext.h> // MFC 확장입니다.
|
||||||
|
|
||||||
|
|
||||||
|
#include <afxdisp.h> // MFC 자동화 클래스입니다.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _AFX_NO_OLE_SUPPORT
|
||||||
|
#include <afxdtctl.h> // Internet Explorer 4 공용 컨트롤에 대한 MFC 지원입니다.
|
||||||
|
#endif
|
||||||
|
#ifndef _AFX_NO_AFXCMN_SUPPORT
|
||||||
|
#include <afxcmn.h> // Windows 공용 컨트롤에 대한 MFC 지원입니다.
|
||||||
|
#endif // _AFX_NO_AFXCMN_SUPPORT
|
||||||
|
|
||||||
|
#include <afxcontrolbars.h> // MFC의 리본 및 컨트롤 막대 지원
|
||||||
|
|
||||||
|
|
||||||
|
#include <afxsock.h> // MFC 소켓 확장
|
||||||
|
|
||||||
|
|
||||||
|
#pragma comment (lib, "cximage.lib")
|
||||||
|
#pragma comment (lib, "Jpeg.lib")
|
||||||
|
#pragma comment (lib, "png.lib")
|
||||||
|
#pragma comment (lib, "mng.lib")
|
||||||
|
#pragma comment (lib, "Tiff.lib")
|
||||||
|
#pragma comment (lib, "zlib.lib")
|
||||||
|
#pragma comment (lib, "jasper.lib")
|
||||||
|
#pragma comment (lib, "libdcr.lib")
|
||||||
|
#pragma comment (lib, "libpsd.lib")
|
||||||
|
#pragma comment (lib, "jbig.lib")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _UNICODE
|
||||||
|
#if defined _M_IX86
|
||||||
|
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
||||||
|
#elif defined _M_X64
|
||||||
|
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
||||||
|
#else
|
||||||
|
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// 포함 SDKDDKVer.h는 사용 가능한 Windows 플랫폼 중 버전이 가장 높은 플랫폼을 정의합니다.
|
||||||
|
|
||||||
|
// 이전 Windows 플랫폼에 대해 응용 프로그램을 빌드하려는 경우에는 SDKDDKVer.h를 포함하기 전에
|
||||||
|
// WinSDKVer.h를 포함하고 _WIN32_WINNT 매크로를 지원하려는 플랫폼으로 설정하십시오.
|
||||||
|
|
||||||
|
#include <SDKDDKVer.h>
|
||||||
Reference in New Issue
Block a user