parent
640247c7a1
commit
cc87de8088
21 changed files with 9370 additions and 0 deletions
@ -0,0 +1,2 @@ |
|||||||
|
build* |
||||||
|
CMakeLists.txt.user |
@ -0,0 +1,26 @@ |
|||||||
|
# |
||||||
|
# Copyright (c) 2010-2019 by Gilles Caulier, <caulier dot gilles at gmail dot com> |
||||||
|
# Copyright (c) 2015 by Veaceslav Munteanu, <veaceslav dot munteanu90 at gmail dot com> |
||||||
|
# |
||||||
|
# Redistribution and use is allowed according to the terms of the BSD license. |
||||||
|
# For details see the accompanying COPYING-CMAKE-SCRIPTS file. |
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.1.0) |
||||||
|
set(CMAKE_CXX_STANDARD 14) |
||||||
|
project(pgfutils) |
||||||
|
|
||||||
|
find_package (Qt5 COMPONENTS Core Gui REQUIRED) |
||||||
|
|
||||||
|
set(libpgfutils_SRCS |
||||||
|
pgfutils.cpp |
||||||
|
libpgf/Decoder.cpp |
||||||
|
libpgf/Encoder.cpp |
||||||
|
libpgf/PGFimage.cpp |
||||||
|
libpgf/PGFstream.cpp |
||||||
|
libpgf/Subband.cpp |
||||||
|
libpgf/WaveletTransform.cpp |
||||||
|
) |
||||||
|
|
||||||
|
add_library(pgfutils ${libpgfutils_SRCS}) |
||||||
|
target_link_libraries(pgfutils Qt5::Core Qt5::Gui) |
||||||
|
target_include_directories(pgfutils PUBLIC libpgf) |
@ -0,0 +1 @@ |
|||||||
|
ADAPTED FROM DIGIKAM pgfutils @ 33d0457 |
@ -0,0 +1,341 @@ |
|||||||
|
/*
|
||||||
|
* The Progressive Graphics File; http://www.libpgf.org
|
||||||
|
*
|
||||||
|
* $Date: 2006-06-04 22:05:59 +0200 (So, 04 Jun 2006) $ |
||||||
|
* $Revision: 229 $ |
||||||
|
*
|
||||||
|
* This file Copyright (C) 2006 xeraina GmbH, Switzerland |
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE |
||||||
|
* as published by the Free Software Foundation; either version 2.1 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||||
|
*/ |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// @file Bitstream.h
|
||||||
|
/// @brief PGF bit-stream operations
|
||||||
|
/// @author C. Stamm
|
||||||
|
|
||||||
|
#ifndef PGF_BITSTREAM_H |
||||||
|
#define PGF_BITSTREAM_H |
||||||
|
|
||||||
|
#include "PGFtypes.h" |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// constants
|
||||||
|
//static const WordWidth = 32;
|
||||||
|
//static const WordWidthLog = 5;
|
||||||
|
static const UINT32 Filled = 0xFFFFFFFF; |
||||||
|
|
||||||
|
/// @brief Make 64 bit unsigned integer from two 32 bit unsigned integers
|
||||||
|
#define MAKEU64(a, b) ((UINT64) (((UINT32) (a)) | ((UINT64) ((UINT32) (b))) << 32)) |
||||||
|
|
||||||
|
/*
|
||||||
|
static UINT8 lMask[] = { |
||||||
|
0x00, // 00000000
|
||||||
|
0x80, // 10000000
|
||||||
|
0xc0, // 11000000
|
||||||
|
0xe0, // 11100000
|
||||||
|
0xf0, // 11110000
|
||||||
|
0xf8, // 11111000
|
||||||
|
0xfc, // 11111100
|
||||||
|
0xfe, // 11111110
|
||||||
|
0xff, // 11111111
|
||||||
|
}; |
||||||
|
*/ |
||||||
|
// these procedures have to be inlined because of performance reasons
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Set one bit of a bit stream to 1
|
||||||
|
/// @param stream A bit stream stored in array of unsigned integers
|
||||||
|
/// @param pos A valid zero-based position in the bit stream
|
||||||
|
inline void SetBit(UINT32* stream, UINT32 pos) { |
||||||
|
stream[pos >> WordWidthLog] |= (1 << (pos%WordWidth)); |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Set one bit of a bit stream to 0
|
||||||
|
/// @param stream A bit stream stored in array of unsigned integers
|
||||||
|
/// @param pos A valid zero-based position in the bit stream
|
||||||
|
inline void ClearBit(UINT32* stream, UINT32 pos) { |
||||||
|
stream[pos >> WordWidthLog] &= ~(1 << (pos%WordWidth));
|
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return one bit of a bit stream
|
||||||
|
/// @param stream A bit stream stored in array of unsigned integers
|
||||||
|
/// @param pos A valid zero-based position in the bit stream
|
||||||
|
/// @return bit at position pos of bit stream stream
|
||||||
|
inline bool GetBit(UINT32* stream, UINT32 pos) { |
||||||
|
return (stream[pos >> WordWidthLog] & (1 << (pos%WordWidth))) > 0; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Compare k-bit binary representation of stream at position pos with val
|
||||||
|
/// @param stream A bit stream stored in array of unsigned integers
|
||||||
|
/// @param pos A valid zero-based position in the bit stream
|
||||||
|
/// @param k Number of bits to compare
|
||||||
|
/// @param val Value to compare with
|
||||||
|
/// @return true if equal
|
||||||
|
inline bool CompareBitBlock(UINT32* stream, UINT32 pos, UINT32 k, UINT32 val) { |
||||||
|
const UINT32 iLoInt = pos >> WordWidthLog; |
||||||
|
const UINT32 iHiInt = (pos + k - 1) >> WordWidthLog; |
||||||
|
ASSERT(iLoInt <= iHiInt); |
||||||
|
const UINT32 mask = (Filled >> (WordWidth - k)); |
||||||
|
|
||||||
|
if (iLoInt == iHiInt) { |
||||||
|
// fits into one integer
|
||||||
|
val &= mask; |
||||||
|
val <<= (pos%WordWidth); |
||||||
|
return (stream[iLoInt] & val) == val; |
||||||
|
} else { |
||||||
|
// must be splitted over integer boundary
|
||||||
|
UINT64 v1 = MAKEU64(stream[iLoInt], stream[iHiInt]); |
||||||
|
UINT64 v2 = UINT64(val & mask) << (pos%WordWidth); |
||||||
|
return (v1 & v2) == v2; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Store k-bit binary representation of val in stream at position pos
|
||||||
|
/// @param stream A bit stream stored in array of unsigned integers
|
||||||
|
/// @param pos A valid zero-based position in the bit stream
|
||||||
|
/// @param val Value to store in stream at position pos
|
||||||
|
/// @param k Number of bits of integer representation of val
|
||||||
|
inline void SetValueBlock(UINT32* stream, UINT32 pos, UINT32 val, UINT32 k) { |
||||||
|
const UINT32 offset = pos%WordWidth; |
||||||
|
const UINT32 iLoInt = pos >> WordWidthLog; |
||||||
|
const UINT32 iHiInt = (pos + k - 1) >> WordWidthLog; |
||||||
|
ASSERT(iLoInt <= iHiInt); |
||||||
|
const UINT32 loMask = Filled << offset; |
||||||
|
const UINT32 hiMask = Filled >> (WordWidth - 1 - ((pos + k - 1)%WordWidth)); |
||||||
|
|
||||||
|
if (iLoInt == iHiInt) { |
||||||
|
// fits into one integer
|
||||||
|
stream[iLoInt] &= ~(loMask & hiMask); // clear bits
|
||||||
|
stream[iLoInt] |= val << offset; // write value
|
||||||
|
} else { |
||||||
|
// must be splitted over integer boundary
|
||||||
|
stream[iLoInt] &= ~loMask; // clear bits
|
||||||
|
stream[iLoInt] |= val << offset; // write lower part of value
|
||||||
|
stream[iHiInt] &= ~hiMask; // clear bits
|
||||||
|
stream[iHiInt] |= val >> (WordWidth - offset); // write higher part of value
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Read k-bit number from stream at position pos
|
||||||
|
/// @param stream A bit stream stored in array of unsigned integers
|
||||||
|
/// @param pos A valid zero-based position in the bit stream
|
||||||
|
/// @param k Number of bits to read: 1 <= k <= 32
|
||||||
|
inline UINT32 GetValueBlock(UINT32* stream, UINT32 pos, UINT32 k) { |
||||||
|
UINT32 count, hiCount; |
||||||
|
const UINT32 iLoInt = pos >> WordWidthLog; // integer of first bit
|
||||||
|
const UINT32 iHiInt = (pos + k - 1) >> WordWidthLog; // integer of last bit
|
||||||
|
const UINT32 loMask = Filled << (pos%WordWidth); |
||||||
|
const UINT32 hiMask = Filled >> (WordWidth - 1 - ((pos + k - 1)%WordWidth)); |
||||||
|
|
||||||
|
if (iLoInt == iHiInt) { |
||||||
|
// inside integer boundary
|
||||||
|
count = stream[iLoInt] & (loMask & hiMask); |
||||||
|
count >>= pos%WordWidth; |
||||||
|
} else { |
||||||
|
// overlapping integer boundary
|
||||||
|
count = stream[iLoInt] & loMask; |
||||||
|
count >>= pos%WordWidth; |
||||||
|
hiCount = stream[iHiInt] & hiMask; |
||||||
|
hiCount <<= WordWidth - (pos%WordWidth); |
||||||
|
count |= hiCount; |
||||||
|
} |
||||||
|
return count; |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Clear block of size at least len at position pos in stream
|
||||||
|
/// @param stream A bit stream stored in array of unsigned integers
|
||||||
|
/// @param pos A valid zero-based position in the bit stream
|
||||||
|
/// @param len Number of bits set to 0
|
||||||
|
inline void ClearBitBlock(UINT32* stream, UINT32 pos, UINT32 len) { |
||||||
|
ASSERT(len > 0); |
||||||
|
const UINT32 iFirstInt = pos >> WordWidthLog; |
||||||
|
const UINT32 iLastInt = (pos + len - 1) >> WordWidthLog; |
||||||
|
|
||||||
|
const UINT32 startMask = Filled << (pos%WordWidth); |
||||||
|
// const UINT32 endMask=Filled>>(WordWidth-1-((pos+len-1)%WordWidth));
|
||||||
|
|
||||||
|
if (iFirstInt == iLastInt) { |
||||||
|
stream[iFirstInt] &= ~(startMask /*& endMask*/); |
||||||
|
} else { |
||||||
|
stream[iFirstInt] &= ~startMask; |
||||||
|
for (UINT32 i = iFirstInt + 1; i <= iLastInt; i++) { // changed <=
|
||||||
|
stream[i] = 0; |
||||||
|
} |
||||||
|
//stream[iLastInt] &= ~endMask;
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Set block of size at least len at position pos in stream
|
||||||
|
/// @param stream A bit stream stored in array of unsigned integers
|
||||||
|
/// @param pos A valid zero-based position in the bit stream
|
||||||
|
/// @param len Number of bits set to 1
|
||||||
|
inline void SetBitBlock(UINT32* stream, UINT32 pos, UINT32 len) { |
||||||
|
ASSERT(len > 0); |
||||||
|
|
||||||
|
const UINT32 iFirstInt = pos >> WordWidthLog; |
||||||
|
const UINT32 iLastInt = (pos + len - 1) >> WordWidthLog; |
||||||
|
|
||||||
|
const UINT32 startMask = Filled << (pos%WordWidth); |
||||||
|
// const UINT32 endMask=Filled>>(WordWidth-1-((pos+len-1)%WordWidth));
|
||||||
|
|
||||||
|
if (iFirstInt == iLastInt) { |
||||||
|
stream[iFirstInt] |= (startMask /*& endMask*/); |
||||||
|
} else { |
||||||
|
stream[iFirstInt] |= startMask; |
||||||
|
for (UINT32 i = iFirstInt + 1; i <= iLastInt; i++) { // changed <=
|
||||||
|
stream[i] = Filled; |
||||||
|
} |
||||||
|
//stream[iLastInt] &= ~endMask;
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Returns the distance to the next 1 in stream at position pos.
|
||||||
|
/// If no 1 is found within len bits, then len is returned.
|
||||||
|
/// @param stream A bit stream stored in array of unsigned integers
|
||||||
|
/// @param pos A valid zero-based position in the bit stream
|
||||||
|
/// @param len size of search area (in bits)
|
||||||
|
/// return The distance to the next 1 in stream at position pos
|
||||||
|
inline UINT32 SeekBitRange(UINT32* stream, UINT32 pos, UINT32 len) { |
||||||
|
UINT32 count = 0; |
||||||
|
UINT32 testMask = 1 << (pos%WordWidth); |
||||||
|
UINT32* word = stream + (pos >> WordWidthLog); |
||||||
|
|
||||||
|
while (((*word & testMask) == 0) && (count < len)) { |
||||||
|
count++;
|
||||||
|
testMask <<= 1; |
||||||
|
if (!testMask) { |
||||||
|
word++; testMask = 1; |
||||||
|
|
||||||
|
// fast steps if all bits in a word are zero
|
||||||
|
while ((count + WordWidth <= len) && (*word == 0)) { |
||||||
|
word++;
|
||||||
|
count += WordWidth; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return count; |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Returns the distance to the next 0 in stream at position pos.
|
||||||
|
/// If no 0 is found within len bits, then len is returned.
|
||||||
|
/// @param stream A bit stream stored in array of unsigned integers
|
||||||
|
/// @param pos A valid zero-based position in the bit stream
|
||||||
|
/// @param len size of search area (in bits)
|
||||||
|
/// return The distance to the next 0 in stream at position pos
|
||||||
|
inline UINT32 SeekBit1Range(UINT32* stream, UINT32 pos, UINT32 len) { |
||||||
|
UINT32 count = 0; |
||||||
|
UINT32 testMask = 1 << (pos%WordWidth); |
||||||
|
UINT32* word = stream + (pos >> WordWidthLog); |
||||||
|
|
||||||
|
while (((*word & testMask) != 0) && (count < len)) { |
||||||
|
count++;
|
||||||
|
testMask <<= 1; |
||||||
|
if (!testMask) { |
||||||
|
word++; testMask = 1; |
||||||
|
|
||||||
|
// fast steps if all bits in a word are one
|
||||||
|
while ((count + WordWidth <= len) && (*word == Filled)) { |
||||||
|
word++;
|
||||||
|
count += WordWidth; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return count; |
||||||
|
} |
||||||
|
/*
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// BitCopy: copies k bits from source to destination
|
||||||
|
/// Note: only 8 bits are copied at a time, if speed is an issue, a more
|
||||||
|
/// complicated but faster 64 bit algorithm should be used.
|
||||||
|
inline void BitCopy(const UINT8 *sStream, UINT32 sPos, UINT8 *dStream, UINT32 dPos, UINT32 k) { |
||||||
|
ASSERT(k > 0); |
||||||
|
|
||||||
|
div_t divS = div(sPos, 8); |
||||||
|
div_t divD = div(dPos, 8); |
||||||
|
UINT32 sOff = divS.rem; |
||||||
|
UINT32 dOff = divD.rem; |
||||||
|
INT32 tmp = div(dPos + k - 1, 8).quot; |
||||||
|
|
||||||
|
const UINT8 *sAddr = sStream + divS.quot; |
||||||
|
UINT8 *dAddrS = dStream + divD.quot; |
||||||
|
UINT8 *dAddrE = dStream + tmp; |
||||||
|
UINT8 eMask; |
||||||
|
|
||||||
|
UINT8 destSB = *dAddrS; |
||||||
|
UINT8 destEB = *dAddrE; |
||||||
|
UINT8 *dAddr; |
||||||
|
UINT8 prec; |
||||||
|
INT32 shiftl, shiftr; |
||||||
|
|
||||||
|
if (dOff > sOff) { |
||||||
|
prec = 0; |
||||||
|
shiftr = dOff - sOff; |
||||||
|
shiftl = 8 - dOff + sOff; |
||||||
|
} else { |
||||||
|
prec = *sAddr << (sOff - dOff); |
||||||
|
shiftr = 8 - sOff + dOff; |
||||||
|
shiftl = sOff - dOff; |
||||||
|
sAddr++; |
||||||
|
} |
||||||
|
|
||||||
|
for (dAddr = dAddrS; dAddr < dAddrE; dAddr++, sAddr++) { |
||||||
|
*dAddr = prec | (*sAddr >> shiftr); |
||||||
|
prec = *sAddr << shiftl; |
||||||
|
} |
||||||
|
|
||||||
|
if ((sPos + k)%8 == 0) { |
||||||
|
*dAddr = prec; |
||||||
|
} else { |
||||||
|
*dAddr = prec | (*sAddr >> shiftr); |
||||||
|
} |
||||||
|
|
||||||
|
eMask = lMask[dOff]; |
||||||
|
*dAddrS = (destSB & eMask) | (*dAddrS & (~eMask)); |
||||||
|
|
||||||
|
INT32 mind = (dPos + k) % 8; |
||||||
|
eMask = (mind) ? lMask[mind] : lMask[8]; |
||||||
|
*dAddrE = (destEB & (~eMask)) | (*dAddrE & eMask); |
||||||
|
} |
||||||
|
*/ |
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Compute bit position of the next 32-bit word
|
||||||
|
/// @param pos current bit stream position
|
||||||
|
/// @return bit position of next 32-bit word
|
||||||
|
inline UINT32 AlignWordPos(UINT32 pos) { |
||||||
|
// return ((pos + WordWidth - 1) >> WordWidthLog) << WordWidthLog;
|
||||||
|
return DWWIDTHBITS(pos); |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Compute number of the 32-bit words
|
||||||
|
/// @param pos Current bit stream position
|
||||||
|
/// @return Number of 32-bit words
|
||||||
|
inline UINT32 NumberOfWords(UINT32 pos) { |
||||||
|
return (pos + WordWidth - 1) >> WordWidthLog; |
||||||
|
} |
||||||
|
|
||||||
|
#endif //PGF_BITSTREAM_H
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,218 @@ |
|||||||
|
/*
|
||||||
|
* The Progressive Graphics File; http://www.libpgf.org
|
||||||
|
*
|
||||||
|
* $Date: 2006-06-04 22:05:59 +0200 (So, 04 Jun 2006) $ |
||||||
|
* $Revision: 229 $ |
||||||
|
*
|
||||||
|
* This file Copyright (C) 2006 xeraina GmbH, Switzerland |
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE |
||||||
|
* as published by the Free Software Foundation; either version 2.1 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||||
|
*/ |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// @file Decoder.h
|
||||||
|
/// @brief PGF decoder class
|
||||||
|
/// @author C. Stamm, R. Spuler
|
||||||
|
|
||||||
|
#ifndef PGF_DECODER_H |
||||||
|
#define PGF_DECODER_H |
||||||
|
|
||||||
|
#include "PGFstream.h" |
||||||
|
#include "BitStream.h" |
||||||
|
#include "Subband.h" |
||||||
|
#include "WaveletTransform.h" |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// Constants
|
||||||
|
#define BufferLen (BufferSize/WordWidth) ///< number of words per buffer
|
||||||
|
#define CodeBufferLen BufferSize ///< number of words in code buffer (CodeBufferLen > BufferLen)
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// PGF decoder class.
|
||||||
|
/// @author C. Stamm, R. Spuler
|
||||||
|
/// @brief PGF decoder
|
||||||
|
class CDecoder { |
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// PGF decoder macro block class.
|
||||||
|
/// @author C. Stamm, I. Bauersachs
|
||||||
|
/// @brief A macro block is a decoding unit of fixed size (uncoded)
|
||||||
|
class CMacroBlock { |
||||||
|
public: |
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Constructor: Initializes new macro block.
|
||||||
|
CMacroBlock() |
||||||
|
: m_header(0) // makes sure that IsCompletelyRead() returns true for an empty macro block
|
||||||
|
#ifdef _MSC_VER |
||||||
|
#pragma warning( suppress : 4351 ) |
||||||
|
#endif |
||||||
|
, m_value() |
||||||
|
, m_codeBuffer() |
||||||
|
, m_valuePos(0) |
||||||
|
, m_sigFlagVector() |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Returns true if this macro block has been completely read.
|
||||||
|
/// @return true if current value position is at block end
|
||||||
|
bool IsCompletelyRead() const { return m_valuePos >= m_header.rbh.bufferSize; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Decodes already read input data into this macro block.
|
||||||
|
/// Several macro blocks can be decoded in parallel.
|
||||||
|
/// Call CDecoder::ReadMacroBlock before this method.
|
||||||
|
void BitplaneDecode(); |
||||||
|
|
||||||
|
ROIBlockHeader m_header; ///< block header
|
||||||
|
DataT m_value[BufferSize]; ///< output buffer of values with index m_valuePos
|
||||||
|
UINT32 m_codeBuffer[CodeBufferLen]; ///< input buffer for encoded bitstream
|
||||||
|
UINT32 m_valuePos; ///< current position in m_value
|
||||||
|
|
||||||
|
private: |
||||||
|
UINT32 ComposeBitplane(UINT32 bufferSize, DataT planeMask, UINT32* sigBits, UINT32* refBits, UINT32* signBits); |
||||||
|
UINT32 ComposeBitplaneRLD(UINT32 bufferSize, DataT planeMask, UINT32 sigPos, UINT32* refBits); |
||||||
|
UINT32 ComposeBitplaneRLD(UINT32 bufferSize, DataT planeMask, UINT32* sigBits, UINT32* refBits, UINT32 signPos); |
||||||
|
void SetBitAtPos(UINT32 pos, DataT planeMask) { (m_value[pos] >= 0) ? m_value[pos] |= planeMask : m_value[pos] -= planeMask; } |
||||||
|
void SetSign(UINT32 pos, bool sign) { m_value[pos] = -m_value[pos]*sign + m_value[pos]*(!sign); } |
||||||
|
|
||||||
|
bool m_sigFlagVector[BufferSize+1]; // see paper from Malvar, Fast Progressive Wavelet Coder
|
||||||
|
}; |
||||||
|
|
||||||
|
public: |
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Constructor: Read pre-header, header, and levelLength at current stream position.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param stream A PGF stream
|
||||||
|
/// @param preHeader [out] A PGF pre-header
|
||||||
|
/// @param header [out] A PGF header
|
||||||
|
/// @param postHeader [out] A PGF post-header
|
||||||
|
/// @param levelLength The location of the levelLength array. The array is allocated in this method. The caller has to delete this array.
|
||||||
|
/// @param userDataPos The stream position of the user data (metadata)
|
||||||
|
/// @param useOMP If true, then the decoder will use multi-threading based on openMP
|
||||||
|
/// @param userDataPolicy Policy of user data (meta-data) handling while reading PGF headers.
|
||||||
|
CDecoder(CPGFStream* stream, PGFPreHeader& preHeader, PGFHeader& header, |
||||||
|
PGFPostHeader& postHeader, UINT32*& levelLength, UINT64& userDataPos,
|
||||||
|
bool useOMP, UINT32 userDataPolicy); // throws IOException
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Destructor
|
||||||
|
~CDecoder(); |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Unpartitions a rectangular region of a given subband.
|
||||||
|
/// Partitioning scheme: The plane is partitioned in squares of side length LinBlockSize.
|
||||||
|
/// Read wavelet coefficients from the output buffer of a macro block.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param band A subband
|
||||||
|
/// @param quantParam Dequantization value
|
||||||
|
/// @param width The width of the rectangle
|
||||||
|
/// @param height The height of the rectangle
|
||||||
|
/// @param startPos The relative subband position of the top left corner of the rectangular region
|
||||||
|
/// @param pitch The number of bytes in row of the subband
|
||||||
|
void Partition(CSubband* band, int quantParam, int width, int height, int startPos, int pitch); |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Deccoding and dequantization of HL and LH subband (interleaved) using partitioning scheme.
|
||||||
|
/// Partitioning scheme: The plane is partitioned in squares of side length InterBlockSize.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param wtChannel A wavelet transform channel containing the HL and HL band
|
||||||
|
/// @param level Wavelet transform level
|
||||||
|
/// @param quantParam Dequantization value
|
||||||
|
void DecodeInterleaved(CWaveletTransform* wtChannel, int level, int quantParam); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Returns the length of all encoded headers in bytes.
|
||||||
|
/// @return The length of all encoded headers in bytes
|
||||||
|
UINT32 GetEncodedHeaderLength() const { return m_encodedHeaderLength; } |
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
/// Resets stream position to beginning of PGF pre-header
|
||||||
|
void SetStreamPosToStart() { ASSERT(m_stream); m_stream->SetPos(FSFromStart, m_startPos); } |
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
/// Resets stream position to beginning of data block
|
||||||
|
void SetStreamPosToData() { ASSERT(m_stream); m_stream->SetPos(FSFromStart, m_startPos + m_encodedHeaderLength); } |
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
/// Skips a given number of bytes in the open stream.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
void Skip(UINT64 offset); |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Dequantization of a single value at given position in subband.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param band A subband
|
||||||
|
/// @param bandPos A valid position in subband band
|
||||||
|
/// @param quantParam The quantization parameter
|
||||||
|
void DequantizeValue(CSubband* band, UINT32 bandPos, int quantParam); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Copies data from the open stream to a target buffer.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param target The target buffer
|
||||||
|
/// @param len The number of bytes to read
|
||||||
|
/// @return The number of bytes copied to the target buffer
|
||||||
|
UINT32 ReadEncodedData(UINT8* target, UINT32 len) const; |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Reads next block(s) from stream and decodes them
|
||||||
|
/// It might throw an IOException.
|
||||||
|
void DecodeBuffer(); |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// @return Stream
|
||||||
|
CPGFStream* GetStream() { return m_stream; } |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Gets next macro block
|
||||||
|
/// It might throw an IOException.
|
||||||
|
void GetNextMacroBlock(); |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Resets stream position to next tile.
|
||||||
|
/// Used with ROI encoding scheme only.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
void SkipTileBuffer(); |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Enables region of interest (ROI) status.
|
||||||
|
void SetROI() { m_roi = true; } |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef TRACE |
||||||
|
void DumpBuffer(); |
||||||
|
#endif |
||||||
|
|
||||||
|
private: |
||||||
|
void ReadMacroBlock(CMacroBlock* block); ///< throws IOException
|
||||||
|
|
||||||
|
CPGFStream *m_stream; ///< input PGF stream
|
||||||
|
UINT64 m_startPos; ///< stream position at the beginning of the PGF pre-header
|
||||||
|
UINT64 m_streamSizeEstimation; ///< estimation of stream size
|
||||||
|
UINT32 m_encodedHeaderLength; ///< stream offset from startPos to the beginning of the data part (highest level)
|
||||||
|
|
||||||
|
CMacroBlock **m_macroBlocks; ///< array of macroblocks
|
||||||
|
int m_currentBlockIndex; ///< index of current macro block
|
||||||
|
int m_macroBlockLen; ///< array length
|
||||||
|
int m_macroBlocksAvailable; ///< number of decoded macro blocks (including currently used macro block)
|
||||||
|
CMacroBlock *m_currentBlock; ///< current macro block (used by main thread)
|
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
bool m_roi; ///< true: ensures region of interest (ROI) decoding
|
||||||
|
#endif |
||||||
|
}; |
||||||
|
|
||||||
|
#endif //PGF_DECODER_H
|
@ -0,0 +1,830 @@ |
|||||||
|
/*
|
||||||
|
* The Progressive Graphics File; http://www.libpgf.org
|
||||||
|
*
|
||||||
|
* $Date: 2007-02-03 13:04:21 +0100 (Sa, 03 Feb 2007) $ |
||||||
|
* $Revision: 280 $ |
||||||
|
*
|
||||||
|
* This file Copyright (C) 2006 xeraina GmbH, Switzerland |
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE |
||||||
|
* as published by the Free Software Foundation; either version 2.1 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||||
|
*/ |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// @file Encoder.cpp
|
||||||
|
/// @brief PGF encoder class implementation
|
||||||
|
/// @author C. Stamm, R. Spuler
|
||||||
|
|
||||||
|
#include "Encoder.h" |
||||||
|
#ifdef TRACE |
||||||
|
#include <stdio.h> |
||||||
|
#endif |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// PGF: file structure
|
||||||
|
//
|
||||||
|
// PGFPreHeader PGFHeader [PGFPostHeader] LevelLengths Level_n-1 Level_n-2 ... Level_0
|
||||||
|
// PGFPostHeader ::= [ColorTable] [UserData]
|
||||||
|
// LevelLengths ::= UINT32[nLevels]
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// Encoding scheme
|
||||||
|
// input: wavelet coefficients stored in subbands
|
||||||
|
// output: binary file
|
||||||
|
//
|
||||||
|
// subband
|
||||||
|
// |
|
||||||
|
// m_value [BufferSize]
|
||||||
|
// | | |
|
||||||
|
// m_sign sigBits refBits [BufferSize, BufferLen, BufferLen]
|
||||||
|
// | | |
|
||||||
|
// m_codeBuffer (for each plane: RLcodeLength (16 bit), RLcoded sigBits + m_sign, refBits)
|
||||||
|
// |
|
||||||
|
// file (for each buffer: packedLength (16 bit), packed bits)
|
||||||
|
//
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
#define CodeBufferBitLen (CodeBufferLen*WordWidth) ///< max number of bits in m_codeBuffer
|
||||||
|
#define MaxCodeLen ((1 << RLblockSizeLen) - 1) ///< max length of RL encoded block
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
/// Write pre-header, header, postHeader, and levelLength.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param stream A PGF stream
|
||||||
|
/// @param preHeader A already filled in PGF pre-header
|
||||||
|
/// @param header An already filled in PGF header
|
||||||
|
/// @param postHeader [in] An already filled in PGF post-header (containing color table, user data, ...)
|
||||||
|
/// @param userDataPos [out] File position of user data
|
||||||
|
/// @param useOMP If true, then the encoder will use multi-threading based on openMP
|
||||||
|
CEncoder::CEncoder(CPGFStream* stream, PGFPreHeader preHeader, PGFHeader header, const PGFPostHeader& postHeader, UINT64& userDataPos, bool useOMP) |
||||||
|
: m_stream(stream) |
||||||
|
, m_bufferStartPos(0) |
||||||
|
, m_currLevelIndex(0) |
||||||
|
, m_nLevels(header.nLevels) |
||||||
|
, m_favorSpeed(false) |
||||||
|
, m_forceWriting(false) |
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
, m_roi(false) |
||||||
|
#endif |
||||||
|
{ |
||||||
|
ASSERT(m_stream); |
||||||
|
|
||||||
|
int count; |
||||||
|
m_lastMacroBlock = 0; |
||||||
|
m_levelLength = nullptr; |
||||||
|
|
||||||
|
// set number of threads
|
||||||
|
#ifdef LIBPGF_USE_OPENMP |
||||||
|
m_macroBlockLen = omp_get_num_procs(); |
||||||
|
#else |
||||||
|
m_macroBlockLen = 1; |
||||||
|
#endif |
||||||
|
|
||||||
|
if (useOMP && m_macroBlockLen > 1) { |
||||||
|
#ifdef LIBPGF_USE_OPENMP |
||||||
|
omp_set_num_threads(m_macroBlockLen); |
||||||
|
#endif |
||||||
|
// create macro block array
|
||||||
|
m_macroBlocks = new(std::nothrow) CMacroBlock*[m_macroBlockLen]; |
||||||
|
if (!m_macroBlocks) ReturnWithError(InsufficientMemory); |
||||||
|
for (int i=0; i < m_macroBlockLen; i++) m_macroBlocks[i] = new CMacroBlock(this); |
||||||
|
m_currentBlock = m_macroBlocks[m_lastMacroBlock++]; |
||||||
|
} else { |
||||||
|
m_macroBlocks = 0; |
||||||
|
m_macroBlockLen = 1; |
||||||
|
m_currentBlock = new CMacroBlock(this); |
||||||
|
} |
||||||
|
|
||||||
|
// save file position
|
||||||
|
m_startPosition = m_stream->GetPos(); |
||||||
|
|
||||||
|
// write preHeader
|
||||||
|
preHeader.hSize = __VAL(preHeader.hSize); |
||||||
|
count = PreHeaderSize; |
||||||
|
m_stream->Write(&count, &preHeader); |
||||||
|
|
||||||
|
// write file header
|
||||||
|
header.height = __VAL(header.height); |
||||||
|
header.width = __VAL(header.width); |
||||||
|
count = HeaderSize; |
||||||
|
m_stream->Write(&count, &header); |
||||||
|
|
||||||
|
// write postHeader
|
||||||
|
if (header.mode == ImageModeIndexedColor) { |
||||||
|
// write color table
|
||||||
|
count = ColorTableSize; |
||||||
|
m_stream->Write(&count, (void *)postHeader.clut); |
||||||
|
} |
||||||
|
// save user data file position
|
||||||
|
userDataPos = m_stream->GetPos(); |
||||||
|
if (postHeader.userDataLen) { |
||||||
|
if (postHeader.userData) { |
||||||
|
// write user data
|
||||||
|
count = postHeader.userDataLen; |
||||||
|
m_stream->Write(&count, postHeader.userData); |
||||||
|
} else { |
||||||
|
m_stream->SetPos(FSFromCurrent, count); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// save level length file position
|
||||||
|
m_levelLengthPos = m_stream->GetPos(); |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// Destructor
|
||||||
|
CEncoder::~CEncoder() {
|
||||||
|
if (m_macroBlocks) { |
||||||
|
for (int i=0; i < m_macroBlockLen; i++) delete m_macroBlocks[i]; |
||||||
|
delete[] m_macroBlocks; |
||||||
|
} else { |
||||||
|
delete m_currentBlock; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Increase post-header size and write new size into stream.
|
||||||
|
/// @param preHeader An already filled in PGF pre-header
|
||||||
|
/// It might throw an IOException.
|
||||||
|
void CEncoder::UpdatePostHeaderSize(PGFPreHeader preHeader) { |
||||||
|
UINT64 curPos = m_stream->GetPos(); // end of user data
|
||||||
|
int count = PreHeaderSize; |
||||||
|
|
||||||
|
// write preHeader
|
||||||
|
SetStreamPosToStart(); |
||||||
|
preHeader.hSize = __VAL(preHeader.hSize); |
||||||
|
m_stream->Write(&count, &preHeader); |
||||||
|
|
||||||
|
m_stream->SetPos(FSFromStart, curPos); |
||||||
|
} |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Create level length data structure and write a place holder into stream.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param levelLength A reference to an integer array, large enough to save the relative file positions of all PGF levels
|
||||||
|
/// @return number of bytes written into stream
|
||||||
|
UINT32 CEncoder::WriteLevelLength(UINT32*& levelLength) { |
||||||
|
// renew levelLength
|
||||||
|
delete[] levelLength; |
||||||
|
levelLength = new(std::nothrow) UINT32[m_nLevels]; |
||||||
|
if (!levelLength) ReturnWithError(InsufficientMemory); |
||||||
|
for (UINT8 l = 0; l < m_nLevels; l++) levelLength[l] = 0; |
||||||
|
m_levelLength = levelLength; |
||||||
|
|
||||||
|
// save level length file position
|
||||||
|
m_levelLengthPos = m_stream->GetPos(); |
||||||
|
|
||||||
|
// write dummy levelLength
|
||||||
|
int count = m_nLevels*WordBytes; |
||||||
|
m_stream->Write(&count, m_levelLength); |
||||||
|
|
||||||
|
// save current file position
|
||||||
|
SetBufferStartPos(); |
||||||
|
|
||||||
|
return count; |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
/// Write new levelLength into stream.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @return Written image bytes.
|
||||||
|
UINT32 CEncoder::UpdateLevelLength() { |
||||||
|
UINT64 curPos = m_stream->GetPos(); // end of image
|
||||||
|
|
||||||
|
// set file pos to levelLength
|
||||||
|
m_stream->SetPos(FSFromStart, m_levelLengthPos); |
||||||
|
|
||||||
|
if (m_levelLength) { |
||||||
|
#ifdef PGF_USE_BIG_ENDIAN |
||||||
|
UINT32 levelLength; |
||||||
|
int count = WordBytes; |
||||||
|
|
||||||
|
for (int i=0; i < m_currLevelIndex; i++) { |
||||||
|
levelLength = __VAL(UINT32(m_levelLength[i])); |
||||||
|
m_stream->Write(&count, &levelLength); |
||||||
|
} |
||||||
|
#else |
||||||
|
int count = m_currLevelIndex*WordBytes; |
||||||
|
|
||||||
|
m_stream->Write(&count, m_levelLength); |
||||||
|
#endif //PGF_USE_BIG_ENDIAN
|
||||||
|
} else { |
||||||
|
int count = m_currLevelIndex*WordBytes; |
||||||
|
m_stream->SetPos(FSFromCurrent, count); |
||||||
|
} |
||||||
|
|
||||||
|
// begin of image
|
||||||
|
UINT32 retValue = UINT32(curPos - m_stream->GetPos()); |
||||||
|
|
||||||
|
// restore file position
|
||||||
|
m_stream->SetPos(FSFromStart, curPos); |
||||||
|
|
||||||
|
return retValue; |
||||||
|
} |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Partitions a rectangular region of a given subband.
|
||||||
|
/// Partitioning scheme: The plane is partitioned in squares of side length LinBlockSize.
|
||||||
|
/// Write wavelet coefficients from subband into the input buffer of a macro block.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param band A subband
|
||||||
|
/// @param width The width of the rectangle
|
||||||
|
/// @param height The height of the rectangle
|
||||||
|
/// @param startPos The absolute subband position of the top left corner of the rectangular region
|
||||||
|
/// @param pitch The number of bytes in row of the subband
|
||||||
|
void CEncoder::Partition(CSubband* band, int width, int height, int startPos, int pitch) { |
||||||
|
ASSERT(band); |
||||||
|
|
||||||
|
const div_t hh = div(height, LinBlockSize); |
||||||
|
const div_t ww = div(width, LinBlockSize); |
||||||
|
const int ws = pitch - LinBlockSize; |
||||||
|
const int wr = pitch - ww.rem; |
||||||
|
int pos, base = startPos, base2; |
||||||
|
|
||||||
|
// main height
|
||||||
|
for (int i=0; i < hh.quot; i++) { |
||||||
|
// main width
|
||||||
|
base2 = base; |
||||||
|
for (int j=0; j < ww.quot; j++) { |
||||||
|
pos = base2; |
||||||
|
for (int y=0; y < LinBlockSize; y++) { |
||||||
|
for (int x=0; x < LinBlockSize; x++) { |
||||||
|
WriteValue(band, pos); |
||||||
|
pos++; |
||||||
|
} |
||||||
|
pos += ws; |
||||||
|
} |
||||||
|
base2 += LinBlockSize; |
||||||
|
} |
||||||
|
// rest of width
|
||||||
|
pos = base2; |
||||||
|
for (int y=0; y < LinBlockSize; y++) { |
||||||
|
for (int x=0; x < ww.rem; x++) { |
||||||
|
WriteValue(band, pos); |
||||||
|
pos++; |
||||||
|
} |
||||||
|
pos += wr; |
||||||
|
base += pitch; |
||||||
|
} |
||||||
|
} |
||||||
|
// main width
|
||||||
|
base2 = base; |
||||||
|
for (int j=0; j < ww.quot; j++) { |
||||||
|
// rest of height
|
||||||
|
pos = base2; |
||||||
|
for (int y=0; y < hh.rem; y++) { |
||||||
|
for (int x=0; x < LinBlockSize; x++) { |
||||||
|
WriteValue(band, pos); |
||||||
|
pos++; |
||||||
|
} |
||||||
|
pos += ws; |
||||||
|
} |
||||||
|
base2 += LinBlockSize; |
||||||
|
} |
||||||
|
// rest of height
|
||||||
|
pos = base2; |
||||||
|
for (int y=0; y < hh.rem; y++) { |
||||||
|
// rest of width
|
||||||
|
for (int x=0; x < ww.rem; x++) { |
||||||
|
WriteValue(band, pos); |
||||||
|
pos++; |
||||||
|
} |
||||||
|
pos += wr; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
/// Pad buffer with zeros and encode buffer.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
void CEncoder::Flush() { |
||||||
|
if (m_currentBlock->m_valuePos > 0) { |
||||||
|
// pad buffer with zeros
|
||||||
|
memset(&(m_currentBlock->m_value[m_currentBlock->m_valuePos]), 0, (BufferSize - m_currentBlock->m_valuePos)*DataTSize); |
||||||
|
m_currentBlock->m_valuePos = BufferSize; |
||||||
|
|
||||||
|
// encode buffer
|
||||||
|
m_forceWriting = true; // makes sure that the following EncodeBuffer is really written into the stream
|
||||||
|
EncodeBuffer(ROIBlockHeader(m_currentBlock->m_valuePos, true)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// Stores band value from given position bandPos into buffer m_value at position m_valuePos
|
||||||
|
// If buffer is full encode it to file
|
||||||
|
// It might throw an IOException.
|
||||||
|
void CEncoder::WriteValue(CSubband* band, int bandPos) { |
||||||
|
if (m_currentBlock->m_valuePos == BufferSize) { |
||||||
|
EncodeBuffer(ROIBlockHeader(BufferSize, false)); |
||||||
|
} |
||||||
|
DataT val = m_currentBlock->m_value[m_currentBlock->m_valuePos++] = band->GetData(bandPos); |
||||||
|
UINT32 v = abs(val); |
||||||
|
if (v > m_currentBlock->m_maxAbsValue) m_currentBlock->m_maxAbsValue = v; |
||||||
|
} |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// Encode buffer and write data into stream.
|
||||||
|
// h contains buffer size and flag indicating end of tile.
|
||||||
|
// Encoding scheme: <wordLen>(16 bits) [ ROI ] data
|
||||||
|
// ROI ::= <bufferSize>(15 bits) <eofTile>(1 bit)
|
||||||
|
// It might throw an IOException.
|
||||||
|
void CEncoder::EncodeBuffer(ROIBlockHeader h) { |
||||||
|
ASSERT(m_currentBlock); |
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
ASSERT(m_roi && h.rbh.bufferSize <= BufferSize || h.rbh.bufferSize == BufferSize); |
||||||
|
#else |
||||||
|
ASSERT(h.rbh.bufferSize == BufferSize); |
||||||
|
#endif |
||||||
|
m_currentBlock->m_header = h; |
||||||
|
|
||||||
|
// macro block management
|
||||||
|
if (m_macroBlockLen == 1) { |
||||||
|
m_currentBlock->BitplaneEncode(); |
||||||
|
WriteMacroBlock(m_currentBlock); |
||||||
|
} else { |
||||||
|
// save last level index
|
||||||
|
int lastLevelIndex = m_currentBlock->m_lastLevelIndex; |
||||||
|
|
||||||
|
if (m_forceWriting || m_lastMacroBlock == m_macroBlockLen) { |
||||||
|
// encode macro blocks
|
||||||
|
/*
|
||||||
|
volatile OSError error = NoError; |
||||||
|
#ifdef LIBPGF_USE_OPENMP |
||||||
|
#pragma omp parallel for ordered default(shared) |
||||||
|
#endif |
||||||
|
for (int i=0; i < m_lastMacroBlock; i++) { |
||||||
|
if (error == NoError) { |
||||||
|
m_macroBlocks[i]->BitplaneEncode(); |
||||||
|
#ifdef LIBPGF_USE_OPENMP |
||||||
|
#pragma omp ordered |
||||||
|
#endif |
||||||
|
{ |
||||||
|
try { |
||||||
|
WriteMacroBlock(m_macroBlocks[i]); |
||||||
|
} catch (IOException& e) { |
||||||
|
error = e.error; |
||||||
|
} |
||||||
|
delete m_macroBlocks[i]; m_macroBlocks[i] = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (error != NoError) ReturnWithError(error); |
||||||
|
*/ |
||||||
|
#ifdef LIBPGF_USE_OPENMP |
||||||
|
#pragma omp parallel for default(shared) //no declared exceptions in next block
|
||||||
|
#endif |
||||||
|
for (int i=0; i < m_lastMacroBlock; i++) { |
||||||
|
m_macroBlocks[i]->BitplaneEncode(); |
||||||
|
} |
||||||
|
for (int i=0; i < m_lastMacroBlock; i++) { |
||||||
|
WriteMacroBlock(m_macroBlocks[i]); |
||||||
|
} |
||||||
|
|
||||||
|
// prepare for next round
|
||||||
|
m_forceWriting = false; |
||||||
|
m_lastMacroBlock = 0; |
||||||
|
} |
||||||
|
// re-initialize macro block
|
||||||
|
m_currentBlock = m_macroBlocks[m_lastMacroBlock++]; |
||||||
|
m_currentBlock->Init(lastLevelIndex); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// Write encoded macro block into stream.
|
||||||
|
// It might throw an IOException.
|
||||||
|
void CEncoder::WriteMacroBlock(CMacroBlock* block) { |
||||||
|
ASSERT(block); |
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
ROIBlockHeader h = block->m_header; |
||||||
|
#endif |
||||||
|
UINT16 wordLen = UINT16(NumberOfWords(block->m_codePos)); ASSERT(wordLen <= CodeBufferLen); |
||||||
|
int count = sizeof(UINT16); |
||||||
|
|
||||||
|
#ifdef TRACE |
||||||
|
//UINT32 filePos = (UINT32)m_stream->GetPos();
|
||||||
|
//printf("EncodeBuffer: %d\n", filePos);
|
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef PGF_USE_BIG_ENDIAN |
||||||
|
// write wordLen
|
||||||
|
UINT16 wl = __VAL(wordLen); |
||||||
|
m_stream->Write(&count, &wl); ASSERT(count == sizeof(UINT16)); |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
// write ROIBlockHeader
|
||||||
|
if (m_roi) { |
||||||
|
count = sizeof(ROIBlockHeader); |
||||||
|
h.val = __VAL(h.val); |
||||||
|
m_stream->Write(&count, &h.val); ASSERT(count == sizeof(ROIBlockHeader)); |
||||||
|
} |
||||||
|
#endif // __PGFROISUPPORT__
|
||||||
|
|
||||||
|
// convert data
|
||||||
|
for (int i=0; i < wordLen; i++) { |
||||||
|
block->m_codeBuffer[i] = __VAL(block->m_codeBuffer[i]); |
||||||
|
} |
||||||
|
#else |
||||||
|
// write wordLen
|
||||||
|
m_stream->Write(&count, &wordLen); ASSERT(count == sizeof(UINT16)); |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
// write ROIBlockHeader
|
||||||
|
if (m_roi) { |
||||||
|
count = sizeof(ROIBlockHeader); |
||||||
|
m_stream->Write(&count, &h.val); ASSERT(count == sizeof(ROIBlockHeader)); |
||||||
|
} |
||||||
|
#endif // __PGFROISUPPORT__
|
||||||
|
#endif // PGF_USE_BIG_ENDIAN
|
||||||
|
|
||||||
|
// write encoded data into stream
|
||||||
|
count = wordLen*WordBytes; |
||||||
|
m_stream->Write(&count, block->m_codeBuffer); |
||||||
|
|
||||||
|
// store levelLength
|
||||||
|
if (m_levelLength) { |
||||||
|
// store level length
|
||||||
|
// EncodeBuffer has been called after m_lastLevelIndex has been updated
|
||||||
|
ASSERT(m_currLevelIndex < m_nLevels); |
||||||
|
m_levelLength[m_currLevelIndex] += (UINT32)ComputeBufferLength(); |
||||||
|
m_currLevelIndex = block->m_lastLevelIndex + 1; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// prepare for next buffer
|
||||||
|
SetBufferStartPos(); |
||||||
|
|
||||||
|
// reset values
|
||||||
|
block->m_valuePos = 0; |
||||||
|
block->m_maxAbsValue = 0; |
||||||
|
} |
||||||
|
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
// Encode buffer of given size using bit plane coding.
|
||||||
|
// A buffer contains bufferLen UINT32 values, thus, bufferSize bits per bit plane.
|
||||||
|
// Following coding scheme is used:
|
||||||
|
// Buffer ::= <nPlanes>(5 bits) foreach(plane i): Plane[i]
|
||||||
|
// Plane[i] ::= [ Sig1 | Sig2 ] [DWORD alignment] refBits
|
||||||
|
// Sig1 ::= 1 <codeLen>(15 bits) codedSigAndSignBits
|
||||||
|
// Sig2 ::= 0 <sigLen>(15 bits) [Sign1 | Sign2 ] [DWORD alignment] sigBits
|
||||||
|
// Sign1 ::= 1 <codeLen>(15 bits) codedSignBits
|
||||||
|
// Sign2 ::= 0 <signLen>(15 bits) [DWORD alignment] signBits
|
||||||
|
void CEncoder::CMacroBlock::BitplaneEncode() { |
||||||
|
UINT8 nPlanes; |
||||||
|
UINT32 sigLen, codeLen = 0, wordPos, refLen, signLen; |
||||||
|
UINT32 sigBits[BufferLen] = { 0 };
|
||||||
|
UINT32 refBits[BufferLen] = { 0 };
|
||||||
|
UINT32 signBits[BufferLen] = { 0 };
|
||||||
|
UINT32 planeMask; |
||||||
|
UINT32 bufferSize = m_header.rbh.bufferSize; ASSERT(bufferSize <= BufferSize); |
||||||
|
bool useRL; |
||||||
|
|
||||||
|
#ifdef TRACE |
||||||
|
//printf("which thread: %d\n", omp_get_thread_num());
|
||||||
|
#endif |
||||||
|
|
||||||
|
// clear significance vector
|
||||||
|
for (UINT32 k=0; k < bufferSize; k++) { |
||||||
|
m_sigFlagVector[k] = false; |
||||||
|
} |
||||||
|
m_sigFlagVector[bufferSize] = true; // sentinel
|
||||||
|
|
||||||
|
// clear output buffer
|
||||||
|
for (UINT32 k=0; k < bufferSize; k++) { |
||||||
|
m_codeBuffer[k] = 0; |
||||||
|
} |
||||||
|
m_codePos = 0; |
||||||
|
|
||||||
|
// compute number of bit planes and split buffer into separate bit planes
|
||||||
|
nPlanes = NumberOfBitplanes(); |
||||||
|
|
||||||
|
// write number of bit planes to m_codeBuffer
|
||||||
|
// <nPlanes>
|
||||||
|
SetValueBlock(m_codeBuffer, 0, nPlanes, MaxBitPlanesLog); |
||||||
|
m_codePos += MaxBitPlanesLog; |
||||||
|
|
||||||
|
// loop through all bit planes
|
||||||
|
if (nPlanes == 0) nPlanes = MaxBitPlanes + 1; |
||||||
|
planeMask = 1 << (nPlanes - 1); |
||||||
|
|
||||||
|
for (int plane = nPlanes - 1; plane >= 0; plane--) { |
||||||
|
// clear significant bitset
|
||||||
|
for (UINT32 k=0; k < BufferLen; k++) { |
||||||
|
sigBits[k] = 0; |
||||||
|
} |
||||||
|
|
||||||
|
// split bitplane in significant bitset and refinement bitset
|
||||||
|
sigLen = DecomposeBitplane(bufferSize, planeMask, m_codePos + RLblockSizeLen + 1, sigBits, refBits, signBits, signLen, codeLen); |
||||||
|
|
||||||
|
if (sigLen > 0 && codeLen <= MaxCodeLen && codeLen < AlignWordPos(sigLen) + AlignWordPos(signLen) + 2*RLblockSizeLen) { |
||||||
|
// set RL code bit
|
||||||
|
// <1><codeLen>
|
||||||
|
SetBit(m_codeBuffer, m_codePos++); |
||||||
|
|
||||||
|
// write length codeLen to m_codeBuffer
|
||||||
|
SetValueBlock(m_codeBuffer, m_codePos, codeLen, RLblockSizeLen); |
||||||
|
m_codePos += RLblockSizeLen + codeLen; |
||||||
|
} else { |
||||||
|
#ifdef TRACE |
||||||
|
//printf("new\n");
|
||||||
|
//for (UINT32 i=0; i < bufferSize; i++) {
|
||||||
|
// printf("%s", (GetBit(sigBits, i)) ? "1" : "_");
|
||||||
|
// if (i%120 == 119) printf("\n");
|
||||||
|
//}
|
||||||
|
//printf("\n");
|
||||||
|
#endif // TRACE
|
||||||
|
|
||||||
|
// run-length coding wasn't efficient enough
|
||||||
|
// we don't use RL coding for sigBits
|
||||||
|
// <0><sigLen>
|
||||||
|
ClearBit(m_codeBuffer, m_codePos++); |
||||||
|
|
||||||
|
// write length sigLen to m_codeBuffer
|
||||||
|
ASSERT(sigLen <= MaxCodeLen);
|
||||||
|
SetValueBlock(m_codeBuffer, m_codePos, sigLen, RLblockSizeLen); |
||||||
|
m_codePos += RLblockSizeLen; |
||||||
|
|
||||||
|
if (m_encoder->m_favorSpeed || signLen == 0) { |
||||||
|
useRL = false; |
||||||
|
} else { |
||||||
|
// overwrite m_codeBuffer
|
||||||
|
useRL = true; |
||||||
|
// run-length encode m_sign and append them to the m_codeBuffer
|
||||||
|
codeLen = RLESigns(m_codePos + RLblockSizeLen + 1, signBits, signLen); |
||||||
|
} |
||||||
|
|
||||||
|
if (useRL && codeLen <= MaxCodeLen && codeLen < signLen) { |
||||||
|
// RL encoding of m_sign was efficient
|
||||||
|
// <1><codeLen><codedSignBits>_
|
||||||
|
// write RL code bit
|
||||||
|
SetBit(m_codeBuffer, m_codePos++); |
||||||
|
|
||||||
|
// write codeLen to m_codeBuffer
|
||||||
|
SetValueBlock(m_codeBuffer, m_codePos, codeLen, RLblockSizeLen); |
||||||
|
|
||||||
|
// compute position of sigBits
|
||||||
|
wordPos = NumberOfWords(m_codePos + RLblockSizeLen + codeLen); |
||||||
|
ASSERT(0 <= wordPos && wordPos < CodeBufferLen); |
||||||
|
} else { |
||||||
|
// RL encoding of signBits wasn't efficient
|
||||||
|
// <0><signLen>_<signBits>_
|
||||||
|
// clear RL code bit
|
||||||
|
ClearBit(m_codeBuffer, m_codePos++); |
||||||
|
|
||||||
|
// write signLen to m_codeBuffer
|
||||||
|
ASSERT(signLen <= MaxCodeLen);
|
||||||
|
SetValueBlock(m_codeBuffer, m_codePos, signLen, RLblockSizeLen); |
||||||
|
|
||||||
|
// write signBits to m_codeBuffer
|
||||||
|
wordPos = NumberOfWords(m_codePos + RLblockSizeLen); |
||||||
|
ASSERT(0 <= wordPos && wordPos < CodeBufferLen); |
||||||
|
codeLen = NumberOfWords(signLen); |
||||||
|
|
||||||
|
for (UINT32 k=0; k < codeLen; k++) { |
||||||
|
m_codeBuffer[wordPos++] = signBits[k]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// write sigBits
|
||||||
|
// <sigBits>_
|
||||||
|
ASSERT(0 <= wordPos && wordPos < CodeBufferLen); |
||||||
|
refLen = NumberOfWords(sigLen); |
||||||
|
|
||||||
|
for (UINT32 k=0; k < refLen; k++) { |
||||||
|
m_codeBuffer[wordPos++] = sigBits[k]; |
||||||
|
} |
||||||
|
m_codePos = wordPos << WordWidthLog; |
||||||
|
} |
||||||
|
|
||||||
|
// append refinement bitset (aligned to word boundary)
|
||||||
|
// _<refBits>
|
||||||
|
wordPos = NumberOfWords(m_codePos); |
||||||
|
ASSERT(0 <= wordPos && wordPos < CodeBufferLen); |
||||||
|
refLen = NumberOfWords(bufferSize - sigLen); |
||||||
|
|
||||||
|
for (UINT32 k=0; k < refLen; k++) { |
||||||
|
m_codeBuffer[wordPos++] = refBits[k]; |
||||||
|
} |
||||||
|
m_codePos = wordPos << WordWidthLog; |
||||||
|
planeMask >>= 1; |
||||||
|
} |
||||||
|
ASSERT(0 <= m_codePos && m_codePos <= CodeBufferBitLen); |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
// Split bitplane of length bufferSize into significant and refinement bitset
|
||||||
|
// returns length [bits] of significant bits
|
||||||
|
// input: bufferSize, planeMask, codePos
|
||||||
|
// output: sigBits, refBits, signBits, signLen [bits], codeLen [bits]
|
||||||
|
// RLE
|
||||||
|
// - Encode run of 2^k zeros by a single 0.
|
||||||
|
// - Encode run of count 0's followed by a 1 with codeword: 1<count>x
|
||||||
|
// - x is 0: if a positive sign is stored, otherwise 1
|
||||||
|
// - Store each bit in m_codeBuffer[codePos] and increment codePos.
|
||||||
|
UINT32 CEncoder::CMacroBlock::DecomposeBitplane(UINT32 bufferSize, UINT32 planeMask, UINT32 codePos, UINT32* sigBits, UINT32* refBits, UINT32* signBits, UINT32& signLen, UINT32& codeLen) { |
||||||
|
ASSERT(sigBits); |
||||||
|
ASSERT(refBits); |
||||||
|
ASSERT(signBits); |
||||||
|
ASSERT(codePos < CodeBufferBitLen); |
||||||
|
|
||||||
|
UINT32 sigPos = 0; |
||||||
|
UINT32 valuePos = 0, valueEnd; |
||||||
|
UINT32 refPos = 0; |
||||||
|
|
||||||
|
// set output value
|
||||||
|
signLen = 0; |
||||||
|
|
||||||
|
// prepare RLE of Sigs and Signs
|
||||||
|
const UINT32 outStartPos = codePos; |
||||||
|
UINT32 k = 3; |
||||||
|
UINT32 runlen = 1 << k; // = 2^k
|
||||||
|
UINT32 count = 0; |
||||||
|
|
||||||
|
while (valuePos < bufferSize) { |
||||||
|
// search next 1 in m_sigFlagVector using searching with sentinel
|
||||||
|
valueEnd = valuePos; |
||||||
|
while(!m_sigFlagVector[valueEnd]) { valueEnd++; } |
||||||
|
|
||||||
|
// search 1's in m_value[plane][valuePos..valueEnd)
|
||||||
|
// these 1's are significant bits
|
||||||
|
while (valuePos < valueEnd) { |
||||||
|
if (GetBitAtPos(valuePos, planeMask)) { |
||||||
|
// RLE encoding
|
||||||
|
// encode run of count 0's followed by a 1
|
||||||
|
// with codeword: 1<count>(signBits[signPos])
|
||||||
|
SetBit(m_codeBuffer, codePos++);
|
||||||
|
if (k > 0) { |
||||||
|
SetValueBlock(m_codeBuffer, codePos, count, k); |
||||||
|
codePos += k; |
||||||
|
|
||||||
|
// adapt k (half the zero run-length)
|
||||||
|
k--;
|
||||||
|
runlen >>= 1; |
||||||
|
} |
||||||
|
|
||||||
|
// copy and write sign bit
|
||||||
|
if (m_value[valuePos] < 0) { |
||||||
|
SetBit(signBits, signLen++); |
||||||
|
SetBit(m_codeBuffer, codePos++); |
||||||
|
} else { |
||||||
|
ClearBit(signBits, signLen++); |
||||||
|
ClearBit(m_codeBuffer, codePos++); |
||||||
|
} |
||||||
|
|
||||||
|
// write a 1 to sigBits
|
||||||
|
SetBit(sigBits, sigPos++);
|
||||||
|
|
||||||
|
// update m_sigFlagVector
|
||||||
|
m_sigFlagVector[valuePos] = true; |
||||||
|
|
||||||
|
// prepare for next run
|
||||||
|
count = 0; |
||||||
|
} else { |
||||||
|
// RLE encoding
|
||||||
|
count++; |
||||||
|
if (count == runlen) { |
||||||
|
// encode run of 2^k zeros by a single 0
|
||||||
|
ClearBit(m_codeBuffer, codePos++); |
||||||
|
// adapt k (double the zero run-length)
|
||||||
|
if (k < WordWidth) { |
||||||
|
k++; |
||||||
|
runlen <<= 1; |
||||||
|
} |
||||||
|
|
||||||
|
// prepare for next run
|
||||||
|
count = 0; |
||||||
|
} |
||||||
|
|
||||||
|
// write 0 to sigBits
|
||||||
|
sigPos++; |
||||||
|
} |
||||||
|
valuePos++; |
||||||
|
} |
||||||
|
// refinement bit
|
||||||
|
if (valuePos < bufferSize) { |
||||||
|
// write one refinement bit
|
||||||
|
if (GetBitAtPos(valuePos++, planeMask)) { |
||||||
|
SetBit(refBits, refPos); |
||||||
|
} else { |
||||||
|
ClearBit(refBits, refPos); |
||||||
|
} |
||||||
|
refPos++; |
||||||
|
} |
||||||
|
} |
||||||
|
// RLE encoding of the rest of the plane
|
||||||
|
// encode run of count 0's followed by a 1
|
||||||
|
// with codeword: 1<count>(signBits[signPos])
|
||||||
|
SetBit(m_codeBuffer, codePos++);
|
||||||
|
if (k > 0) { |
||||||
|
SetValueBlock(m_codeBuffer, codePos, count, k); |
||||||
|
codePos += k; |
||||||
|
} |
||||||
|
// write dmmy sign bit
|
||||||
|
SetBit(m_codeBuffer, codePos++); |
||||||
|
|
||||||
|
// write word filler zeros
|
||||||
|
|
||||||
|
ASSERT(sigPos <= bufferSize); |
||||||
|
ASSERT(refPos <= bufferSize); |
||||||
|
ASSERT(signLen <= bufferSize); |
||||||
|
ASSERT(valuePos == bufferSize); |
||||||
|
ASSERT(codePos >= outStartPos && codePos < CodeBufferBitLen); |
||||||
|
codeLen = codePos - outStartPos; |
||||||
|
|
||||||
|
return sigPos; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////
|
||||||
|
// Compute number of bit planes needed
|
||||||
|
UINT8 CEncoder::CMacroBlock::NumberOfBitplanes() { |
||||||
|
UINT8 cnt = 0; |
||||||
|
|
||||||
|
// determine number of bitplanes for max value
|
||||||
|
if (m_maxAbsValue > 0) { |
||||||
|
while (m_maxAbsValue > 0) { |
||||||
|
m_maxAbsValue >>= 1; cnt++; |
||||||
|
} |
||||||
|
if (cnt == MaxBitPlanes + 1) cnt = 0; |
||||||
|
// end cs
|
||||||
|
ASSERT(cnt <= MaxBitPlanes); |
||||||
|
ASSERT((cnt >> MaxBitPlanesLog) == 0); |
||||||
|
return cnt; |
||||||
|
} else { |
||||||
|
return 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// Adaptive Run-Length encoder for long sequences of ones.
|
||||||
|
// Returns length of output in bits.
|
||||||
|
// - Encode run of 2^k ones by a single 1.
|
||||||
|
// - Encode run of count 1's followed by a 0 with codeword: 0<count>.
|
||||||
|
// - Store each bit in m_codeBuffer[codePos] and increment codePos.
|
||||||
|
UINT32 CEncoder::CMacroBlock::RLESigns(UINT32 codePos, UINT32* signBits, UINT32 signLen) { |
||||||
|
ASSERT(signBits); |
||||||
|
ASSERT(0 <= codePos && codePos < CodeBufferBitLen); |
||||||
|
ASSERT(0 < signLen && signLen <= BufferSize); |
||||||
|
|
||||||
|
const UINT32 outStartPos = codePos; |
||||||
|
UINT32 k = 0; |
||||||
|
UINT32 runlen = 1 << k; // = 2^k
|
||||||
|
UINT32 count = 0; |
||||||
|
UINT32 signPos = 0; |
||||||
|
|
||||||
|
while (signPos < signLen) { |
||||||
|
// search next 0 in signBits starting at position signPos
|
||||||
|
count = SeekBit1Range(signBits, signPos, __min(runlen, signLen - signPos)); |
||||||
|
// count 1's found
|
||||||
|
if (count == runlen) { |
||||||
|
// encode run of 2^k ones by a single 1
|
||||||
|
signPos += count;
|
||||||
|
SetBit(m_codeBuffer, codePos++); |
||||||
|
// adapt k (double the 1's run-length)
|
||||||
|
if (k < WordWidth) { |
||||||
|
k++;
|
||||||
|
runlen <<= 1; |
||||||
|
} |
||||||
|
} else { |
||||||
|
// encode run of count 1's followed by a 0
|
||||||
|
// with codeword: 0(count)
|
||||||
|
signPos += count + 1; |
||||||
|
ClearBit(m_codeBuffer, codePos++); |
||||||
|
if (k > 0) { |
||||||
|
SetValueBlock(m_codeBuffer, codePos, count, k); |
||||||
|
codePos += k; |
||||||
|
} |
||||||
|
// adapt k (half the 1's run-length)
|
||||||
|
if (k > 0) { |
||||||
|
k--;
|
||||||
|
runlen >>= 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
ASSERT(signPos == signLen || signPos == signLen + 1); |
||||||
|
ASSERT(codePos >= outStartPos && codePos < CodeBufferBitLen); |
||||||
|
return codePos - outStartPos; |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
#ifdef TRACE |
||||||
|
void CEncoder::DumpBuffer() const { |
||||||
|
//printf("\nDump\n");
|
||||||
|
//for (UINT32 i=0; i < BufferSize; i++) {
|
||||||
|
// printf("%d", m_value[i]);
|
||||||
|
//}
|
||||||
|
//printf("\n");
|
||||||
|
} |
||||||
|
#endif //TRACE
|
||||||
|
|
||||||
|
|
@ -0,0 +1,235 @@ |
|||||||
|
/*
|
||||||
|
* The Progressive Graphics File; http://www.libpgf.org
|
||||||
|
*
|
||||||
|
* $Date: 2006-06-04 22:05:59 +0200 (So, 04 Jun 2006) $ |
||||||
|
* $Revision: 229 $ |
||||||
|
*
|
||||||
|
* This file Copyright (C) 2006 xeraina GmbH, Switzerland |
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE |
||||||
|
* as published by the Free Software Foundation; either version 2.1 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||||
|
*/ |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// @file Encoder.h
|
||||||
|
/// @brief PGF encoder class
|
||||||
|
/// @author C. Stamm, R. Spuler
|
||||||
|
|
||||||
|
#ifndef PGF_ENCODER_H |
||||||
|
#define PGF_ENCODER_H |
||||||
|
|
||||||
|
#include "PGFstream.h" |
||||||
|
#include "BitStream.h" |
||||||
|
#include "Subband.h" |
||||||
|
#include "WaveletTransform.h" |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// Constants
|
||||||
|
#define BufferLen (BufferSize/WordWidth) ///< number of words per buffer
|
||||||
|
#define CodeBufferLen BufferSize ///< number of words in code buffer (CodeBufferLen > BufferLen)
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// PGF encoder class.
|
||||||
|
/// @author C. Stamm
|
||||||
|
/// @brief PGF encoder
|
||||||
|
class CEncoder { |
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// PGF encoder macro block class.
|
||||||
|
/// @author C. Stamm, I. Bauersachs
|
||||||
|
/// @brief A macro block is an encoding unit of fixed size (uncoded)
|
||||||
|
class CMacroBlock { |
||||||
|
public: |
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Constructor: Initializes new macro block.
|
||||||
|
/// @param encoder Pointer to outer class.
|
||||||
|
CMacroBlock(CEncoder *encoder) |
||||||
|
#ifdef _MSC_VER |
||||||
|
#pragma warning( suppress : 4351 ) |
||||||
|
#endif |
||||||
|
: m_value() |
||||||
|
, m_codeBuffer() |
||||||
|
, m_header(0) |
||||||
|
, m_encoder(encoder) |
||||||
|
, m_sigFlagVector() |
||||||
|
{ |
||||||
|
ASSERT(m_encoder); |
||||||
|
Init(-1); |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Reinitialzes this macro block (allows reusage).
|
||||||
|
/// @param lastLevelIndex Level length directory index of last encoded level: [0, nLevels)
|
||||||
|
void Init(int lastLevelIndex) { // initialize for reusage
|
||||||
|
m_valuePos = 0; |
||||||
|
m_maxAbsValue = 0; |
||||||
|
m_codePos = 0; |
||||||
|
m_lastLevelIndex = lastLevelIndex; |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Encodes this macro block into internal code buffer.
|
||||||
|
/// Several macro blocks can be encoded in parallel.
|
||||||
|
/// Call CEncoder::WriteMacroBlock after this method.
|
||||||
|
void BitplaneEncode(); |
||||||
|
|
||||||
|
DataT m_value[BufferSize]; ///< input buffer of values with index m_valuePos
|
||||||
|
UINT32 m_codeBuffer[CodeBufferLen]; ///< output buffer for encoded bitstream
|
||||||
|
ROIBlockHeader m_header; ///< block header
|
||||||
|
UINT32 m_valuePos; ///< current buffer position
|
||||||
|
UINT32 m_maxAbsValue; ///< maximum absolute coefficient in each buffer
|
||||||
|
UINT32 m_codePos; ///< current position in encoded bitstream
|
||||||
|
int m_lastLevelIndex; ///< index of last encoded level: [0, nLevels); used because a level-end can occur before a buffer is full
|
||||||
|
|
||||||
|
private: |
||||||
|
UINT32 RLESigns(UINT32 codePos, UINT32* signBits, UINT32 signLen); |
||||||
|
UINT32 DecomposeBitplane(UINT32 bufferSize, UINT32 planeMask, UINT32 codePos, UINT32* sigBits, UINT32* refBits, UINT32* signBits, UINT32& signLen, UINT32& codeLen); |
||||||
|
UINT8 NumberOfBitplanes(); |
||||||
|
bool GetBitAtPos(UINT32 pos, UINT32 planeMask) const { return (abs(m_value[pos]) & planeMask) > 0; }
|
||||||
|
|
||||||
|
CEncoder *m_encoder; // encoder instance
|
||||||
|
bool m_sigFlagVector[BufferSize+1]; // see paper from Malvar, Fast Progressive Wavelet Coder
|
||||||
|
}; |
||||||
|
|
||||||
|
public: |
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Write pre-header, header, post-Header, and levelLength.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param stream A PGF stream
|
||||||
|
/// @param preHeader A already filled in PGF pre-header
|
||||||
|
/// @param header An already filled in PGF header
|
||||||
|
/// @param postHeader [in] An already filled in PGF post-header (containing color table, user data, ...)
|
||||||
|
/// @param userDataPos [out] File position of user data
|
||||||
|
/// @param useOMP If true, then the encoder will use multi-threading based on openMP
|
||||||
|
CEncoder(CPGFStream* stream, PGFPreHeader preHeader, PGFHeader header, const PGFPostHeader& postHeader,
|
||||||
|
UINT64& userDataPos, bool useOMP); // throws IOException
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Destructor
|
||||||
|
~CEncoder(); |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Encoder favors speed over compression size
|
||||||
|
void FavorSpeedOverSize() { m_favorSpeed = true; } |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Pad buffer with zeros and encode buffer.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
void Flush(); |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Increase post-header size and write new size into stream.
|
||||||
|
/// @param preHeader An already filled in PGF pre-header
|
||||||
|
/// It might throw an IOException.
|
||||||
|
void UpdatePostHeaderSize(PGFPreHeader preHeader); |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Create level length data structure and write a place holder into stream.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param levelLength A reference to an integer array, large enough to save the relative file positions of all PGF levels
|
||||||
|
/// @return number of bytes written into stream
|
||||||
|
UINT32 WriteLevelLength(UINT32*& levelLength); |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Write new levelLength into stream.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @return Written image bytes.
|
||||||
|
UINT32 UpdateLevelLength(); |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Partitions a rectangular region of a given subband.
|
||||||
|
/// Partitioning scheme: The plane is partitioned in squares of side length LinBlockSize.
|
||||||
|
/// Write wavelet coefficients from subband into the input buffer of a macro block.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param band A subband
|
||||||
|
/// @param width The width of the rectangle
|
||||||
|
/// @param height The height of the rectangle
|
||||||
|
/// @param startPos The absolute subband position of the top left corner of the rectangular region
|
||||||
|
/// @param pitch The number of bytes in row of the subband
|
||||||
|
void Partition(CSubband* band, int width, int height, int startPos, int pitch); |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Informs the encoder about the encoded level.
|
||||||
|
/// @param currentLevel encoded level [0, nLevels)
|
||||||
|
void SetEncodedLevel(int currentLevel) { ASSERT(currentLevel >= 0); m_currentBlock->m_lastLevelIndex = m_nLevels - currentLevel - 1; m_forceWriting = true; } |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Write a single value into subband at given position.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param band A subband
|
||||||
|
/// @param bandPos A valid position in subband band
|
||||||
|
void WriteValue(CSubband* band, int bandPos); |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Compute stream length of header.
|
||||||
|
/// @return header length
|
||||||
|
INT64 ComputeHeaderLength() const { return m_levelLengthPos - m_startPosition; } |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Compute stream length of encoded buffer.
|
||||||
|
/// @return encoded buffer length
|
||||||
|
INT64 ComputeBufferLength() const { return m_stream->GetPos() - m_bufferStartPos; } |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Compute file offset between real and expected levelLength position.
|
||||||
|
/// @return file offset
|
||||||
|
INT64 ComputeOffset() const { return m_stream->GetPos() - m_levelLengthPos; } |
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
/// Resets stream position to beginning of PGF pre-header
|
||||||
|
void SetStreamPosToStart() { ASSERT(m_stream); m_stream->SetPos(FSFromStart, m_startPosition); } |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Save current stream position as beginning of current level.
|
||||||
|
void SetBufferStartPos() { m_bufferStartPos = m_stream->GetPos(); } |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Encodes tile buffer and writes it into stream
|
||||||
|
/// It might throw an IOException.
|
||||||
|
void EncodeTileBuffer() { ASSERT(m_currentBlock && m_currentBlock->m_valuePos >= 0 && m_currentBlock->m_valuePos <= BufferSize); EncodeBuffer(ROIBlockHeader(m_currentBlock->m_valuePos, true)); } |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Enables region of interest (ROI) status.
|
||||||
|
void SetROI() { m_roi = true; } |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef TRACE |
||||||
|
void DumpBuffer() const; |
||||||
|
#endif |
||||||
|
|
||||||
|
private: |
||||||
|
void EncodeBuffer(ROIBlockHeader h); // throws IOException
|
||||||
|
void WriteMacroBlock(CMacroBlock* block); // throws IOException
|
||||||
|
|
||||||
|
CPGFStream *m_stream; ///< output PMF stream
|
||||||
|
UINT64 m_startPosition; ///< stream position of PGF start (PreHeader)
|
||||||
|
UINT64 m_levelLengthPos; ///< stream position of Metadata
|
||||||
|
UINT64 m_bufferStartPos; ///< stream position of encoded buffer
|
||||||
|
|
||||||
|
CMacroBlock **m_macroBlocks; ///< array of macroblocks
|
||||||
|
int m_macroBlockLen; ///< array length
|
||||||
|
int m_lastMacroBlock; ///< array index of the last created macro block
|
||||||
|
CMacroBlock *m_currentBlock; ///< current macro block (used by main thread)
|
||||||
|
|
||||||
|
UINT32* m_levelLength; ///< temporary saves the level index
|
||||||
|
int m_currLevelIndex; ///< counts where (=index) to save next value
|
||||||
|
UINT8 m_nLevels; ///< number of levels
|
||||||
|
bool m_favorSpeed; ///< favor speed over size
|
||||||
|
bool m_forceWriting; ///< all macro blocks have to be written into the stream
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
bool m_roi; ///< true: ensures region of interest (ROI) encoding
|
||||||
|
#endif |
||||||
|
}; |
||||||
|
|
||||||
|
#endif //PGF_ENCODER
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,581 @@ |
|||||||
|
/*
|
||||||
|
* The Progressive Graphics File; http://www.libpgf.org
|
||||||
|
*
|
||||||
|
* $Date: 2007-02-03 13:04:21 +0100 (Sa, 03 Feb 2007) $ |
||||||
|
* $Revision: 280 $ |
||||||
|
*
|
||||||
|
* This file Copyright (C) 2006 xeraina GmbH, Switzerland |
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE |
||||||
|
* as published by the Free Software Foundation; either version 2.1 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||||
|
*/ |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// @file PGFimage.h
|
||||||
|
/// @brief PGF image class
|
||||||
|
/// @author C. Stamm
|
||||||
|
|
||||||
|
#ifndef PGF_PGFIMAGE_H |
||||||
|
#define PGF_PGFIMAGE_H |
||||||
|
|
||||||
|
#include "PGFstream.h" |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// prototypes
|
||||||
|
class CDecoder; |
||||||
|
class CEncoder; |
||||||
|
class CWaveletTransform; |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// PGF image class is the main class. You always need a PGF object
|
||||||
|
/// for encoding or decoding image data.
|
||||||
|
/// Decoding:
|
||||||
|
/// Open()
|
||||||
|
/// Read()
|
||||||
|
/// GetBitmap()
|
||||||
|
/// Encoding:
|
||||||
|
/// SetHeader()
|
||||||
|
/// ImportBitmap()
|
||||||
|
/// Write()
|
||||||
|
/// @author C. Stamm, R. Spuler
|
||||||
|
/// @brief PGF main class
|
||||||
|
class CPGFImage { |
||||||
|
public: |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Standard constructor
|
||||||
|
CPGFImage(); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Destructor
|
||||||
|
virtual ~CPGFImage(); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// Destroy internal data structures. Object state after this is the same as after CPGFImage().
|
||||||
|
void Destroy(); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Open a PGF image at current stream position: read pre-header, header, and ckeck image type.
|
||||||
|
/// Precondition: The stream has been opened for reading.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param stream A PGF stream
|
||||||
|
void Open(CPGFStream* stream); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Returns true if the PGF has been opened for reading.
|
||||||
|
bool IsOpen() const { return m_decoder != nullptr; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Read and decode some levels of a PGF image at current stream position.
|
||||||
|
/// A PGF image is structered in levels, numbered between 0 and Levels() - 1.
|
||||||
|
/// Each level can be seen as a single image, containing the same content
|
||||||
|
/// as all other levels, but in a different size (width, height).
|
||||||
|
/// The image size at level i is double the size (width, height) of the image at level i+1.
|
||||||
|
/// The image at level 0 contains the original size.
|
||||||
|
/// Precondition: The PGF image has been opened with a call of Open(...).
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param level [0, nLevels) The image level of the resulting image in the internal image buffer.
|
||||||
|
/// @param cb A pointer to a callback procedure. The procedure is called after reading a single level. If cb returns true, then it stops proceeding.
|
||||||
|
/// @param data Data Pointer to C++ class container to host callback procedure.
|
||||||
|
void Read(int level = 0, CallbackPtr cb = nullptr, void *data = nullptr); |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Read a rectangular region of interest of a PGF image at current stream position.
|
||||||
|
/// The origin of the coordinate axis is the top-left corner of the image.
|
||||||
|
/// All coordinates are measured in pixels.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param rect [inout] Rectangular region of interest (ROI) at level 0. The rect might be cropped.
|
||||||
|
/// @param level [0, nLevels) The image level of the resulting image in the internal image buffer.
|
||||||
|
/// @param cb A pointer to a callback procedure. The procedure is called after reading a single level. If cb returns true, then it stops proceeding.
|
||||||
|
/// @param data Data Pointer to C++ class container to host callback procedure.
|
||||||
|
void Read(PGFRect& rect, int level = 0, CallbackPtr cb = nullptr, void *data = nullptr); |
||||||
|
#endif |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Read and decode smallest level of a PGF image at current stream position.
|
||||||
|
/// For details, please refert to Read(...)
|
||||||
|
/// Precondition: The PGF image has been opened with a call of Open(...).
|
||||||
|
/// It might throw an IOException.
|
||||||
|
void ReadPreview() { Read(Levels() - 1); } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// After you've written a PGF image, you can call this method followed by GetBitmap/GetYUV
|
||||||
|
/// to get a quick reconstruction (coded -> decoded image).
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param level The image level of the resulting image in the internal image buffer.
|
||||||
|
void Reconstruct(int level = 0); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Get image data in interleaved format: (ordering of RGB data is BGR[A])
|
||||||
|
/// Upsampling, YUV to RGB transform and interleaving are done here to reduce the number
|
||||||
|
/// of passes over the data.
|
||||||
|
/// The absolute value of pitch is the number of bytes of an image row of the given image buffer.
|
||||||
|
/// If pitch is negative, then the image buffer must point to the last row of a bottom-up image (first byte on last row).
|
||||||
|
/// if pitch is positive, then the image buffer must point to the first row of a top-down image (first byte).
|
||||||
|
/// The sequence of output channels in the output image buffer does not need to be the same as provided by PGF. In case of different sequences you have to
|
||||||
|
/// provide a channelMap of size of expected channels (depending on image mode). For example, PGF provides a channel sequence BGR in RGB color mode.
|
||||||
|
/// If your provided image buffer expects a channel sequence ARGB, then the channelMap looks like { 3, 2, 1, 0 }.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param pitch The number of bytes of a row of the image buffer.
|
||||||
|
/// @param buff An image buffer.
|
||||||
|
/// @param bpp The number of bits per pixel used in image buffer.
|
||||||
|
/// @param channelMap A integer array containing the mapping of PGF channel ordering to expected channel ordering.
|
||||||
|
/// @param cb A pointer to a callback procedure. The procedure is called after each copied buffer row. If cb returns true, then it stops proceeding.
|
||||||
|
/// @param data Data Pointer to C++ class container to host callback procedure.
|
||||||
|
void GetBitmap(int pitch, UINT8* buff, BYTE bpp, int channelMap[] = nullptr, CallbackPtr cb = nullptr, void *data = nullptr) const; // throws IOException
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Get YUV image data in interleaved format: (ordering is YUV[A])
|
||||||
|
/// The absolute value of pitch is the number of bytes of an image row of the given image buffer.
|
||||||
|
/// If pitch is negative, then the image buffer must point to the last row of a bottom-up image (first byte on last row).
|
||||||
|
/// if pitch is positive, then the image buffer must point to the first row of a top-down image (first byte).
|
||||||
|
/// The sequence of output channels in the output image buffer does not need to be the same as provided by PGF. In case of different sequences you have to
|
||||||
|
/// provide a channelMap of size of expected channels (depending on image mode). For example, PGF provides a channel sequence BGR in RGB color mode.
|
||||||
|
/// If your provided image buffer expects a channel sequence VUY, then the channelMap looks like { 2, 1, 0 }.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param pitch The number of bytes of a row of the image buffer.
|
||||||
|
/// @param buff An image buffer.
|
||||||
|
/// @param bpp The number of bits per pixel used in image buffer.
|
||||||
|
/// @param channelMap A integer array containing the mapping of PGF channel ordering to expected channel ordering.
|
||||||
|
/// @param cb A pointer to a callback procedure. The procedure is called after each copied buffer row. If cb returns true, then it stops proceeding.
|
||||||
|
/// @param data Data Pointer to C++ class container to host callback procedure.
|
||||||
|
void GetYUV(int pitch, DataT* buff, BYTE bpp, int channelMap[] = nullptr, CallbackPtr cb = nullptr, void *data = nullptr) const; // throws IOException
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Import an image from a specified image buffer.
|
||||||
|
/// This method is usually called before Write(...) and after SetHeader(...).
|
||||||
|
/// The absolute value of pitch is the number of bytes of an image row.
|
||||||
|
/// If pitch is negative, then buff points to the last row of a bottom-up image (first byte on last row).
|
||||||
|
/// If pitch is positive, then buff points to the first row of a top-down image (first byte).
|
||||||
|
/// The sequence of input channels in the input image buffer does not need to be the same as expected from PGF. In case of different sequences you have to
|
||||||
|
/// provide a channelMap of size of expected channels (depending on image mode). For example, PGF expects in RGB color mode a channel sequence BGR.
|
||||||
|
/// If your provided image buffer contains a channel sequence ARGB, then the channelMap looks like { 3, 2, 1, 0 }.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param pitch The number of bytes of a row of the image buffer.
|
||||||
|
/// @param buff An image buffer.
|
||||||
|
/// @param bpp The number of bits per pixel used in image buffer.
|
||||||
|
/// @param channelMap A integer array containing the mapping of input channel ordering to expected channel ordering.
|
||||||
|
/// @param cb A pointer to a callback procedure. The procedure is called after each imported buffer row. If cb returns true, then it stops proceeding.
|
||||||
|
/// @param data Data Pointer to C++ class container to host callback procedure.
|
||||||
|
void ImportBitmap(int pitch, UINT8 *buff, BYTE bpp, int channelMap[] = nullptr, CallbackPtr cb = nullptr, void *data = nullptr); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Import a YUV image from a specified image buffer.
|
||||||
|
/// The absolute value of pitch is the number of bytes of an image row.
|
||||||
|
/// If pitch is negative, then buff points to the last row of a bottom-up image (first byte on last row).
|
||||||
|
/// If pitch is positive, then buff points to the first row of a top-down image (first byte).
|
||||||
|
/// The sequence of input channels in the input image buffer does not need to be the same as expected from PGF. In case of different sequences you have to
|
||||||
|
/// provide a channelMap of size of expected channels (depending on image mode). For example, PGF expects in RGB color mode a channel sequence BGR.
|
||||||
|
/// If your provided image buffer contains a channel sequence VUY, then the channelMap looks like { 2, 1, 0 }.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param pitch The number of bytes of a row of the image buffer.
|
||||||
|
/// @param buff An image buffer.
|
||||||
|
/// @param bpp The number of bits per pixel used in image buffer.
|
||||||
|
/// @param channelMap A integer array containing the mapping of input channel ordering to expected channel ordering.
|
||||||
|
/// @param cb A pointer to a callback procedure. The procedure is called after each imported buffer row. If cb returns true, then it stops proceeding.
|
||||||
|
/// @param data Data Pointer to C++ class container to host callback procedure.
|
||||||
|
void ImportYUV(int pitch, DataT *buff, BYTE bpp, int channelMap[] = nullptr, CallbackPtr cb = nullptr, void *data = nullptr); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Encode and write an entire PGF image (header and image) at current stream position.
|
||||||
|
/// A PGF image is structered in levels, numbered between 0 and Levels() - 1.
|
||||||
|
/// Each level can be seen as a single image, containing the same content
|
||||||
|
/// as all other levels, but in a different size (width, height).
|
||||||
|
/// The image size at level i is double the size (width, height) of the image at level i+1.
|
||||||
|
/// The image at level 0 contains the original size.
|
||||||
|
/// Precondition: the PGF image contains a valid header (see also SetHeader(...)).
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param stream A PGF stream
|
||||||
|
/// @param nWrittenBytes [in-out] The number of bytes written into stream are added to the input value.
|
||||||
|
/// @param cb A pointer to a callback procedure. The procedure is called after writing a single level. If cb returns true, then it stops proceeding.
|
||||||
|
/// @param data Data Pointer to C++ class container to host callback procedure.
|
||||||
|
void Write(CPGFStream* stream, UINT32* nWrittenBytes = nullptr, CallbackPtr cb = nullptr, void *data = nullptr); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
/// Create wavelet transform channels and encoder. Write header at current stream position.
|
||||||
|
/// Call this method before your first call of Write(int level) or WriteImage(), but after SetHeader().
|
||||||
|
/// This method is called inside of Write(stream, ...).
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param stream A PGF stream
|
||||||
|
/// @return The number of bytes written into stream.
|
||||||
|
UINT32 WriteHeader(CPGFStream* stream); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Encode and write an image at current stream position.
|
||||||
|
/// Call this method after WriteHeader(). In case you want to write uncached metadata,
|
||||||
|
/// then do that after WriteHeader() and before WriteImage().
|
||||||
|
/// This method is called inside of Write(stream, ...).
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param stream A PGF stream
|
||||||
|
/// @param cb A pointer to a callback procedure. The procedure is called after writing a single level. If cb returns true, then it stops proceeding.
|
||||||
|
/// @param data Data Pointer to C++ class container to host callback procedure.
|
||||||
|
/// @return The number of bytes written into stream.
|
||||||
|
UINT32 WriteImage(CPGFStream* stream, CallbackPtr cb = nullptr, void *data = nullptr); |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
/// Encode and write down to given level at current stream position.
|
||||||
|
/// A PGF image is structered in levels, numbered between 0 and Levels() - 1.
|
||||||
|
/// Each level can be seen as a single image, containing the same content
|
||||||
|
/// as all other levels, but in a different size (width, height).
|
||||||
|
/// The image size at level i is double the size (width, height) of the image at level i+1.
|
||||||
|
/// The image at level 0 contains the original size.
|
||||||
|
/// Preconditions: the PGF image contains a valid header (see also SetHeader(...)) and
|
||||||
|
/// WriteHeader() has been called before. Levels() > 0.
|
||||||
|
/// The ROI encoding scheme must be used (see also SetHeader(...)).
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param level [0, nLevels) The image level of the resulting image in the internal image buffer.
|
||||||
|
/// @param cb A pointer to a callback procedure. The procedure is called after writing a single level. If cb returns true, then it stops proceeding.
|
||||||
|
/// @param data Data Pointer to C++ class container to host callback procedure.
|
||||||
|
/// @return The number of bytes written into stream.
|
||||||
|
UINT32 Write(int level, CallbackPtr cb = nullptr, void *data = nullptr); |
||||||
|
#endif |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Configures the encoder.
|
||||||
|
/// @param useOMP Use parallel threading with Open MP during encoding. Default value: true. Influences the encoding only if the codec has been compiled with OpenMP support.
|
||||||
|
/// @param favorSpeedOverSize Favors encoding speed over compression ratio. Default value: false
|
||||||
|
void ConfigureEncoder(bool useOMP = true, bool favorSpeedOverSize = false) { m_useOMPinEncoder = useOMP; m_favorSpeedOverSize = favorSpeedOverSize; } |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Configures the decoder.
|
||||||
|
/// @param useOMP Use parallel threading with Open MP during decoding. Default value: true. Influences the decoding only if the codec has been compiled with OpenMP support.
|
||||||
|
/// @param policy The file might contain user data (e.g. metadata). The policy defines the behaviour during Open().
|
||||||
|
/// UP_CacheAll: User data is read and stored completely in a new allocated memory block. It can be accessed by GetUserData().
|
||||||
|
/// UP_CachePrefix: Only prefixSize bytes at the beginning of the user data are stored in a new allocated memory block. It can be accessed by GetUserData().
|
||||||
|
/// UP_Skip: User data is skipped and nothing is cached.
|
||||||
|
/// @param prefixSize Is only used in combination with UP_CachePrefix. It defines the number of bytes cached.
|
||||||
|
void ConfigureDecoder(bool useOMP = true, UserdataPolicy policy = UP_CacheAll, UINT32 prefixSize = 0) { ASSERT(prefixSize <= MaxUserDataSize); m_useOMPinDecoder = useOMP; m_userDataPolicy = (UP_CachePrefix) ? prefixSize : 0xFFFFFFFF - policy; } |
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
/// Reset stream position to start of PGF pre-header or start of data. Must not be called before Open() or before Write().
|
||||||
|
/// Use this method after Read() if you want to read the same image several times, e.g. reading different ROIs.
|
||||||
|
/// @param startOfData true: you want to read the same image several times. false: resets stream position to the initial position
|
||||||
|
void ResetStreamPos(bool startOfData); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Set internal PGF image buffer channel.
|
||||||
|
/// @param channel A YUV data channel
|
||||||
|
/// @param c A channel index
|
||||||
|
void SetChannel(DataT* channel, int c = 0) { ASSERT(c >= 0 && c < MaxChannels); m_channel[c] = channel; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Set PGF header and user data.
|
||||||
|
/// Precondition: The PGF image has been never opened with Open(...).
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param header A valid and already filled in PGF header structure
|
||||||
|
/// @param flags A combination of additional version flags. In case you use level-wise encoding then set flag = PGFROI.
|
||||||
|
/// @param userData A user-defined memory block containing any kind of cached metadata.
|
||||||
|
/// @param userDataLength The size of user-defined memory block in bytes
|
||||||
|
void SetHeader(const PGFHeader& header, BYTE flags = 0, const UINT8* userData = 0, UINT32 userDataLength = 0); // throws IOException
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Set maximum intensity value for image modes with more than eight bits per channel.
|
||||||
|
/// Call this method after SetHeader, but before ImportBitmap.
|
||||||
|
/// @param maxValue The maximum intensity value.
|
||||||
|
void SetMaxValue(UINT32 maxValue); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Set progress mode used in Read and Write.
|
||||||
|
/// Default mode is PM_Relative.
|
||||||
|
/// This method must be called before Open() or SetHeader().
|
||||||
|
/// PM_Relative: 100% = level difference between current level and target level of Read/Write
|
||||||
|
/// PM_Absolute: 100% = number of levels
|
||||||
|
void SetProgressMode(ProgressMode pm) { m_progressMode = pm; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Set refresh callback procedure and its parameter.
|
||||||
|
/// The refresh callback is called during Read(...) after each level read.
|
||||||
|
/// @param callback A refresh callback procedure
|
||||||
|
/// @param arg A parameter of the refresh callback procedure
|
||||||
|
void SetRefreshCallback(RefreshCB callback, void* arg) { m_cb = callback; m_cbArg = arg; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Sets the red, green, blue (RGB) color values for a range of entries in the palette (clut).
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param iFirstColor The color table index of the first entry to set.
|
||||||
|
/// @param nColors The number of color table entries to set.
|
||||||
|
/// @param prgbColors A pointer to the array of RGBQUAD structures to set the color table entries.
|
||||||
|
void SetColorTable(UINT32 iFirstColor, UINT32 nColors, const RGBQUAD* prgbColors); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return an internal YUV image channel.
|
||||||
|
/// @param c A channel index
|
||||||
|
/// @return An internal YUV image channel
|
||||||
|
DataT* GetChannel(int c = 0) { ASSERT(c >= 0 && c < MaxChannels); return m_channel[c]; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Retrieves red, green, blue (RGB) color values from a range of entries in the palette of the DIB section.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param iFirstColor The color table index of the first entry to retrieve.
|
||||||
|
/// @param nColors The number of color table entries to retrieve.
|
||||||
|
/// @param prgbColors A pointer to the array of RGBQUAD structures to retrieve the color table entries.
|
||||||
|
void GetColorTable(UINT32 iFirstColor, UINT32 nColors, RGBQUAD* prgbColors) const; |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// Returns address of internal color table
|
||||||
|
/// @return Address of color table
|
||||||
|
const RGBQUAD* GetColorTable() const { return m_postHeader.clut; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return the PGF header structure.
|
||||||
|
/// @return A PGF header structure
|
||||||
|
const PGFHeader* GetHeader() const { return &m_header; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Get maximum intensity value for image modes with more than eight bits per channel.
|
||||||
|
/// Don't call this method before the PGF header has been read.
|
||||||
|
/// @return The maximum intensity value.
|
||||||
|
UINT32 GetMaxValue() const { return (1 << m_header.usedBitsPerChannel) - 1; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return the stream position of the user data or 0.
|
||||||
|
/// Precondition: The PGF image has been opened with a call of Open(...).
|
||||||
|
UINT64 GetUserDataPos() const { return m_userDataPos; }
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return user data and size of user data.
|
||||||
|
/// Precondition: The PGF image has been opened with a call of Open(...).
|
||||||
|
/// @param cachedSize [out] Size of returned user data in bytes.
|
||||||
|
/// @param pTotalSize [optional out] Pointer to return the size of user data stored in image header in bytes.
|
||||||
|
/// @return A pointer to user data or nullptr if there is no user data available.
|
||||||
|
const UINT8* GetUserData(UINT32& cachedSize, UINT32* pTotalSize = nullptr) const; |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return the length of all encoded headers in bytes.
|
||||||
|
/// Precondition: The PGF image has been opened with a call of Open(...).
|
||||||
|
/// @return The length of all encoded headers in bytes
|
||||||
|
UINT32 GetEncodedHeaderLength() const; |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return the length of an encoded PGF level in bytes.
|
||||||
|
/// Precondition: The PGF image has been opened with a call of Open(...).
|
||||||
|
/// @param level The image level
|
||||||
|
/// @return The length of a PGF level in bytes
|
||||||
|
UINT32 GetEncodedLevelLength(int level) const { ASSERT(level >= 0 && level < m_header.nLevels); return m_levelLength[m_header.nLevels - level - 1]; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Reads the encoded PGF header and copies it to a target buffer.
|
||||||
|
/// Precondition: The PGF image has been opened with a call of Open(...).
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param target The target buffer
|
||||||
|
/// @param targetLen The length of the target buffer in bytes
|
||||||
|
/// @return The number of bytes copied to the target buffer
|
||||||
|
UINT32 ReadEncodedHeader(UINT8* target, UINT32 targetLen) const; |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Reads the data of an encoded PGF level and copies it to a target buffer
|
||||||
|
/// without decoding.
|
||||||
|
/// Precondition: The PGF image has been opened with a call of Open(...).
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param level The image level
|
||||||
|
/// @param target The target buffer
|
||||||
|
/// @param targetLen The length of the target buffer in bytes
|
||||||
|
/// @return The number of bytes copied to the target buffer
|
||||||
|
UINT32 ReadEncodedData(int level, UINT8* target, UINT32 targetLen) const; |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return current image width of given channel in pixels.
|
||||||
|
/// The returned width depends on the levels read so far and on ROI.
|
||||||
|
/// @param c A channel index
|
||||||
|
/// @return Channel width in pixels
|
||||||
|
UINT32 ChannelWidth(int c = 0) const { ASSERT(c >= 0 && c < MaxChannels); return m_width[c]; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return current image height of given channel in pixels.
|
||||||
|
/// The returned height depends on the levels read so far and on ROI.
|
||||||
|
/// @param c A channel index
|
||||||
|
/// @return Channel height in pixels
|
||||||
|
UINT32 ChannelHeight(int c = 0) const { ASSERT(c >= 0 && c < MaxChannels); return m_height[c]; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return bits per channel of the image's encoder.
|
||||||
|
/// @return Bits per channel
|
||||||
|
BYTE ChannelDepth() const { return MaxChannelDepth(m_preHeader.version); } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return image width of channel 0 at given level in pixels.
|
||||||
|
/// The returned width is independent of any Read-operations and ROI.
|
||||||
|
/// @param level A level
|
||||||
|
/// @return Image level width in pixels
|
||||||
|
UINT32 Width(int level = 0) const { ASSERT(level >= 0); return LevelSizeL(m_header.width, level); } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return image height of channel 0 at given level in pixels.
|
||||||
|
/// The returned height is independent of any Read-operations and ROI.
|
||||||
|
/// @param level A level
|
||||||
|
/// @return Image level height in pixels
|
||||||
|
UINT32 Height(int level = 0) const { ASSERT(level >= 0); return LevelSizeL(m_header.height, level); } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return current image level.
|
||||||
|
/// Since Read(...) can be used to read each image level separately, it is
|
||||||
|
/// helpful to know the current level. The current level immediately after Open(...) is Levels().
|
||||||
|
/// @return Current image level
|
||||||
|
BYTE Level() const { return (BYTE)m_currentLevel; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return the number of image levels.
|
||||||
|
/// @return Number of image levels
|
||||||
|
BYTE Levels() const { return m_header.nLevels; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return true if all levels have been read
|
||||||
|
bool IsFullyRead() const { return m_currentLevel == 0; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return the PGF quality. The quality is inbetween 0 and MaxQuality.
|
||||||
|
/// PGF quality 0 means lossless quality.
|
||||||
|
/// @return PGF quality
|
||||||
|
BYTE Quality() const { return m_header.quality; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return the number of image channels.
|
||||||
|
/// An image of type RGB contains 3 image channels (B, G, R).
|
||||||
|
/// @return Number of image channels
|
||||||
|
BYTE Channels() const { return m_header.channels; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return the image mode.
|
||||||
|
/// An image mode is a predefined constant value (see also PGFtypes.h) compatible with Adobe Photoshop.
|
||||||
|
/// It represents an image type and format.
|
||||||
|
/// @return Image mode
|
||||||
|
BYTE Mode() const { return m_header.mode; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return the number of bits per pixel.
|
||||||
|
/// Valid values can be 1, 8, 12, 16, 24, 32, 48, 64.
|
||||||
|
/// @return Number of bits per pixel.
|
||||||
|
BYTE BPP() const { return m_header.bpp; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return true if the pgf image supports Region Of Interest (ROI).
|
||||||
|
/// @return true if the pgf image supports ROI.
|
||||||
|
bool ROIisSupported() const { return (m_preHeader.version & PGFROI) == PGFROI; } |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
/// Return ROI of channel 0 at current level in pixels.
|
||||||
|
/// The returned rect is only valid after reading a ROI.
|
||||||
|
/// @return ROI in pixels
|
||||||
|
PGFRect ComputeLevelROI() const; |
||||||
|
#endif |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Returns number of used bits per input/output image channel.
|
||||||
|
/// Precondition: header must be initialized.
|
||||||
|
/// @return number of used bits per input/output image channel.
|
||||||
|
BYTE UsedBitsPerChannel() const; |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Returns the used codec major version of a pgf image
|
||||||
|
/// @return PGF codec major version of this image
|
||||||
|
BYTE Version() const { BYTE ver = CodecMajorVersion(m_preHeader.version); return (ver <= 7) ? ver : (BYTE)m_header.version.major; } |
||||||
|
|
||||||
|
//class methods
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Check for valid import image mode.
|
||||||
|
/// @param mode Image mode
|
||||||
|
/// @return True if an image of given mode can be imported with ImportBitmap(...)
|
||||||
|
static bool ImportIsSupported(BYTE mode); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Compute and return image width/height of LL subband at given level.
|
||||||
|
/// @param size Original image size (e.g. width or height at level 0)
|
||||||
|
/// @param level An image level
|
||||||
|
/// @return Image width/height at given level in pixels
|
||||||
|
static UINT32 LevelSizeL(UINT32 size, int level) { ASSERT(level >= 0); UINT32 d = 1 << level; return (size + d - 1) >> level; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Compute and return image width/height of HH subband at given level.
|
||||||
|
/// @param size Original image size (e.g. width or height at level 0)
|
||||||
|
/// @param level An image level
|
||||||
|
/// @return high pass size at given level in pixels
|
||||||
|
static UINT32 LevelSizeH(UINT32 size, int level) { ASSERT(level >= 0); UINT32 d = 1 << (level - 1); return (size + d - 1) >> level; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return codec major version.
|
||||||
|
/// @param version pgf pre-header version number
|
||||||
|
/// @return PGF major of given version
|
||||||
|
static BYTE CodecMajorVersion(BYTE version = PGFVersion); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return maximum channel depth.
|
||||||
|
/// @param version pgf pre-header version number
|
||||||
|
/// @return maximum channel depth in bit of given version (16 or 32 bit)
|
||||||
|
static BYTE MaxChannelDepth(BYTE version = PGFVersion) { return (version & PGF32) ? 32 : 16; } |
||||||
|
|
||||||
|
protected: |
||||||
|
CWaveletTransform* m_wtChannel[MaxChannels]; ///< wavelet transformed color channels
|
||||||
|
DataT* m_channel[MaxChannels]; ///< untransformed channels in YUV format
|
||||||
|
CDecoder* m_decoder; ///< PGF decoder
|
||||||
|
CEncoder* m_encoder; ///< PGF encoder
|
||||||
|
UINT32* m_levelLength; ///< length of each level in bytes; first level starts immediately after this array
|
||||||
|
UINT32 m_width[MaxChannels]; ///< width of each channel at current level
|
||||||
|
UINT32 m_height[MaxChannels]; ///< height of each channel at current level
|
||||||
|
PGFPreHeader m_preHeader; ///< PGF pre-header
|
||||||
|
PGFHeader m_header; ///< PGF file header
|
||||||
|
PGFPostHeader m_postHeader; ///< PGF post-header
|
||||||
|
UINT64 m_userDataPos; ///< stream position of user data
|
||||||
|
int m_currentLevel; ///< transform level of current image
|
||||||
|
UINT32 m_userDataPolicy; ///< user data (metadata) policy during open
|
||||||
|
BYTE m_quant; ///< quantization parameter
|
||||||
|
bool m_downsample; ///< chrominance channels are downsampled
|
||||||
|
bool m_favorSpeedOverSize; ///< favor encoding speed over compression ratio
|
||||||
|
bool m_useOMPinEncoder; ///< use Open MP in encoder
|
||||||
|
bool m_useOMPinDecoder; ///< use Open MP in decoder
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
bool m_streamReinitialized; ///< stream has been reinitialized
|
||||||
|
PGFRect m_roi; ///< region of interest
|
||||||
|
#endif |
||||||
|
|
||||||
|
private:
|
||||||
|
RefreshCB m_cb; ///< pointer to refresh callback procedure
|
||||||
|
void *m_cbArg; ///< refresh callback argument
|
||||||
|
double m_percent; ///< progress [0..1]
|
||||||
|
ProgressMode m_progressMode; ///< progress mode used in Read and Write; PM_Relative is default mode
|
||||||
|
|
||||||
|
void Init(); |
||||||
|
void ComputeLevels(); |
||||||
|
bool CompleteHeader(); |
||||||
|
void RgbToYuv(int pitch, UINT8* rgbBuff, BYTE bpp, int channelMap[], CallbackPtr cb, void *data); |
||||||
|
void Downsample(int nChannel); |
||||||
|
UINT32 UpdatePostHeaderSize(); |
||||||
|
void WriteLevel(); |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
PGFRect GetAlignedROI(int c = 0) const; |
||||||
|
void SetROI(PGFRect rect); |
||||||
|
#endif |
||||||
|
|
||||||
|
UINT8 Clamp4(DataT v) const { |
||||||
|
if (v & 0xFFFFFFF0) return (v < 0) ? (UINT8)0: (UINT8)15; else return (UINT8)v; |
||||||
|
}
|
||||||
|
UINT16 Clamp6(DataT v) const { |
||||||
|
if (v & 0xFFFFFFC0) return (v < 0) ? (UINT16)0: (UINT16)63; else return (UINT16)v; |
||||||
|
}
|
||||||
|
UINT8 Clamp8(DataT v) const { |
||||||
|
// needs only one test in the normal case
|
||||||
|
if (v & 0xFFFFFF00) return (v < 0) ? (UINT8)0 : (UINT8)255; else return (UINT8)v; |
||||||
|
} |
||||||
|
UINT16 Clamp16(DataT v) const { |
||||||
|
if (v & 0xFFFF0000) return (v < 0) ? (UINT16)0: (UINT16)65535; else return (UINT16)v; |
||||||
|
}
|
||||||
|
UINT32 Clamp31(DataT v) const { |
||||||
|
return (v < 0) ? 0 : (UINT32)v; |
||||||
|
}
|
||||||
|
}; |
||||||
|
|
||||||
|
#endif //PGF_PGFIMAGE_H
|
@ -0,0 +1,631 @@ |
|||||||
|
/*
|
||||||
|
* The Progressive Graphics File; http://www.libpgf.org
|
||||||
|
*
|
||||||
|
* $Date: 2007-06-12 19:27:47 +0200 (Di, 12 Jun 2007) $ |
||||||
|
* $Revision: 307 $ |
||||||
|
*
|
||||||
|
* This file Copyright (C) 2006 xeraina GmbH, Switzerland |
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE |
||||||
|
* as published by the Free Software Foundation; either version 2.1 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||||
|
*/ |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// @file PGFplatform.h
|
||||||
|
/// @brief PGF platform specific definitions
|
||||||
|
/// @author C. Stamm
|
||||||
|
|
||||||
|
#ifndef PGF_PGFPLATFORM_H |
||||||
|
#define PGF_PGFPLATFORM_H |
||||||
|
|
||||||
|
#include <cassert> |
||||||
|
#include <cmath> |
||||||
|
#include <cstdlib> |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// Endianess detection taken from lcms2 header.
|
||||||
|
// This list can be endless, so only some checks are performed over here.
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#if defined(_HOST_BIG_ENDIAN) || defined(__BIG_ENDIAN__) || defined(WORDS_BIGENDIAN) |
||||||
|
#define PGF_USE_BIG_ENDIAN 1 |
||||||
|
#endif |
||||||
|
|
||||||
|
#if defined(__sgi__) || defined(__sgi) || defined(__powerpc__) || defined(__sparc) || defined(__sparc__) |
||||||
|
#define PGF_USE_BIG_ENDIAN 1 |
||||||
|
#endif |
||||||
|
|
||||||
|
#if defined(__ppc__) || defined(__s390__) || defined(__s390x__) |
||||||
|
#define PGF_USE_BIG_ENDIAN 1 |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef TARGET_CPU_PPC |
||||||
|
#define PGF_USE_BIG_ENDIAN 1 |
||||||
|
#endif |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// ROI support
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#ifndef NPGFROI |
||||||
|
#define __PGFROISUPPORT__ // without ROI support the program code gets simpler and smaller
|
||||||
|
#endif |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// 32 bit per channel support
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#ifndef NPGF32 |
||||||
|
#define __PGF32SUPPORT__ // without 32 bit the memory consumption during encoding and decoding is much lesser
|
||||||
|
#endif |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// 32 Bit platform constants
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#define WordWidth 32 ///< WordBytes*8
|
||||||
|
#define WordWidthLog 5 ///< ld of WordWidth
|
||||||
|
#define WordMask 0xFFFFFFE0 ///< least WordWidthLog bits are zero
|
||||||
|
#define WordBytes 4 ///< sizeof(UINT32)
|
||||||
|
#define WordBytesMask 0xFFFFFFFC ///< least WordBytesLog bits are zero
|
||||||
|
#define WordBytesLog 2 ///< ld of WordBytes
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// Alignment macros (used in PGF based libraries)
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#define DWWIDTHBITS(bits) (((bits) + WordWidth - 1) & WordMask) ///< aligns scanline width in bits to DWORD value
|
||||||
|
#define DWWIDTH(bytes) (((bytes) + WordBytes - 1) & WordBytesMask) ///< aligns scanline width in bytes to DWORD value
|
||||||
|
#define DWWIDTHREST(bytes) ((WordBytes - (bytes)%WordBytes)%WordBytes) ///< DWWIDTH(bytes) - bytes
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// Min-Max macros
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#ifndef __min |
||||||
|
#define __min(x, y) ((x) <= (y) ? (x) : (y)) |
||||||
|
#define __max(x, y) ((x) >= (y) ? (x) : (y)) |
||||||
|
#endif // __min
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// Defines -- Adobe image modes.
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#define ImageModeBitmap 0 |
||||||
|
#define ImageModeGrayScale 1 |
||||||
|
#define ImageModeIndexedColor 2 |
||||||
|
#define ImageModeRGBColor 3 |
||||||
|
#define ImageModeCMYKColor 4 |
||||||
|
#define ImageModeHSLColor 5 |
||||||
|
#define ImageModeHSBColor 6 |
||||||
|
#define ImageModeMultichannel 7 |
||||||
|
#define ImageModeDuotone 8 |
||||||
|
#define ImageModeLabColor 9 |
||||||
|
#define ImageModeGray16 10 // 565
|
||||||
|
#define ImageModeRGB48 11 |
||||||
|
#define ImageModeLab48 12 |
||||||
|
#define ImageModeCMYK64 13 |
||||||
|
#define ImageModeDeepMultichannel 14 |
||||||
|
#define ImageModeDuotone16 15 |
||||||
|
// pgf extension
|
||||||
|
#define ImageModeRGBA 17 |
||||||
|
#define ImageModeGray32 18 // MSB is 0 (can be interpreted as signed 15.16 fixed point format)
|
||||||
|
#define ImageModeRGB12 19 |
||||||
|
#define ImageModeRGB16 20 |
||||||
|
#define ImageModeUnknown 255 |
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// WINDOWS
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#if defined(WIN32) || defined(WINCE) || defined(WIN64) || defined(__MINGW32__) |
||||||
|
#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// MFC
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#ifdef _MFC_VER |
||||||
|
#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
|
||||||
|
#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
|
||||||
|
#endif |
||||||
|
#include <afx.h> |
||||||
|
#include <afxwin.h> // MFC core and standard components |
||||||
|
#include <afxext.h> // MFC extensions |
||||||
|
#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls |
||||||
|
#ifndef _AFX_NO_AFXCMN_SUPPORT |
||||||
|
#include <afxcmn.h> // MFC support for Windows Common Controls |
||||||
|
#endif // _AFX_NO_AFXCMN_SUPPORT
|
||||||
|
|
||||||
|
#else |
||||||
|
|
||||||
|
#include <windows.h> |
||||||
|
#include <ole2.h> |
||||||
|
|
||||||
|
#endif // _MFC_VER
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define DllExport __declspec( dllexport ) |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// unsigned number type definitions
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
typedef unsigned char UINT8; |
||||||
|
typedef unsigned char BYTE; |
||||||
|
typedef unsigned short UINT16; |
||||||
|
typedef unsigned short WORD; |
||||||
|
typedef unsigned int UINT32; |
||||||
|
typedef unsigned long DWORD; |
||||||
|
typedef unsigned long ULONG; |
||||||
|
typedef unsigned __int64 UINT64;
|
||||||
|
typedef unsigned __int64 ULONGLONG;
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// signed number type definitions
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
typedef signed char INT8; |
||||||
|
typedef signed short INT16; |
||||||
|
typedef signed int INT32; |
||||||
|
typedef signed int BOOL; |
||||||
|
typedef signed long LONG; |
||||||
|
typedef signed __int64 INT64; |
||||||
|
typedef signed __int64 LONGLONG; |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// other types
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
typedef int OSError; |
||||||
|
typedef bool (__cdecl *CallbackPtr)(double percent, bool escapeAllowed, void *data); |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// struct type definitions
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// DEBUG macros
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#ifndef ASSERT |
||||||
|
#ifdef _DEBUG |
||||||
|
#define ASSERT(x) assert(x) |
||||||
|
#else |
||||||
|
#if defined(__GNUC__) |
||||||
|
#define ASSERT(ignore)((void) 0) |
||||||
|
#elif _MSC_VER >= 1300 |
||||||
|
#define ASSERT __noop |
||||||
|
#else |
||||||
|
#define ASSERT ((void)0) |
||||||
|
#endif |
||||||
|
#endif //_DEBUG
|
||||||
|
#endif //ASSERT
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// Exception handling macros
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#ifdef NEXCEPTIONS |
||||||
|
extern OSError _PGF_Error_; |
||||||
|
extern OSError GetLastPGFError(); |
||||||
|
|
||||||
|
#define ReturnWithError(err) { _PGF_Error_ = err; return; } |
||||||
|
#define ReturnWithError2(err, ret) { _PGF_Error_ = err; return ret; } |
||||||
|
#else |
||||||
|
#define ReturnWithError(err) throw IOException(err) |
||||||
|
#define ReturnWithError2(err, ret) throw IOException(err) |
||||||
|
#endif //NEXCEPTIONS
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// constants
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#define FSFromStart FILE_BEGIN // 0
|
||||||
|
#define FSFromCurrent FILE_CURRENT // 1
|
||||||
|
#define FSFromEnd FILE_END // 2
|
||||||
|
|
||||||
|
#define INVALID_SET_FILE_POINTER ((DWORD)-1) |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// IO Error constants
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#define NoError ERROR_SUCCESS ///< no error
|
||||||
|
#define AppError 0x20000000 ///< all application error messages must be larger than this value
|
||||||
|
#define InsufficientMemory 0x20000001 ///< memory allocation was not successfull
|
||||||
|
#define InvalidStreamPos 0x20000002 ///< invalid memory stream position
|
||||||
|
#define EscapePressed 0x20000003 ///< user break by ESC
|
||||||
|
#define WrongVersion 0x20000004 ///< wrong PGF version
|
||||||
|
#define FormatCannotRead 0x20000005 ///< wrong data file format
|
||||||
|
#define ImageTooSmall 0x20000006 ///< image is too small
|
||||||
|
#define ZlibError 0x20000007 ///< error in zlib functions
|
||||||
|
#define ColorTableError 0x20000008 ///< errors related to color table size
|
||||||
|
#define PNGError 0x20000009 ///< errors in png functions
|
||||||
|
#define MissingData 0x2000000A ///< expected data cannot be read
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// methods
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
inline OSError FileRead(HANDLE hFile, int *count, void *buffPtr) { |
||||||
|
if (ReadFile(hFile, buffPtr, *count, (ULONG *)count, nullptr)) { |
||||||
|
return NoError; |
||||||
|
} else { |
||||||
|
return GetLastError(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
inline OSError FileWrite(HANDLE hFile, int *count, void *buffPtr) { |
||||||
|
if (WriteFile(hFile, buffPtr, *count, (ULONG *)count, nullptr)) { |
||||||
|
return NoError; |
||||||
|
} else { |
||||||
|
return GetLastError(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
inline OSError GetFPos(HANDLE hFile, UINT64 *pos) { |
||||||
|
#ifdef WINCE |
||||||
|
LARGE_INTEGER li; |
||||||
|
li.QuadPart = 0; |
||||||
|
|
||||||
|
li.LowPart = SetFilePointer (hFile, li.LowPart, &li.HighPart, FILE_CURRENT); |
||||||
|
if (li.LowPart == INVALID_SET_FILE_POINTER) { |
||||||
|
OSError err = GetLastError(); |
||||||
|
if (err != NoError) { |
||||||
|
return err; |
||||||
|
} |
||||||
|
} |
||||||
|
*pos = li.QuadPart; |
||||||
|
return NoError; |
||||||
|
#else |
||||||
|
LARGE_INTEGER li; |
||||||
|
li.QuadPart = 0; |
||||||
|
if (SetFilePointerEx(hFile, li, (PLARGE_INTEGER)pos, FILE_CURRENT)) { |
||||||
|
return NoError; |
||||||
|
} else { |
||||||
|
return GetLastError(); |
||||||
|
} |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
inline OSError SetFPos(HANDLE hFile, int posMode, INT64 posOff) { |
||||||
|
#ifdef WINCE |
||||||
|
LARGE_INTEGER li; |
||||||
|
li.QuadPart = posOff; |
||||||
|
|
||||||
|
if (SetFilePointer (hFile, li.LowPart, &li.HighPart, posMode) == INVALID_SET_FILE_POINTER) { |
||||||
|
OSError err = GetLastError(); |
||||||
|
if (err != NoError) { |
||||||
|
return err; |
||||||
|
} |
||||||
|
} |
||||||
|
return NoError; |
||||||
|
#else |
||||||
|
LARGE_INTEGER li; |
||||||
|
li.QuadPart = posOff; |
||||||
|
if (SetFilePointerEx(hFile, li, nullptr, posMode)) { |
||||||
|
return NoError; |
||||||
|
} else { |
||||||
|
return GetLastError(); |
||||||
|
} |
||||||
|
#endif |
||||||
|
} |
||||||
|
#endif //WIN32
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// Apple OSX
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#ifdef __APPLE__ |
||||||
|
#define __POSIX__ |
||||||
|
#endif // __APPLE__
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// LINUX
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#if defined(__linux__) || defined(__GLIBC__) |
||||||
|
#define __POSIX__ |
||||||
|
#endif // __linux__ or __GLIBC__
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// SOLARIS
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#ifdef __sun |
||||||
|
#define __POSIX__ |
||||||
|
#endif // __sun
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// *BSD
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) |
||||||
|
#ifndef __POSIX__ |
||||||
|
#define __POSIX__ |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifndef off64_t |
||||||
|
#define off64_t off_t |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifndef lseek64 |
||||||
|
#define lseek64 lseek |
||||||
|
#endif |
||||||
|
|
||||||
|
#endif // __NetBSD__ or __OpenBSD__ or __FreeBSD__
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// POSIX *NIXes
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef __POSIX__ |
||||||
|
#include <unistd.h> |
||||||
|
#include <errno.h> |
||||||
|
#include <stdint.h> // for int64_t and uint64_t |
||||||
|
#include <string.h> // memcpy() |
||||||
|
|
||||||
|
#undef major |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// unsigned number type definitions
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
typedef unsigned char UINT8; |
||||||
|
typedef unsigned char BYTE; |
||||||
|
typedef unsigned short UINT16; |
||||||
|
typedef unsigned short WORD; |
||||||
|
typedef unsigned int UINT32; |
||||||
|
typedef unsigned int DWORD; |
||||||
|
typedef unsigned long ULONG; |
||||||
|
typedef unsigned long long __Uint64; |
||||||
|
typedef __Uint64 UINT64; |
||||||
|
typedef __Uint64 ULONGLONG; |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// signed number type definitions
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
typedef signed char INT8; |
||||||
|
typedef signed short INT16; |
||||||
|
typedef signed int INT32; |
||||||
|
typedef signed int BOOL; |
||||||
|
typedef signed long LONG; |
||||||
|
typedef int64_t INT64; |
||||||
|
typedef int64_t LONGLONG; |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// other types
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
typedef int OSError; |
||||||
|
typedef int HANDLE;
|
||||||
|
typedef unsigned long ULONG_PTR; |
||||||
|
typedef void* PVOID; |
||||||
|
typedef char* LPTSTR; |
||||||
|
typedef bool (*CallbackPtr)(double percent, bool escapeAllowed, void *data); |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// struct type definitions
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
typedef struct tagRGBTRIPLE { |
||||||
|
BYTE rgbtBlue; |
||||||
|
BYTE rgbtGreen; |
||||||
|
BYTE rgbtRed; |
||||||
|
} RGBTRIPLE; |
||||||
|
|
||||||
|
typedef struct tagRGBQUAD { |
||||||
|
BYTE rgbBlue; |
||||||
|
BYTE rgbGreen; |
||||||
|
BYTE rgbRed; |
||||||
|
BYTE rgbReserved; |
||||||
|
} RGBQUAD; |
||||||
|
|
||||||
|
typedef union _LARGE_INTEGER { |
||||||
|
struct { |
||||||
|
DWORD LowPart; |
||||||
|
LONG HighPart; |
||||||
|
} u; |
||||||
|
LONGLONG QuadPart; |
||||||
|
} LARGE_INTEGER, *PLARGE_INTEGER; |
||||||
|
#endif // __POSIX__
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__POSIX__) || defined(WINCE) |
||||||
|
// CMYK macros
|
||||||
|
#define GetKValue(cmyk) ((BYTE)(cmyk)) |
||||||
|
#define GetYValue(cmyk) ((BYTE)((cmyk)>> 8)) |
||||||
|
#define GetMValue(cmyk) ((BYTE)((cmyk)>>16)) |
||||||
|
#define GetCValue(cmyk) ((BYTE)((cmyk)>>24)) |
||||||
|
#define CMYK(c,m,y,k) ((COLORREF)((((BYTE)(k)|((WORD)((BYTE)(y))<<8))|(((DWORD)(BYTE)(m))<<16))|(((DWORD)(BYTE)(c))<<24))) |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// methods
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
/* The MulDiv function multiplies two 32-bit values and then divides the 64-bit
|
||||||
|
* result by a third 32-bit value. The return value is rounded up or down to
|
||||||
|
* the nearest integer. |
||||||
|
* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winprog/winprog/muldiv.asp
|
||||||
|
* */ |
||||||
|
__inline int MulDiv(int nNumber, int nNumerator, int nDenominator) { |
||||||
|
INT64 multRes = nNumber*nNumerator; |
||||||
|
INT32 divRes = INT32(multRes/nDenominator); |
||||||
|
return divRes; |
||||||
|
} |
||||||
|
#endif // __POSIX__ or WINCE
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __POSIX__ |
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// DEBUG macros
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#ifndef ASSERT |
||||||
|
#ifdef _DEBUG |
||||||
|
#define ASSERT(x) assert(x) |
||||||
|
#else |
||||||
|
#define ASSERT(x) |
||||||
|
#endif //_DEBUG
|
||||||
|
#endif //ASSERT
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// Exception handling macros
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#ifdef NEXCEPTIONS |
||||||
|
extern OSError _PGF_Error_; |
||||||
|
extern OSError GetLastPGFError(); |
||||||
|
|
||||||
|
#define ReturnWithError(err) { _PGF_Error_ = err; return; } |
||||||
|
#define ReturnWithError2(err, ret) { _PGF_Error_ = err; return ret; } |
||||||
|
#else |
||||||
|
#define ReturnWithError(err) throw IOException(err) |
||||||
|
#define ReturnWithError2(err, ret) throw IOException(err) |
||||||
|
#endif //NEXCEPTIONS
|
||||||
|
|
||||||
|
#define THROW_ throw(IOException) |
||||||
|
#define CONST const |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// constants
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#define FSFromStart SEEK_SET |
||||||
|
#define FSFromCurrent SEEK_CUR |
||||||
|
#define FSFromEnd SEEK_END |
||||||
|
#define nullptr NULL |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// IO Error constants
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#define NoError 0x0000 ///< no error
|
||||||
|
#define AppError 0x2000 ///< all application error messages must be larger than this value
|
||||||
|
#define InsufficientMemory 0x2001 ///< memory allocation wasn't successfull
|
||||||
|
#define InvalidStreamPos 0x2002 ///< invalid memory stream position
|
||||||
|
#define EscapePressed 0x2003 ///< user break by ESC
|
||||||
|
#define WrongVersion 0x2004 ///< wrong pgf version
|
||||||
|
#define FormatCannotRead 0x2005 ///< wrong data file format
|
||||||
|
#define ImageTooSmall 0x2006 ///< image is too small
|
||||||
|
#define ZlibError 0x2007 ///< error in zlib functions
|
||||||
|
#define ColorTableError 0x2008 ///< errors related to color table size
|
||||||
|
#define PNGError 0x2009 ///< errors in png functions
|
||||||
|
#define MissingData 0x200A ///< expected data cannot be read
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// methods
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
__inline OSError FileRead(HANDLE hFile, int *count, void *buffPtr) { |
||||||
|
*count = (int)read(hFile, buffPtr, *count); |
||||||
|
if (*count != -1) { |
||||||
|
return NoError; |
||||||
|
} else { |
||||||
|
return errno; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
__inline OSError FileWrite(HANDLE hFile, int *count, void *buffPtr) { |
||||||
|
*count = (int)write(hFile, buffPtr, (size_t)*count); |
||||||
|
if (*count != -1) { |
||||||
|
return NoError; |
||||||
|
} else { |
||||||
|
return errno; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
__inline OSError GetFPos(HANDLE hFile, UINT64 *pos) { |
||||||
|
#ifdef __APPLE__ |
||||||
|
off_t ret; |
||||||
|
if ((ret = lseek(hFile, 0, SEEK_CUR)) == -1) { |
||||||
|
return errno; |
||||||
|
} else { |
||||||
|
*pos = (UINT64)ret; |
||||||
|
return NoError; |
||||||
|
} |
||||||
|
#else |
||||||
|
off64_t ret; |
||||||
|
if ((ret = lseek64(hFile, 0, SEEK_CUR)) == -1) { |
||||||
|
return errno; |
||||||
|
} else { |
||||||
|
*pos = (UINT64)ret; |
||||||
|
return NoError; |
||||||
|
} |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
__inline OSError SetFPos(HANDLE hFile, int posMode, INT64 posOff) { |
||||||
|
#ifdef __APPLE__ |
||||||
|
if ((lseek(hFile, (off_t)posOff, posMode)) == -1) { |
||||||
|
return errno; |
||||||
|
} else { |
||||||
|
return NoError; |
||||||
|
} |
||||||
|
#else |
||||||
|
if ((lseek64(hFile, (off64_t)posOff, posMode)) == -1) { |
||||||
|
return errno; |
||||||
|
} else { |
||||||
|
return NoError; |
||||||
|
} |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
#endif /* __POSIX__ */ |
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// Big Endian
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#ifdef PGF_USE_BIG_ENDIAN |
||||||
|
|
||||||
|
#ifndef _lrotl |
||||||
|
#define _lrotl(x,n) (((x) << ((UINT32)(n))) | ((x) >> (32 - (UINT32)(n)))) |
||||||
|
#endif |
||||||
|
|
||||||
|
__inline UINT16 ByteSwap(UINT16 wX) { |
||||||
|
return ((wX & 0xFF00) >> 8) | ((wX & 0x00FF) << 8); |
||||||
|
} |
||||||
|
|
||||||
|
__inline UINT32 ByteSwap(UINT32 dwX) {
|
||||||
|
#ifdef _X86_ |
||||||
|
_asm mov eax, dwX
|
||||||
|
_asm bswap eax |
||||||
|
_asm mov dwX, eax
|
||||||
|
return dwX;
|
||||||
|
#else |
||||||
|
return _lrotl(((dwX & 0xFF00FF00) >> 8) | ((dwX & 0x00FF00FF) << 8), 16);
|
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
#if defined(WIN32) || defined(WIN64) |
||||||
|
__inline UINT64 ByteSwap(UINT64 ui64) {
|
||||||
|
return _byteswap_uint64(ui64); |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
#define __VAL(x) ByteSwap(x) |
||||||
|
|
||||||
|
#else //PGF_USE_BIG_ENDIAN
|
||||||
|
|
||||||
|
#define __VAL(x) (x) |
||||||
|
|
||||||
|
#endif //PGF_USE_BIG_ENDIAN
|
||||||
|
|
||||||
|
// OpenMP rules (inspired from libraw project)
|
||||||
|
// NOTE: Use LIBPGF_DISABLE_OPENMP to disable OpenMP support in whole libpgf
|
||||||
|
#ifndef LIBPGF_DISABLE_OPENMP |
||||||
|
# if defined (_OPENMP) |
||||||
|
# if defined (WIN32) || defined(WIN64) |
||||||
|
# if defined (_MSC_VER) && (_MSC_VER >= 1500) |
||||||
|
// VS2008 SP1 and VS2010+ : OpenMP works OK
|
||||||
|
# define LIBPGF_USE_OPENMP |
||||||
|
# elif defined (__INTEL_COMPILER) && (__INTEL_COMPILER >=910) |
||||||
|
// untested on 9.x and 10.x, Intel documentation claims OpenMP 2.5 support in 9.1
|
||||||
|
# define LIBPGF_USE_OPENMP |
||||||
|
# else |
||||||
|
# undef LIBPGF_USE_OPENMP |
||||||
|
# endif |
||||||
|
// Not Win32
|
||||||
|
# elif (defined(__APPLE__) || defined(__MACOSX__)) && defined(_REENTRANT) |
||||||
|
# undef LIBPGF_USE_OPENMP |
||||||
|
# else |
||||||
|
# define LIBPGF_USE_OPENMP |
||||||
|
# endif |
||||||
|
# endif // defined (_OPENMP)
|
||||||
|
#endif // ifndef LIBPGF_DISABLE_OPENMP
|
||||||
|
#ifdef LIBPGF_USE_OPENMP |
||||||
|
#include <omp.h> |
||||||
|
#endif |
||||||
|
|
||||||
|
#endif //PGF_PGFPLATFORM_H
|
@ -0,0 +1,274 @@ |
|||||||
|
/*
|
||||||
|
* The Progressive Graphics File; http://www.libpgf.org
|
||||||
|
*
|
||||||
|
* $Date: 2007-01-19 11:51:24 +0100 (Fr, 19 Jan 2007) $ |
||||||
|
* $Revision: 268 $ |
||||||
|
*
|
||||||
|
* This file Copyright (C) 2006 xeraina GmbH, Switzerland |
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE |
||||||
|
* as published by the Free Software Foundation; either version 2.1 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||||
|
*/ |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// @file PGFstream.cpp
|
||||||
|
/// @brief PGF stream class implementation
|
||||||
|
/// @author C. Stamm
|
||||||
|
|
||||||
|
#include "PGFstream.h" |
||||||
|
|
||||||
|
#ifdef WIN32 |
||||||
|
#include <malloc.h> |
||||||
|
#endif |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// CPGFFileStream
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
void CPGFFileStream::Write(int *count, void *buffPtr) { |
||||||
|
ASSERT(count); |
||||||
|
ASSERT(buffPtr); |
||||||
|
ASSERT(IsValid()); |
||||||
|
OSError err; |
||||||
|
if ((err = FileWrite(m_hFile, count, buffPtr)) != NoError) ReturnWithError(err); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
void CPGFFileStream::Read(int *count, void *buffPtr) { |
||||||
|
ASSERT(count); |
||||||
|
ASSERT(buffPtr); |
||||||
|
ASSERT(IsValid()); |
||||||
|
OSError err; |
||||||
|
if ((err = FileRead(m_hFile, count, buffPtr)) != NoError) ReturnWithError(err); |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
void CPGFFileStream::SetPos(short posMode, INT64 posOff) { |
||||||
|
ASSERT(IsValid()); |
||||||
|
OSError err; |
||||||
|
if ((err = SetFPos(m_hFile, posMode, posOff)) != NoError) ReturnWithError(err); |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
UINT64 CPGFFileStream::GetPos() const { |
||||||
|
ASSERT(IsValid()); |
||||||
|
OSError err; |
||||||
|
UINT64 pos = 0; |
||||||
|
if ((err = GetFPos(m_hFile, &pos)) != NoError) ReturnWithError2(err, pos); |
||||||
|
return pos; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// CPGFMemoryStream
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Allocate memory block of given size
|
||||||
|
/// @param size Memory size
|
||||||
|
CPGFMemoryStream::CPGFMemoryStream(size_t size)
|
||||||
|
: m_size(size) |
||||||
|
, m_allocated(true) { |
||||||
|
m_buffer = m_pos = m_eos = new(std::nothrow) UINT8[m_size]; |
||||||
|
if (!m_buffer) ReturnWithError(InsufficientMemory); |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Use already allocated memory of given size
|
||||||
|
/// @param pBuffer Memory location
|
||||||
|
/// @param size Memory size
|
||||||
|
CPGFMemoryStream::CPGFMemoryStream(UINT8 *pBuffer, size_t size)
|
||||||
|
: m_buffer(pBuffer) |
||||||
|
, m_pos(pBuffer) |
||||||
|
, m_eos(pBuffer + size) |
||||||
|
, m_size(size) |
||||||
|
, m_allocated(false) { |
||||||
|
ASSERT(IsValid()); |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Use already allocated memory of given size
|
||||||
|
/// @param pBuffer Memory location
|
||||||
|
/// @param size Memory size
|
||||||
|
void CPGFMemoryStream::Reinitialize(UINT8 *pBuffer, size_t size) { |
||||||
|
if (!m_allocated) { |
||||||
|
m_buffer = m_pos = pBuffer; |
||||||
|
m_size = size; |
||||||
|
m_eos = m_buffer + size; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
void CPGFMemoryStream::Write(int *count, void *buffPtr) { |
||||||
|
ASSERT(count); |
||||||
|
ASSERT(buffPtr); |
||||||
|
ASSERT(IsValid()); |
||||||
|
const size_t deltaSize = 0x4000 + *count; |
||||||
|
|
||||||
|
if (m_pos + *count <= m_buffer + m_size) { |
||||||
|
memcpy(m_pos, buffPtr, *count); |
||||||
|
m_pos += *count;
|
||||||
|
if (m_pos > m_eos) m_eos = m_pos; |
||||||
|
} else if (m_allocated) { |
||||||
|
// memory block is too small -> reallocate a deltaSize larger block
|
||||||
|
size_t offset = m_pos - m_buffer; |
||||||
|
UINT8 *buf_tmp = (UINT8 *)realloc(m_buffer, m_size + deltaSize); |
||||||
|
if (!buf_tmp) { |
||||||
|
delete[] m_buffer; |
||||||
|
m_buffer = 0; |
||||||
|
ReturnWithError(InsufficientMemory); |
||||||
|
} else { |
||||||
|
m_buffer = buf_tmp; |
||||||
|
} |
||||||
|
m_size += deltaSize; |
||||||
|
|
||||||
|
// reposition m_pos
|
||||||
|
m_pos = m_buffer + offset; |
||||||
|
|
||||||
|
// write block
|
||||||
|
memcpy(m_pos, buffPtr, *count); |
||||||
|
m_pos += *count;
|
||||||
|
if (m_pos > m_eos) m_eos = m_pos; |
||||||
|
} else { |
||||||
|
ReturnWithError(InsufficientMemory);
|
||||||
|
} |
||||||
|
ASSERT(m_pos <= m_eos); |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
void CPGFMemoryStream::Read(int *count, void *buffPtr) { |
||||||
|
ASSERT(IsValid()); |
||||||
|
ASSERT(count); |
||||||
|
ASSERT(buffPtr); |
||||||
|
ASSERT(m_buffer + m_size >= m_eos); |
||||||
|
ASSERT(m_pos <= m_eos); |
||||||
|
|
||||||
|
if (m_pos + *count <= m_eos) { |
||||||
|
memcpy(buffPtr, m_pos, *count); |
||||||
|
m_pos += *count; |
||||||
|
} else { |
||||||
|
// end of memory block reached -> read only until end
|
||||||
|
*count = (int)__max(0, m_eos - m_pos); |
||||||
|
memcpy(buffPtr, m_pos, *count); |
||||||
|
m_pos += *count; |
||||||
|
} |
||||||
|
ASSERT(m_pos <= m_eos); |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
void CPGFMemoryStream::SetPos(short posMode, INT64 posOff) { |
||||||
|
ASSERT(IsValid()); |
||||||
|
switch(posMode) { |
||||||
|
case FSFromStart: |
||||||
|
m_pos = m_buffer + posOff; |
||||||
|
break; |
||||||
|
case FSFromCurrent: |
||||||
|
m_pos += posOff; |
||||||
|
break; |
||||||
|
case FSFromEnd: |
||||||
|
m_pos = m_eos + posOff; |
||||||
|
break; |
||||||
|
default: |
||||||
|
ASSERT(false); |
||||||
|
} |
||||||
|
if (m_pos > m_eos)
|
||||||
|
ReturnWithError(InvalidStreamPos); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// CPGFMemFileStream
|
||||||
|
#ifdef _MFC_VER |
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
void CPGFMemFileStream::Write(int *count, void *buffPtr) { |
||||||
|
ASSERT(count); |
||||||
|
ASSERT(buffPtr); |
||||||
|
ASSERT(IsValid()); |
||||||
|
m_memFile->Write(buffPtr, *count); |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
void CPGFMemFileStream::Read(int *count, void *buffPtr) { |
||||||
|
ASSERT(count); |
||||||
|
ASSERT(buffPtr); |
||||||
|
ASSERT(IsValid()); |
||||||
|
m_memFile->Read(buffPtr, *count); |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
void CPGFMemFileStream::SetPos(short posMode, INT64 posOff) { |
||||||
|
ASSERT(IsValid()); |
||||||
|
m_memFile->Seek(posOff, posMode);
|
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
UINT64 CPGFMemFileStream::GetPos() const { |
||||||
|
return (UINT64)m_memFile->GetPosition(); |
||||||
|
} |
||||||
|
#endif // _MFC_VER
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// CPGFIStream
|
||||||
|
#if defined(WIN32) || defined(WINCE) |
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
void CPGFIStream::Write(int *count, void *buffPtr) { |
||||||
|
ASSERT(count); |
||||||
|
ASSERT(buffPtr); |
||||||
|
ASSERT(IsValid()); |
||||||
|
|
||||||
|
HRESULT hr = m_stream->Write(buffPtr, *count, (ULONG *)count); |
||||||
|
if (FAILED(hr)) { |
||||||
|
ReturnWithError(hr); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
void CPGFIStream::Read(int *count, void *buffPtr) { |
||||||
|
ASSERT(count); |
||||||
|
ASSERT(buffPtr); |
||||||
|
ASSERT(IsValid()); |
||||||
|
|
||||||
|
HRESULT hr = m_stream->Read(buffPtr, *count, (ULONG *)count); |
||||||
|
if (FAILED(hr)) { |
||||||
|
ReturnWithError(hr); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
void CPGFIStream::SetPos(short posMode, INT64 posOff) { |
||||||
|
ASSERT(IsValid()); |
||||||
|
|
||||||
|
LARGE_INTEGER li; |
||||||
|
li.QuadPart = posOff; |
||||||
|
|
||||||
|
HRESULT hr = m_stream->Seek(li, posMode, nullptr);
|
||||||
|
if (FAILED(hr)) { |
||||||
|
ReturnWithError(hr); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
UINT64 CPGFIStream::GetPos() const { |
||||||
|
ASSERT(IsValid()); |
||||||
|
|
||||||
|
LARGE_INTEGER n; |
||||||
|
ULARGE_INTEGER pos; |
||||||
|
n.QuadPart = 0; |
||||||
|
|
||||||
|
HRESULT hr = m_stream->Seek(n, FSFromCurrent, &pos);
|
||||||
|
if (SUCCEEDED(hr)) { |
||||||
|
return pos.QuadPart; |
||||||
|
} else { |
||||||
|
ReturnWithError2(hr, pos.QuadPart); |
||||||
|
} |
||||||
|
} |
||||||
|
#endif // WIN32 || WINCE
|
@ -0,0 +1,193 @@ |
|||||||
|
/*
|
||||||
|
* The Progressive Graphics File; http://www.libpgf.org
|
||||||
|
*
|
||||||
|
* $Date: 2007-06-11 10:56:17 +0200 (Mo, 11 Jun 2007) $ |
||||||
|
* $Revision: 299 $ |
||||||
|
*
|
||||||
|
* This file Copyright (C) 2006 xeraina GmbH, Switzerland |
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE |
||||||
|
* as published by the Free Software Foundation; either version 2.1 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||||
|
*/ |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// @file PGFstream.h
|
||||||
|
/// @brief PGF stream class
|
||||||
|
/// @author C. Stamm
|
||||||
|
|
||||||
|
#ifndef PGF_STREAM_H |
||||||
|
#define PGF_STREAM_H |
||||||
|
|
||||||
|
#include "PGFtypes.h" |
||||||
|
#include <new> |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Abstract stream base class.
|
||||||
|
/// @author C. Stamm
|
||||||
|
/// @brief Abstract stream base class
|
||||||
|
class CPGFStream { |
||||||
|
public: |
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Standard constructor.
|
||||||
|
CPGFStream() {} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Standard destructor.
|
||||||
|
virtual ~CPGFStream() {} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Write some bytes out of a buffer into this stream.
|
||||||
|
/// @param count A pointer to a value containing the number of bytes should be written. After this call it contains the number of written bytes.
|
||||||
|
/// @param buffer A memory buffer
|
||||||
|
virtual void Write(int *count, void *buffer)=0;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Read some bytes from this stream and stores them into a buffer.
|
||||||
|
/// @param count A pointer to a value containing the number of bytes should be read. After this call it contains the number of read bytes.
|
||||||
|
/// @param buffer A memory buffer
|
||||||
|
virtual void Read(int *count, void *buffer)=0;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Set stream position either absolute or relative.
|
||||||
|
/// @param posMode A position mode (FSFromStart, FSFromCurrent, FSFromEnd)
|
||||||
|
/// @param posOff A new stream position (absolute positioning) or a position offset (relative positioning)
|
||||||
|
virtual void SetPos(short posMode, INT64 posOff)=0; |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Get current stream position.
|
||||||
|
/// @return Current stream position
|
||||||
|
virtual UINT64 GetPos() const=0; |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Check stream validity.
|
||||||
|
/// @return True if stream and current position is valid
|
||||||
|
virtual bool IsValid() const=0; |
||||||
|
}; |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// A PGF stream subclass for external storage files.
|
||||||
|
/// @author C. Stamm
|
||||||
|
/// @brief File stream class
|
||||||
|
class CPGFFileStream : public CPGFStream { |
||||||
|
protected: |
||||||
|
HANDLE m_hFile; ///< file handle
|
||||||
|
|
||||||
|
public: |
||||||
|
CPGFFileStream() : m_hFile(0) {} |
||||||
|
/// Constructor
|
||||||
|
/// @param hFile File handle
|
||||||
|
CPGFFileStream(HANDLE hFile) : m_hFile(hFile) {} |
||||||
|
/// @return File handle
|
||||||
|
HANDLE GetHandle() { return m_hFile; } |
||||||
|
|
||||||
|
virtual ~CPGFFileStream() { m_hFile = 0; } |
||||||
|
virtual void Write(int *count, void *buffer); // throws IOException
|
||||||
|
virtual void Read(int *count, void *buffer); // throws IOException
|
||||||
|
virtual void SetPos(short posMode, INT64 posOff); // throws IOException
|
||||||
|
virtual UINT64 GetPos() const; // throws IOException
|
||||||
|
virtual bool IsValid() const { return m_hFile != 0; } |
||||||
|
}; |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// A PGF stream subclass for internal memory.
|
||||||
|
/// @author C. Stamm
|
||||||
|
/// @brief Memory stream class
|
||||||
|
class CPGFMemoryStream : public CPGFStream { |
||||||
|
protected: |
||||||
|
UINT8 *m_buffer, *m_pos;///< buffer start address and current buffer address
|
||||||
|
UINT8 *m_eos; ///< end of stream (first address beyond written area)
|
||||||
|
size_t m_size; ///< buffer size
|
||||||
|
bool m_allocated; ///< indicates a new allocated buffer
|
||||||
|
|
||||||
|
public: |
||||||
|
/// Constructor
|
||||||
|
/// @param size Size of new allocated memory buffer
|
||||||
|
CPGFMemoryStream(size_t size); |
||||||
|
|
||||||
|
/// Constructor. Use already allocated memory of given size
|
||||||
|
/// @param pBuffer Memory location
|
||||||
|
/// @param size Memory size
|
||||||
|
CPGFMemoryStream(UINT8 *pBuffer, size_t size); |
||||||
|
|
||||||
|
/// Use already allocated memory of given size
|
||||||
|
/// @param pBuffer Memory location
|
||||||
|
/// @param size Memory size
|
||||||
|
void Reinitialize(UINT8 *pBuffer, size_t size); |
||||||
|
|
||||||
|
virtual ~CPGFMemoryStream() {
|
||||||
|
m_pos = 0;
|
||||||
|
if (m_allocated) { |
||||||
|
// the memory buffer has been allocated inside of CPMFmemoryStream constructor
|
||||||
|
delete[] m_buffer; m_buffer = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
virtual void Write(int *count, void *buffer); // throws IOException
|
||||||
|
virtual void Read(int *count, void *buffer); |
||||||
|
virtual void SetPos(short posMode, INT64 posOff); // throws IOException
|
||||||
|
virtual UINT64 GetPos() const { ASSERT(IsValid()); return m_pos - m_buffer; } |
||||||
|
virtual bool IsValid() const { return m_buffer != 0; } |
||||||
|
|
||||||
|
/// @return Memory size
|
||||||
|
size_t GetSize() const { return m_size; } |
||||||
|
/// @return Memory buffer
|
||||||
|
const UINT8* GetBuffer() const { return m_buffer; } |
||||||
|
/// @return Memory buffer
|
||||||
|
UINT8* GetBuffer() { return m_buffer; } |
||||||
|
/// @return relative position of end of stream (= stream length)
|
||||||
|
UINT64 GetEOS() const { ASSERT(IsValid()); return m_eos - m_buffer; } |
||||||
|
/// @param length Stream length (= relative position of end of stream)
|
||||||
|
void SetEOS(UINT64 length) { ASSERT(IsValid()); m_eos = m_buffer + length; } |
||||||
|
}; |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// A PGF stream subclass for internal memory files. Usable only with MFC.
|
||||||
|
/// @author C. Stamm
|
||||||
|
/// @brief Cached memory file stream class
|
||||||
|
#ifdef _MFC_VER |
||||||
|
class CPGFMemFileStream : public CPGFStream { |
||||||
|
protected: |
||||||
|
CMemFile *m_memFile; ///< MFC memory file
|
||||||
|
public: |
||||||
|
CPGFMemFileStream(CMemFile *memFile) : m_memFile(memFile) {} |
||||||
|
virtual bool IsValid() const { return m_memFile != nullptr; } |
||||||
|
virtual ~CPGFMemFileStream() {} |
||||||
|
virtual void Write(int *count, void *buffer); // throws IOException
|
||||||
|
virtual void Read(int *count, void *buffer); // throws IOException
|
||||||
|
virtual void SetPos(short posMode, INT64 posOff); // throws IOException
|
||||||
|
virtual UINT64 GetPos() const; // throws IOException
|
||||||
|
}; |
||||||
|
#endif |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// A PGF stream subclass for IStream. Usable only with COM.
|
||||||
|
/// @author C. Stamm
|
||||||
|
/// @brief COM IStream class
|
||||||
|
#if defined(WIN32) || defined(WINCE) |
||||||
|
class CPGFIStream : public CPGFStream { |
||||||
|
protected: |
||||||
|
IStream *m_stream; ///< COM+ IStream
|
||||||
|
public: |
||||||
|
CPGFIStream(IStream *stream) : m_stream(stream) { m_stream->AddRef(); } |
||||||
|
virtual bool IsValid() const { return m_stream != 0; } |
||||||
|
virtual ~CPGFIStream() { m_stream->Release(); } |
||||||
|
virtual void Write(int *count, void *buffer); // throws IOException
|
||||||
|
virtual void Read(int *count, void *buffer); // throws IOException
|
||||||
|
virtual void SetPos(short posMode, INT64 posOff); // throws IOException
|
||||||
|
virtual UINT64 GetPos() const; // throws IOException
|
||||||
|
IStream* GetIStream() const { return m_stream; } |
||||||
|
}; |
||||||
|
#endif |
||||||
|
|
||||||
|
#endif // PGF_STREAM_H
|
@ -0,0 +1,290 @@ |
|||||||
|
/*
|
||||||
|
* The Progressive Graphics File; http://www.libpgf.org
|
||||||
|
*
|
||||||
|
* $Date: 2007-06-11 10:56:17 +0200 (Mo, 11 Jun 2007) $ |
||||||
|
* $Revision: 299 $ |
||||||
|
*
|
||||||
|
* This file Copyright (C) 2006 xeraina GmbH, Switzerland |
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE |
||||||
|
* as published by the Free Software Foundation; either version 2.1 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||||
|
*/ |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// @file PGFtypes.h
|
||||||
|
/// @brief PGF definitions
|
||||||
|
/// @author C. Stamm
|
||||||
|
|
||||||
|
#ifndef PGF_PGFTYPES_H |
||||||
|
#define PGF_PGFTYPES_H |
||||||
|
|
||||||
|
#include "PGFplatform.h" |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// Codec versions
|
||||||
|
//
|
||||||
|
// Version 2: modified data structure PGFHeader (backward compatibility assured)
|
||||||
|
// Version 4: DataT: INT32 instead of INT16, allows 31 bit per pixel and channel (backward compatibility assured)
|
||||||
|
// Version 5: ROI, new block-reordering scheme (backward compatibility assured)
|
||||||
|
// Version 6: modified data structure PGFPreHeader: hSize (header size) is now a UINT32 instead of a UINT16 (backward compatibility assured)
|
||||||
|
// Version 7: last two bytes in header are now used for extended version numbers; new data representation for bitmaps (backward compatibility assured)
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#define PGFMajorNumber 7 |
||||||
|
#define PGFYear 19 |
||||||
|
#define PGFWeek 03 |
||||||
|
|
||||||
|
#define PPCAT_NX(A, B) A ## B |
||||||
|
#define PPCAT(A, B) PPCAT_NX(A, B) |
||||||
|
#define STRINGIZE_NX(A) #A |
||||||
|
#define STRINGIZE(A) STRINGIZE_NX(A) |
||||||
|
|
||||||
|
//#define PGFCodecVersionID 0x071822
|
||||||
|
#define PGFCodecVersionID PPCAT(PPCAT(PPCAT(0x0, PGFMajorNumber), PGFYear), PGFWeek) |
||||||
|
//#define PGFCodecVersion "7.19.3" ///< Major number, Minor number: Year (2) Week (2)
|
||||||
|
#define PGFCodecVersion STRINGIZE(PPCAT(PPCAT(PPCAT(PPCAT(PGFMajorNumber, .), PGFYear), .), PGFWeek)) |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// Image constants
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#define PGFMagic "PGF" ///< PGF identification
|
||||||
|
#define MaxLevel 30 ///< maximum number of transform levels
|
||||||
|
#define NSubbands 4 ///< number of subbands per level
|
||||||
|
#define MaxChannels 8 ///< maximum number of (color) channels
|
||||||
|
#define DownsampleThreshold 3 ///< if quality is larger than this threshold than downsampling is used
|
||||||
|
#define ColorTableLen 256 ///< size of color lookup table (clut)
|
||||||
|
// version flags
|
||||||
|
#define Version2 2 ///< data structure PGFHeader of major version 2
|
||||||
|
#define PGF32 4 ///< 32 bit values are used -> allows at maximum 31 bits, otherwise 16 bit values are used -> allows at maximum 15 bits
|
||||||
|
#define PGFROI 8 ///< supports Regions Of Interest
|
||||||
|
#define Version5 16 ///< new coding scheme since major version 5
|
||||||
|
#define Version6 32 ///< hSize in PGFPreHeader uses 32 bits instead of 16 bits
|
||||||
|
#define Version7 64 ///< Codec major and minor version number stored in PGFHeader
|
||||||
|
// version numbers
|
||||||
|
#ifdef __PGF32SUPPORT__ |
||||||
|
#define PGFVersion (Version2 | PGF32 | Version5 | Version6 | Version7) ///< current standard version
|
||||||
|
#else |
||||||
|
#define PGFVersion (Version2 | Version5 | Version6 | Version7) ///< current standard version
|
||||||
|
#endif |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// Coder constants
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#define BufferSize 16384 ///< must be a multiple of WordWidth, BufferSize <= UINT16_MAX
|
||||||
|
#define RLblockSizeLen 15 ///< block size length (< 16): ld(BufferSize) < RLblockSizeLen <= 2*ld(BufferSize)
|
||||||
|
#define LinBlockSize 8 ///< side length of a coefficient block in a HH or LL subband
|
||||||
|
#define InterBlockSize 4 ///< side length of a coefficient block in a HL or LH subband
|
||||||
|
#ifdef __PGF32SUPPORT__ |
||||||
|
#define MaxBitPlanes 31 ///< maximum number of bit planes of m_value: 32 minus sign bit
|
||||||
|
#else |
||||||
|
#define MaxBitPlanes 15 ///< maximum number of bit planes of m_value: 16 minus sign bit
|
||||||
|
#endif |
||||||
|
#define MaxBitPlanesLog 5 ///< number of bits to code the maximum number of bit planes (in 32 or 16 bit mode)
|
||||||
|
#define MaxQuality MaxBitPlanes ///< maximum quality
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// Types
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
enum Orientation { LL = 0, HL = 1, LH = 2, HH = 3 }; |
||||||
|
enum ProgressMode { PM_Relative, PM_Absolute }; |
||||||
|
enum UserdataPolicy { UP_Skip = 0, UP_CachePrefix = 1, UP_CacheAll = 2 }; |
||||||
|
|
||||||
|
/// general PGF file structure
|
||||||
|
/// PGFPreHeader PGFHeader [PGFPostHeader] LevelLengths Level_n-1 Level_n-2 ... Level_0
|
||||||
|
/// PGFPostHeader ::= [ColorTable] [UserData]
|
||||||
|
/// LevelLengths ::= UINT32[nLevels]
|
||||||
|
|
||||||
|
#pragma pack(1) |
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// PGF magic and version (part of PGF pre-header)
|
||||||
|
/// @author C. Stamm
|
||||||
|
/// @brief PGF identification and version
|
||||||
|
struct PGFMagicVersion { |
||||||
|
char magic[3]; ///< PGF identification = "PGF"
|
||||||
|
UINT8 version; ///< PGF version
|
||||||
|
// total: 4 Bytes
|
||||||
|
}; |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// PGF pre-header defined header length and PGF identification and version
|
||||||
|
/// @author C. Stamm
|
||||||
|
/// @brief PGF pre-header
|
||||||
|
struct PGFPreHeader : PGFMagicVersion { |
||||||
|
UINT32 hSize; ///< total size of PGFHeader, [ColorTable], and [UserData] in bytes (since Version 6: 4 Bytes)
|
||||||
|
// total: 8 Bytes
|
||||||
|
}; |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Version number since major version 7
|
||||||
|
/// @author C. Stamm
|
||||||
|
/// @brief version number stored in header since major version 7
|
||||||
|
struct PGFVersionNumber { |
||||||
|
PGFVersionNumber(UINT8 _major, UINT8 _year, UINT8 _week) |
||||||
|
#ifdef PGF_USE_BIG_ENDIAN |
||||||
|
: week(_week), year(_year), major(_major) {} |
||||||
|
#else |
||||||
|
: major(_major), year(_year), week(_week) {} |
||||||
|
#endif // PGF_USE_BIG_ENDIAN
|
||||||
|
|
||||||
|
#ifdef PGF_USE_BIG_ENDIAN |
||||||
|
UINT16 week : 6; ///< week number in a year
|
||||||
|
UINT16 year : 6; ///< year since 2000 (year 2001 = 1)
|
||||||
|
UINT16 major : 4; ///< major version number
|
||||||
|
#else |
||||||
|
UINT16 major : 4; ///< major version number
|
||||||
|
UINT16 year : 6; ///< year since 2000 (year 2001 = 1)
|
||||||
|
UINT16 week : 6; ///< week number in a year
|
||||||
|
#endif // PGF_USE_BIG_ENDIAN
|
||||||
|
}; |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// PGF header contains image information
|
||||||
|
/// @author C. Stamm
|
||||||
|
/// @brief PGF header
|
||||||
|
struct PGFHeader { |
||||||
|
PGFHeader() : width(0), height(0), nLevels(0), quality(0), bpp(0), channels(0), mode(ImageModeUnknown), usedBitsPerChannel(0), version(0, 0, 0) {} |
||||||
|
UINT32 width; ///< image width in pixels
|
||||||
|
UINT32 height; ///< image height in pixels
|
||||||
|
UINT8 nLevels; ///< number of FWT transforms
|
||||||
|
UINT8 quality; ///< quantization parameter: 0=lossless, 4=standard, 6=poor quality
|
||||||
|
UINT8 bpp; ///< bits per pixel
|
||||||
|
UINT8 channels; ///< number of channels
|
||||||
|
UINT8 mode; ///< image mode according to Adobe's image modes
|
||||||
|
UINT8 usedBitsPerChannel; ///< number of used bits per channel in 16- and 32-bit per channel modes
|
||||||
|
PGFVersionNumber version; ///< codec version number: (since Version 7)
|
||||||
|
// total: 16 Bytes
|
||||||
|
}; |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// PGF post-header is optional. It contains color table and user data
|
||||||
|
/// @author C. Stamm
|
||||||
|
/// @brief Optional PGF post-header
|
||||||
|
struct PGFPostHeader { |
||||||
|
RGBQUAD clut[ColorTableLen];///< color table for indexed color images (optional part of file header)
|
||||||
|
UINT8 *userData; ///< user data of size userDataLen (optional part of file header)
|
||||||
|
UINT32 userDataLen; ///< user data size in bytes (not part of file header)
|
||||||
|
UINT32 cachedUserDataLen; ///< cached user data size in bytes (not part of file header)
|
||||||
|
}; |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// ROI block header is used with ROI coding scheme. It contains block size and tile end flag
|
||||||
|
/// @author C. Stamm
|
||||||
|
/// @brief Block header used with ROI coding scheme
|
||||||
|
union ROIBlockHeader { |
||||||
|
UINT16 val; ///< unstructured union value
|
||||||
|
/// @brief Named ROI block header (part of the union)
|
||||||
|
struct RBH { |
||||||
|
#ifdef PGF_USE_BIG_ENDIAN |
||||||
|
UINT16 tileEnd : 1; ///< 1: last part of a tile
|
||||||
|
UINT16 bufferSize: RLblockSizeLen; ///< number of uncoded UINT32 values in a block
|
||||||
|
#else |
||||||
|
UINT16 bufferSize: RLblockSizeLen; ///< number of uncoded UINT32 values in a block
|
||||||
|
UINT16 tileEnd : 1; ///< 1: last part of a tile
|
||||||
|
#endif // PGF_USE_BIG_ENDIAN
|
||||||
|
} rbh; ///< ROI block header
|
||||||
|
// total: 2 Bytes
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// @param v Buffer size
|
||||||
|
ROIBlockHeader(UINT16 v) { val = v; } |
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// @param size Buffer size
|
||||||
|
/// @param end 0/1 Flag; 1: last part of a tile
|
||||||
|
ROIBlockHeader(UINT32 size, bool end) { ASSERT(size < (1 << RLblockSizeLen)); rbh.bufferSize = size; rbh.tileEnd = end; } |
||||||
|
}; |
||||||
|
|
||||||
|
#pragma pack() |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// PGF I/O exception
|
||||||
|
/// @author C. Stamm
|
||||||
|
/// @brief PGF exception
|
||||||
|
struct IOException { |
||||||
|
OSError error; ///< operating system error code
|
||||||
|
|
||||||
|
/// Standard constructor
|
||||||
|
IOException() : error(NoError) {} |
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// @param err Run-time error
|
||||||
|
IOException(OSError err) : error(err) {} |
||||||
|
}; |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Rectangle
|
||||||
|
/// @author C. Stamm
|
||||||
|
/// @brief Rectangle
|
||||||
|
struct PGFRect { |
||||||
|
UINT32 left, top, right, bottom; |
||||||
|
|
||||||
|
/// Standard constructor
|
||||||
|
PGFRect() : left(0), top(0), right(0), bottom(0) {} |
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// @param x Left offset
|
||||||
|
/// @param y Top offset
|
||||||
|
/// @param width Rectangle width
|
||||||
|
/// @param height Rectangle height
|
||||||
|
PGFRect(UINT32 x, UINT32 y, UINT32 width, UINT32 height) : left(x), top(y), right(x + width), bottom(y + height) {} |
||||||
|
|
||||||
|
#ifdef WIN32 |
||||||
|
PGFRect(const RECT& rect) : left(rect.left), top(rect.top), right(rect.right), bottom(rect.bottom) { |
||||||
|
ASSERT(rect.left >= 0 && rect.right >= 0 && rect.left <= rect.right); |
||||||
|
ASSERT(rect.top >= 0 && rect.bottom >= 0 && rect.top <= rect.bottom); |
||||||
|
} |
||||||
|
|
||||||
|
PGFRect& operator=(const RECT& rect) { |
||||||
|
left = rect.left; top = rect.top; right = rect.right; bottom = rect.bottom; |
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
operator RECT() { |
||||||
|
RECT rect = { (LONG)left, (LONG)top, (LONG)right, (LONG)bottom }; |
||||||
|
return rect; |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
/// @return Rectangle width
|
||||||
|
UINT32 Width() const { return right - left; } |
||||||
|
|
||||||
|
/// @return Rectangle height
|
||||||
|
UINT32 Height() const { return bottom - top; } |
||||||
|
|
||||||
|
/// Test if point (x,y) is inside this rectangle (inclusive top-left edges, exclusive bottom-right edges)
|
||||||
|
/// @param x Point coordinate x
|
||||||
|
/// @param y Point coordinate y
|
||||||
|
/// @return True if point (x,y) is inside this rectangle (inclusive top-left edges, exclusive bottom-right edges)
|
||||||
|
bool IsInside(UINT32 x, UINT32 y) const { return (x >= left && x < right && y >= top && y < bottom); } |
||||||
|
}; |
||||||
|
|
||||||
|
#ifdef __PGF32SUPPORT__ |
||||||
|
typedef INT32 DataT; |
||||||
|
#else |
||||||
|
typedef INT16 DataT; |
||||||
|
#endif |
||||||
|
|
||||||
|
typedef void (*RefreshCB)(void *p); |
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
// Image constants
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
#define MagicVersionSize sizeof(PGFMagicVersion) |
||||||
|
#define PreHeaderSize sizeof(PGFPreHeader) |
||||||
|
#define HeaderSize sizeof(PGFHeader) |
||||||
|
#define ColorTableSize (ColorTableLen*sizeof(RGBQUAD)) |
||||||
|
#define DataTSize sizeof(DataT) |
||||||
|
#define MaxUserDataSize 0x7FFFFFFF |
||||||
|
|
||||||
|
#endif //PGF_PGFTYPES_H
|
@ -0,0 +1,114 @@ |
|||||||
|
The Progressive Graphics File |
||||||
|
============================= |
||||||
|
|
||||||
|
For more information see http://www.libpgf.org. There you can find some |
||||||
|
documents concerning this progressive graphic file codec. |
||||||
|
|
||||||
|
This project is hosted on the Sourceforge.net platform. For support and |
||||||
|
questions, please use the installed mailing list and forums there. |
||||||
|
The Sourceforge URL of our project is: http://sourceforge.net/projects/libpgf |
||||||
|
|
||||||
|
============================= |
||||||
|
Release Notes |
||||||
|
|
||||||
|
Version 7.19.3, (Tue, 15 Jan 2019) |
||||||
|
------------------------------------ |
||||||
|
|
||||||
|
1. The new version is a minor update of version 7.15.25. |
||||||
|
|
||||||
|
2. This version fixes a compilation bug seen when ROI support is disabled. |
||||||
|
|
||||||
|
|
||||||
|
Version 7.15.32, (Thu, 6 Aug 2015) |
||||||
|
------------------------------------ |
||||||
|
|
||||||
|
1. The new version is a minor update of version 7.15.25. |
||||||
|
|
||||||
|
2. This version improves the reuse of CPGFImage objects for several decoding operations. |
||||||
|
It clarifies the usage of CPGFImage::Close() and CPGFImage::Destroy() by deletion of |
||||||
|
Close(). Several reading operations can be performed in the following way: |
||||||
|
Open(), Read(), GetBitmap(), ResetStreamPos(), Read(), GetBitmap(), ResetStreamPos(), ... |
||||||
|
Calling Destroy() frees all allocated ressources and reinitializes the object to the |
||||||
|
same state as the constructor does. This allows the reuse of the CPGFImage object for |
||||||
|
encoding and decoding: |
||||||
|
SetHeader(), ImportBitmap(), Write(), ResetStreamPos(), Destroy(), Open(), Read(), GetBitmap() |
||||||
|
|
||||||
|
3. Caching or skipping of user data (meta data) while opening a PGF image can be controlled |
||||||
|
by a new UserdataPolicy in ConfigureDecoder(). |
||||||
|
|
||||||
|
|
||||||
|
Version 7.15.25, (Sat, 20 June 2015) |
||||||
|
------------------------------------ |
||||||
|
|
||||||
|
1. This new version is a replacement of version 6.14.12. |
||||||
|
In case you use the ROI decoding, we strongly encourage using version 6.15.25 instead of an older version. |
||||||
|
|
||||||
|
2. This version fixes some decoder bugs only seen in ROI decoding. |
||||||
|
ROI decoding is now also supported for Bitmap and RGB12 image modes. |
||||||
|
|
||||||
|
3. This version introduces a new and more efficient data format for binary images (bitmaps). |
||||||
|
The new format allows ROI decoding. |
||||||
|
The decoder supports both the old and the new format, but ROI decoding works only with the new format. |
||||||
|
|
||||||
|
4. The two reserverd bytes in PGFHeader are now used for a more detailled PGF version number. |
||||||
|
|
||||||
|
5. The Visual Studio project files are in the VS12 format. |
||||||
|
|
||||||
|
|
||||||
|
Version 6.14.12, (Wed, 9 April 2014) |
||||||
|
------------------------------------ |
||||||
|
|
||||||
|
1. The new version is a minor update of version 6.12.24. |
||||||
|
|
||||||
|
2. It mainly contains some fixes of memory leaks in the OpenMP part and some improvements suggested by cppcheck and Coverity. |
||||||
|
|
||||||
|
3. The Visual Studio project files are in the VS11 format. |
||||||
|
|
||||||
|
|
||||||
|
Version 6.12.24, (Thu, 14 June 2012) |
||||||
|
------------------------------------ |
||||||
|
|
||||||
|
1. The new version is a replacement of version 6.11.42. |
||||||
|
In case you use the ROI encoding scheme, we strongly encourage using version 6.12.24 instead of version 6.11.42. |
||||||
|
|
||||||
|
2. This version fixes some decoder bugs, sometimes seen in ROI decoding. |
||||||
|
|
||||||
|
3. This version allows a simpler user-data handling, especially for uncached metadata. The following two methods |
||||||
|
in the class PGFimage are designed for this purpose: |
||||||
|
|
||||||
|
GetUserDataPos() returns in an opened PGF image the stream position of the user data area. |
||||||
|
|
||||||
|
WriteImage() encodes and writes the image at the current stream position. This method is called after |
||||||
|
WriteHeader(). In case you want to write uncached metadata into the stream, then do that after WriteHeader() |
||||||
|
and just before WriteImage(). If you are not interested in writing uncached metadata, then you usually use |
||||||
|
Write() instead of WriteImage(). WriteHeader() and WriteImage() are called inside of Write(). |
||||||
|
|
||||||
|
|
||||||
|
Version 6.11.42, (Sun, 23 Oct 2011) |
||||||
|
----------------------------------- |
||||||
|
|
||||||
|
1. The new version is a replacement of version 6.11.24. |
||||||
|
We strongly encourage using version 6.11.42 instead of version 6.11.24. |
||||||
|
|
||||||
|
2. This version fixes some decoder bugs, only seen in lossless compression of |
||||||
|
large images. |
||||||
|
|
||||||
|
3. The rarely used, but sometimes misused, background information (3 Bytes) |
||||||
|
in the PGFHeader has been replaced by |
||||||
|
|
||||||
|
UINT8 usedBitsPerChannel; // number of used bits per channel |
||||||
|
// in 16- and 32-bit per channel modes |
||||||
|
UINT8 reserved1, reserved2; // not used |
||||||
|
|
||||||
|
The value usedBitsPerChannel is helpful in case you have more than 8 (16) but |
||||||
|
less than 16 (32) significant bits per channel, stored in the most |
||||||
|
significant bits of a pixel. For example, you have a grayscale image with 14 |
||||||
|
bit significant data per pixel stored in the ImageModeGray16 pixel format. In |
||||||
|
case you have left shifted the 14 bits to be the most significant 14 bits, |
||||||
|
then you should set usedBitsPerChannel=14. This will increase the compression |
||||||
|
ratio without any drawbacks, because the 14 bits are internally right shifted. |
||||||
|
On the other side, if the 14 bits are the least significant bits in |
||||||
|
your 16 bit pixel format, then you shoulden’t set usedBitsPerChannel. It will |
||||||
|
be automatically set to 16, but this is no problem, since the not used most |
||||||
|
significant bits per pixel are never coded at all. So, in both cases the same |
||||||
|
compression ratio will result. |
@ -0,0 +1,388 @@ |
|||||||
|
/*
|
||||||
|
* The Progressive Graphics File; http://www.libpgf.org
|
||||||
|
*
|
||||||
|
* $Date: 2006-06-04 22:05:59 +0200 (So, 04 Jun 2006) $ |
||||||
|
* $Revision: 229 $ |
||||||
|
*
|
||||||
|
* This file Copyright (C) 2006 xeraina GmbH, Switzerland |
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE |
||||||
|
* as published by the Free Software Foundation; either version 2.1 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||||
|
*/ |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// @file Subband.cpp
|
||||||
|
/// @brief PGF wavelet subband class implementation
|
||||||
|
/// @author C. Stamm
|
||||||
|
|
||||||
|
#include "Subband.h" |
||||||
|
#include "Encoder.h" |
||||||
|
#include "Decoder.h" |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// Default constructor
|
||||||
|
CSubband::CSubband()
|
||||||
|
: m_width(0) |
||||||
|
, m_height(0) |
||||||
|
, m_size(0) |
||||||
|
, m_level(0) |
||||||
|
, m_orientation(LL) |
||||||
|
, m_dataPos(0) |
||||||
|
, m_data(0) |
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
, m_nTiles(0) |
||||||
|
#endif |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// Destructor
|
||||||
|
CSubband::~CSubband() { |
||||||
|
FreeMemory(); |
||||||
|
} |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// Initialize subband parameters
|
||||||
|
void CSubband::Initialize(UINT32 width, UINT32 height, int level, Orientation orient) { |
||||||
|
m_width = width; |
||||||
|
m_height = height; |
||||||
|
m_size = m_width*m_height; |
||||||
|
m_level = level; |
||||||
|
m_orientation = orient; |
||||||
|
m_data = 0; |
||||||
|
m_dataPos = 0; |
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
m_ROI.left = 0; |
||||||
|
m_ROI.top = 0; |
||||||
|
m_ROI.right = m_width; |
||||||
|
m_ROI.bottom = m_height; |
||||||
|
m_nTiles = 0; |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// Allocate a memory buffer to store all wavelet coefficients of this subband.
|
||||||
|
// @return True if the allocation works without any problems
|
||||||
|
bool CSubband::AllocMemory() { |
||||||
|
UINT32 oldSize = m_size; |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
m_size = BufferWidth()*m_ROI.Height(); |
||||||
|
#endif |
||||||
|
ASSERT(m_size > 0); |
||||||
|
|
||||||
|
if (m_data) { |
||||||
|
if (oldSize >= m_size) { |
||||||
|
return true; |
||||||
|
} else { |
||||||
|
delete[] m_data; |
||||||
|
m_data = new(std::nothrow) DataT[m_size]; |
||||||
|
return (m_data != 0); |
||||||
|
} |
||||||
|
} else { |
||||||
|
m_data = new(std::nothrow) DataT[m_size]; |
||||||
|
return (m_data != 0); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// Delete the memory buffer of this subband.
|
||||||
|
void CSubband::FreeMemory() { |
||||||
|
if (m_data) { |
||||||
|
delete[] m_data; m_data = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// Perform subband quantization with given quantization parameter.
|
||||||
|
// A scalar quantization (with dead-zone) is used. A large quantization value
|
||||||
|
// results in strong quantization and therefore in big quality loss.
|
||||||
|
// @param quantParam A quantization parameter (larger or equal to 0)
|
||||||
|
void CSubband::Quantize(int quantParam) { |
||||||
|
if (m_orientation == LL) { |
||||||
|
quantParam -= (m_level + 1); |
||||||
|
// uniform rounding quantization
|
||||||
|
if (quantParam > 0) { |
||||||
|
quantParam--; |
||||||
|
for (UINT32 i=0; i < m_size; i++) { |
||||||
|
if (m_data[i] < 0) { |
||||||
|
m_data[i] = -(((-m_data[i] >> quantParam) + 1) >> 1); |
||||||
|
} else { |
||||||
|
m_data[i] = ((m_data[i] >> quantParam) + 1) >> 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (m_orientation == HH) { |
||||||
|
quantParam -= (m_level - 1); |
||||||
|
} else { |
||||||
|
quantParam -= m_level; |
||||||
|
} |
||||||
|
// uniform deadzone quantization
|
||||||
|
if (quantParam > 0) { |
||||||
|
int threshold = ((1 << quantParam) * 7)/5; // good value
|
||||||
|
quantParam--; |
||||||
|
for (UINT32 i=0; i < m_size; i++) { |
||||||
|
if (m_data[i] < -threshold) { |
||||||
|
m_data[i] = -(((-m_data[i] >> quantParam) + 1) >> 1); |
||||||
|
} else if (m_data[i] > threshold) { |
||||||
|
m_data[i] = ((m_data[i] >> quantParam) + 1) >> 1; |
||||||
|
} else { |
||||||
|
m_data[i] = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Perform subband dequantization with given quantization parameter.
|
||||||
|
/// A scalar quantization (with dead-zone) is used. A large quantization value
|
||||||
|
/// results in strong quantization and therefore in big quality loss.
|
||||||
|
/// @param quantParam A quantization parameter (larger or equal to 0)
|
||||||
|
void CSubband::Dequantize(int quantParam) { |
||||||
|
if (m_orientation == LL) { |
||||||
|
quantParam -= m_level + 1; |
||||||
|
} else if (m_orientation == HH) { |
||||||
|
quantParam -= m_level - 1; |
||||||
|
} else { |
||||||
|
quantParam -= m_level; |
||||||
|
} |
||||||
|
if (quantParam > 0) { |
||||||
|
for (UINT32 i=0; i < m_size; i++) { |
||||||
|
m_data[i] <<= quantParam; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Extracts a rectangular subregion of this subband.
|
||||||
|
/// Write wavelet coefficients into buffer.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param encoder An encoder instance
|
||||||
|
/// @param tile True if just a rectangular region is extracted, false if the entire subband is extracted.
|
||||||
|
/// @param tileX Tile index in x-direction
|
||||||
|
/// @param tileY Tile index in y-direction
|
||||||
|
void CSubband::ExtractTile(CEncoder& encoder, bool tile /*= false*/, UINT32 tileX /*= 0*/, UINT32 tileY /*= 0*/) { |
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
if (tile) { |
||||||
|
// compute tile position and size
|
||||||
|
UINT32 xPos, yPos, w, h; |
||||||
|
TilePosition(tileX, tileY, xPos, yPos, w, h); |
||||||
|
|
||||||
|
// write values into buffer using partitiong scheme
|
||||||
|
encoder.Partition(this, w, h, xPos + yPos*m_width, m_width); |
||||||
|
} else
|
||||||
|
#endif |
||||||
|
{ |
||||||
|
(void)tileX; (void)tileY; (void)tile; // prevents from unreferenced formal parameter warning
|
||||||
|
// write values into buffer using partitiong scheme
|
||||||
|
encoder.Partition(this, m_width, m_height, 0, m_width); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Decoding and dequantization of this subband.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param decoder A decoder instance
|
||||||
|
/// @param quantParam Dequantization value
|
||||||
|
/// @param tile True if just a rectangular region is placed, false if the entire subband is placed.
|
||||||
|
/// @param tileX Tile index in x-direction
|
||||||
|
/// @param tileY Tile index in y-direction
|
||||||
|
void CSubband::PlaceTile(CDecoder& decoder, int quantParam, bool tile /*= false*/, UINT32 tileX /*= 0*/, UINT32 tileY /*= 0*/) { |
||||||
|
// allocate memory
|
||||||
|
if (!AllocMemory()) ReturnWithError(InsufficientMemory); |
||||||
|
|
||||||
|
// correct quantParam with normalization factor
|
||||||
|
if (m_orientation == LL) { |
||||||
|
quantParam -= m_level + 1; |
||||||
|
} else if (m_orientation == HH) { |
||||||
|
quantParam -= m_level - 1; |
||||||
|
} else { |
||||||
|
quantParam -= m_level; |
||||||
|
} |
||||||
|
if (quantParam < 0) quantParam = 0; |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
if (tile) { |
||||||
|
UINT32 xPos, yPos, w, h; |
||||||
|
|
||||||
|
// compute tile position and size
|
||||||
|
TilePosition(tileX, tileY, xPos, yPos, w, h); |
||||||
|
|
||||||
|
ASSERT(xPos >= m_ROI.left && yPos >= m_ROI.top); |
||||||
|
decoder.Partition(this, quantParam, w, h, (xPos - m_ROI.left) + (yPos - m_ROI.top)*BufferWidth(), BufferWidth()); |
||||||
|
} else
|
||||||
|
#endif |
||||||
|
{ |
||||||
|
(void)tileX; (void)tileY; (void)tile; // prevents from unreferenced formal parameter warning
|
||||||
|
// read values into buffer using partitiong scheme
|
||||||
|
decoder.Partition(this, quantParam, m_width, m_height, 0, m_width); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Set ROI
|
||||||
|
void CSubband::SetAlignedROI(const PGFRect& roi) { |
||||||
|
ASSERT(roi.left <= m_width);
|
||||||
|
ASSERT(roi.top <= m_height);
|
||||||
|
|
||||||
|
m_ROI = roi;
|
||||||
|
if (m_ROI.right > m_width) m_ROI.right = m_width;
|
||||||
|
if (m_ROI.bottom > m_height) m_ROI.bottom = m_height; |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Compute tile position and size.
|
||||||
|
/// @param tileX Tile index in x-direction
|
||||||
|
/// @param tileY Tile index in y-direction
|
||||||
|
/// @param xPos [out] Offset to left
|
||||||
|
/// @param yPos [out] Offset to top
|
||||||
|
/// @param w [out] Tile width
|
||||||
|
/// @param h [out] Tile height
|
||||||
|
void CSubband::TilePosition(UINT32 tileX, UINT32 tileY, UINT32& xPos, UINT32& yPos, UINT32& w, UINT32& h) const { |
||||||
|
ASSERT(tileX < m_nTiles); ASSERT(tileY < m_nTiles); |
||||||
|
// example
|
||||||
|
// band = HH, w = 30, ldTiles = 2 -> 4 tiles in a row/column
|
||||||
|
// --> tile widths
|
||||||
|
// 8 7 8 7
|
||||||
|
//
|
||||||
|
// tile partitioning scheme
|
||||||
|
// 0 1 2 3
|
||||||
|
// 4 5 6 7
|
||||||
|
// 8 9 A B
|
||||||
|
// C D E F
|
||||||
|
|
||||||
|
UINT32 nTiles = m_nTiles; |
||||||
|
UINT32 m; |
||||||
|
UINT32 left = 0, right = nTiles; |
||||||
|
UINT32 top = 0, bottom = nTiles; |
||||||
|
|
||||||
|
xPos = 0; |
||||||
|
yPos = 0; |
||||||
|
w = m_width; |
||||||
|
h = m_height; |
||||||
|
|
||||||
|
while (nTiles > 1) { |
||||||
|
// compute xPos and w with binary search
|
||||||
|
m = left + ((right - left) >> 1); |
||||||
|
if (tileX >= m) { |
||||||
|
xPos += (w + 1) >> 1; |
||||||
|
w >>= 1; |
||||||
|
left = m; |
||||||
|
} else { |
||||||
|
w = (w + 1) >> 1; |
||||||
|
right = m; |
||||||
|
} |
||||||
|
// compute yPos and h with binary search
|
||||||
|
m = top + ((bottom - top) >> 1); |
||||||
|
if (tileY >= m) { |
||||||
|
yPos += (h + 1) >> 1; |
||||||
|
h >>= 1; |
||||||
|
top = m; |
||||||
|
} else { |
||||||
|
h = (h + 1) >> 1; |
||||||
|
bottom = m; |
||||||
|
} |
||||||
|
nTiles >>= 1; |
||||||
|
} |
||||||
|
ASSERT(xPos < m_width && (xPos + w <= m_width)); |
||||||
|
ASSERT(yPos < m_height && (yPos + h <= m_height)); |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Compute tile index and extrem position (x,y) of given position (xPos, yPos).
|
||||||
|
void CSubband::TileIndex(bool topLeft, UINT32 xPos, UINT32 yPos, UINT32& tileX, UINT32& tileY, UINT32& x, UINT32& y) const { |
||||||
|
UINT32 m; |
||||||
|
UINT32 left = 0, right = m_width; |
||||||
|
UINT32 top = 0, bottom = m_height; |
||||||
|
UINT32 nTiles = m_nTiles; |
||||||
|
|
||||||
|
if (xPos > m_width) xPos = m_width; |
||||||
|
if (yPos > m_height) yPos = m_height; |
||||||
|
|
||||||
|
if (topLeft) { |
||||||
|
// compute tileX with binary search
|
||||||
|
tileX = 0; |
||||||
|
while (nTiles > 1) { |
||||||
|
nTiles >>= 1; |
||||||
|
m = left + ((right - left + 1) >> 1); |
||||||
|
if (xPos < m) { |
||||||
|
// exclusive m
|
||||||
|
right = m; |
||||||
|
} else { |
||||||
|
tileX += nTiles; |
||||||
|
left = m; |
||||||
|
} |
||||||
|
} |
||||||
|
x = left; |
||||||
|
ASSERT(tileX >= 0 && tileX < m_nTiles); |
||||||
|
|
||||||
|
// compute tileY with binary search
|
||||||
|
nTiles = m_nTiles; |
||||||
|
tileY = 0; |
||||||
|
while (nTiles > 1) { |
||||||
|
nTiles >>= 1; |
||||||
|
m = top + ((bottom - top + 1) >> 1); |
||||||
|
if (yPos < m) { |
||||||
|
// exclusive m
|
||||||
|
bottom = m; |
||||||
|
} else { |
||||||
|
tileY += nTiles; |
||||||
|
top = m; |
||||||
|
} |
||||||
|
} |
||||||
|
y = top; |
||||||
|
ASSERT(tileY >= 0 && tileY < m_nTiles); |
||||||
|
|
||||||
|
} else { |
||||||
|
// compute tileX with binary search
|
||||||
|
tileX = 1; |
||||||
|
while (nTiles > 1) { |
||||||
|
nTiles >>= 1; |
||||||
|
m = left + ((right - left + 1) >> 1); |
||||||
|
if (xPos <= m) { |
||||||
|
// inclusive m
|
||||||
|
right = m; |
||||||
|
} else { |
||||||
|
tileX += nTiles; |
||||||
|
left = m; |
||||||
|
} |
||||||
|
} |
||||||
|
x = right; |
||||||
|
ASSERT(tileX > 0 && tileX <= m_nTiles); |
||||||
|
|
||||||
|
// compute tileY with binary search
|
||||||
|
nTiles = m_nTiles; |
||||||
|
tileY = 1; |
||||||
|
while (nTiles > 1) { |
||||||
|
nTiles >>= 1; |
||||||
|
m = top + ((bottom - top + 1) >> 1); |
||||||
|
if (yPos <= m) { |
||||||
|
// inclusive m
|
||||||
|
bottom = m; |
||||||
|
} else { |
||||||
|
tileY += nTiles; |
||||||
|
top = m; |
||||||
|
} |
||||||
|
} |
||||||
|
y = bottom; |
||||||
|
ASSERT(tileY > 0 && tileY <= m_nTiles); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,180 @@ |
|||||||
|
/*
|
||||||
|
* The Progressive Graphics File; http://www.libpgf.org
|
||||||
|
*
|
||||||
|
* $Date: 2006-06-04 22:05:59 +0200 (So, 04 Jun 2006) $ |
||||||
|
* $Revision: 229 $ |
||||||
|
*
|
||||||
|
* This file Copyright (C) 2006 xeraina GmbH, Switzerland |
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE |
||||||
|
* as published by the Free Software Foundation; either version 2.1 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||||
|
*/ |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// @file Subband.h
|
||||||
|
/// @brief PGF wavelet subband class
|
||||||
|
/// @author C. Stamm
|
||||||
|
|
||||||
|
#ifndef PGF_SUBBAND_H |
||||||
|
#define PGF_SUBBAND_H |
||||||
|
|
||||||
|
#include "PGFtypes.h" |
||||||
|
|
||||||
|
class CEncoder; |
||||||
|
class CDecoder; |
||||||
|
class CRoiIndices; |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// PGF wavelet channel subband class.
|
||||||
|
/// @author C. Stamm, R. Spuler
|
||||||
|
/// @brief Wavelet channel class
|
||||||
|
class CSubband { |
||||||
|
friend class CWaveletTransform; |
||||||
|
friend class CRoiIndices; |
||||||
|
|
||||||
|
public: |
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Standard constructor.
|
||||||
|
CSubband(); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Destructor.
|
||||||
|
~CSubband(); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Allocate a memory buffer to store all wavelet coefficients of this subband.
|
||||||
|
/// @return True if the allocation did work without any problems
|
||||||
|
bool AllocMemory(); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Delete the memory buffer of this subband.
|
||||||
|
void FreeMemory(); |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Extracts a rectangular subregion of this subband.
|
||||||
|
/// Write wavelet coefficients into buffer.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param encoder An encoder instance
|
||||||
|
/// @param tile True if just a rectangular region is extracted, false if the entire subband is extracted.
|
||||||
|
/// @param tileX Tile index in x-direction
|
||||||
|
/// @param tileY Tile index in y-direction
|
||||||
|
void ExtractTile(CEncoder& encoder, bool tile = false, UINT32 tileX = 0, UINT32 tileY = 0); |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Decoding and dequantization of this subband.
|
||||||
|
/// It might throw an IOException.
|
||||||
|
/// @param decoder A decoder instance
|
||||||
|
/// @param quantParam Dequantization value
|
||||||
|
/// @param tile True if just a rectangular region is placed, false if the entire subband is placed.
|
||||||
|
/// @param tileX Tile index in x-direction
|
||||||
|
/// @param tileY Tile index in y-direction
|
||||||
|
void PlaceTile(CDecoder& decoder, int quantParam, bool tile = false, UINT32 tileX = 0, UINT32 tileY = 0); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Perform subband quantization with given quantization parameter.
|
||||||
|
/// A scalar quantization (with dead-zone) is used. A large quantization value
|
||||||
|
/// results in strong quantization and therefore in big quality loss.
|
||||||
|
/// @param quantParam A quantization parameter (larger or equal to 0)
|
||||||
|
void Quantize(int quantParam); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Perform subband dequantization with given quantization parameter.
|
||||||
|
/// A scalar quantization (with dead-zone) is used. A large quantization value
|
||||||
|
/// results in strong quantization and therefore in big quality loss.
|
||||||
|
/// @param quantParam A quantization parameter (larger or equal to 0)
|
||||||
|
void Dequantize(int quantParam); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Store wavelet coefficient in subband at given position.
|
||||||
|
/// @param pos A subband position (>= 0)
|
||||||
|
/// @param v A wavelet coefficient
|
||||||
|
void SetData(UINT32 pos, DataT v) { ASSERT(pos < m_size); m_data[pos] = v; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Get a pointer to an array of all wavelet coefficients of this subband.
|
||||||
|
/// @return Pointer to array of wavelet coefficients
|
||||||
|
DataT* GetBuffer() { return m_data; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return wavelet coefficient at given position.
|
||||||
|
/// @param pos A subband position (>= 0)
|
||||||
|
/// @return Wavelet coefficient
|
||||||
|
DataT GetData(UINT32 pos) const { ASSERT(pos < m_size); return m_data[pos]; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return level of this subband.
|
||||||
|
/// @return Level of this subband
|
||||||
|
int GetLevel() const { return m_level; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return height of this subband.
|
||||||
|
/// @return Height of this subband (in pixels)
|
||||||
|
int GetHeight() const { return m_height; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return width of this subband.
|
||||||
|
/// @return Width of this subband (in pixels)
|
||||||
|
int GetWidth() const { return m_width; } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return orientation of this subband.
|
||||||
|
/// LL LH
|
||||||
|
/// HL HH
|
||||||
|
/// @return Orientation of this subband (LL, HL, LH, HH)
|
||||||
|
Orientation GetOrientation() const { return m_orientation; } |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// Set data buffer position to given position + one row.
|
||||||
|
/// @param pos Given position
|
||||||
|
void IncBuffRow(UINT32 pos) { m_dataPos = pos + BufferWidth(); } |
||||||
|
|
||||||
|
#endif |
||||||
|
|
||||||
|
private: |
||||||
|
void Initialize(UINT32 width, UINT32 height, int level, Orientation orient); |
||||||
|
void WriteBuffer(DataT val) { ASSERT(m_dataPos < m_size); m_data[m_dataPos++] = val; } |
||||||
|
void SetBuffer(DataT* b) { ASSERT(b); m_data = b; } |
||||||
|
DataT ReadBuffer() { ASSERT(m_dataPos < m_size); return m_data[m_dataPos++]; } |
||||||
|
|
||||||
|
UINT32 GetBuffPos() const { return m_dataPos; } |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
UINT32 BufferWidth() const { return m_ROI.Width(); } |
||||||
|
void TilePosition(UINT32 tileX, UINT32 tileY, UINT32& left, UINT32& top, UINT32& w, UINT32& h) const; |
||||||
|
void TileIndex(bool topLeft, UINT32 xPos, UINT32 yPos, UINT32& tileX, UINT32& tileY, UINT32& x, UINT32& y) const; |
||||||
|
const PGFRect& GetAlignedROI() const { return m_ROI; } |
||||||
|
void SetNTiles(UINT32 nTiles) { m_nTiles = nTiles; } |
||||||
|
void SetAlignedROI(const PGFRect& roi); |
||||||
|
void InitBuffPos(UINT32 left = 0, UINT32 top = 0) { m_dataPos = top*BufferWidth() + left; ASSERT(m_dataPos < m_size); } |
||||||
|
#else |
||||||
|
void InitBuffPos() { m_dataPos = 0; } |
||||||
|
#endif |
||||||
|
|
||||||
|
private: |
||||||
|
UINT32 m_width; ///< width in pixels
|
||||||
|
UINT32 m_height; ///< height in pixels
|
||||||
|
UINT32 m_size; ///< size of data buffer m_data
|
||||||
|
int m_level; ///< recursion level
|
||||||
|
Orientation m_orientation; ///< 0=LL, 1=HL, 2=LH, 3=HH L=lowpass filtered, H=highpass filterd
|
||||||
|
UINT32 m_dataPos; ///< current position in m_data
|
||||||
|
DataT* m_data; ///< buffer
|
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
PGFRect m_ROI; ///< region of interest (block aligned)
|
||||||
|
UINT32 m_nTiles; ///< number of tiles in one dimension in this subband
|
||||||
|
#endif |
||||||
|
}; |
||||||
|
|
||||||
|
#endif //PGF_SUBBAND_H
|
@ -0,0 +1,570 @@ |
|||||||
|
/*
|
||||||
|
* The Progressive Graphics File; http://www.libpgf.org
|
||||||
|
*
|
||||||
|
* $Date: 2006-05-18 16:03:32 +0200 (Do, 18 Mai 2006) $ |
||||||
|
* $Revision: 194 $ |
||||||
|
*
|
||||||
|
* This file Copyright (C) 2006 xeraina GmbH, Switzerland |
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE |
||||||
|
* as published by the Free Software Foundation; either version 2.1 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||||
|
*/ |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// @file WaveletTransform.cpp
|
||||||
|
/// @brief PGF wavelet transform class implementation
|
||||||
|
/// @author C. Stamm
|
||||||
|
|
||||||
|
#include "WaveletTransform.h" |
||||||
|
|
||||||
|
#define c1 1 // best value 1
|
||||||
|
#define c2 2 // best value 2
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor: Constructs a wavelet transform pyramid of given size and levels.
|
||||||
|
// @param width The width of the original image (at level 0) in pixels
|
||||||
|
// @param height The height of the original image (at level 0) in pixels
|
||||||
|
// @param levels The number of levels (>= 0)
|
||||||
|
// @param data Input data of subband LL at level 0
|
||||||
|
CWaveletTransform::CWaveletTransform(UINT32 width, UINT32 height, int levels, DataT* data)
|
||||||
|
:
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
m_indices(nullptr), |
||||||
|
#endif |
||||||
|
m_nLevels(levels + 1) // m_nLevels in CPGFImage determines the number of FWT steps; this.m_nLevels determines the number subband-planes
|
||||||
|
, m_subband(nullptr) |
||||||
|
{ |
||||||
|
ASSERT(m_nLevels > 0 && m_nLevels <= MaxLevel + 1); |
||||||
|
InitSubbands(width, height, data); |
||||||
|
} |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// Initialize size subbands on all levels
|
||||||
|
void CWaveletTransform::InitSubbands(UINT32 width, UINT32 height, DataT* data) { |
||||||
|
if (m_subband) Destroy(); |
||||||
|
|
||||||
|
// create subbands
|
||||||
|
m_subband = new CSubband[m_nLevels][NSubbands]; |
||||||
|
|
||||||
|
// init subbands
|
||||||
|
UINT32 loWidth = width; |
||||||
|
UINT32 hiWidth = width; |
||||||
|
UINT32 loHeight = height; |
||||||
|
UINT32 hiHeight = height; |
||||||
|
|
||||||
|
for (int level = 0; level < m_nLevels; level++) { |
||||||
|
m_subband[level][LL].Initialize(loWidth, loHeight, level, LL); // LL
|
||||||
|
m_subband[level][HL].Initialize(hiWidth, loHeight, level, HL); // HL
|
||||||
|
m_subband[level][LH].Initialize(loWidth, hiHeight, level, LH); // LH
|
||||||
|
m_subband[level][HH].Initialize(hiWidth, hiHeight, level, HH); // HH
|
||||||
|
hiWidth = loWidth >> 1; hiHeight = loHeight >> 1; |
||||||
|
loWidth = (loWidth + 1) >> 1; loHeight = (loHeight + 1) >> 1; |
||||||
|
} |
||||||
|
if (data) { |
||||||
|
m_subband[0][LL].SetBuffer(data); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Compute fast forward wavelet transform of LL subband at given level and
|
||||||
|
// stores result in all 4 subbands of level + 1.
|
||||||
|
// Wavelet transform used in writing a PGF file
|
||||||
|
// Forward Transform of srcBand and split and store it into subbands on destLevel
|
||||||
|
// low pass filter at even positions: 1/8[-1, 2, (6), 2, -1]
|
||||||
|
// high pass filter at odd positions: 1/4[-2, (4), -2]
|
||||||
|
// @param level A wavelet transform pyramid level (>= 0 && < Levels())
|
||||||
|
// @param quant A quantization value (linear scalar quantization)
|
||||||
|
// @return error in case of a memory allocation problem
|
||||||
|
OSError CWaveletTransform::ForwardTransform(int level, int quant) { |
||||||
|
ASSERT(level >= 0 && level < m_nLevels - 1); |
||||||
|
const int destLevel = level + 1; |
||||||
|
ASSERT(m_subband[destLevel]); |
||||||
|
CSubband* srcBand = &m_subband[level][LL]; ASSERT(srcBand); |
||||||
|
const UINT32 width = srcBand->GetWidth(); |
||||||
|
const UINT32 height = srcBand->GetHeight(); |
||||||
|
DataT* src = srcBand->GetBuffer(); ASSERT(src); |
||||||
|
DataT *row0, *row1, *row2, *row3; |
||||||
|
|
||||||
|
// Allocate memory for next transform level
|
||||||
|
for (int i=0; i < NSubbands; i++) { |
||||||
|
if (!m_subband[destLevel][i].AllocMemory()) return InsufficientMemory; |
||||||
|
} |
||||||
|
|
||||||
|
if (height >= FilterSize) { // changed from FilterSizeH to FilterSize
|
||||||
|
// top border handling
|
||||||
|
row0 = src; row1 = row0 + width; row2 = row1 + width; |
||||||
|
ForwardRow(row0, width); |
||||||
|
ForwardRow(row1, width); |
||||||
|
ForwardRow(row2, width); |
||||||
|
for (UINT32 k=0; k < width; k++) { |
||||||
|
row1[k] -= ((row0[k] + row2[k] + c1) >> 1); // high pass
|
||||||
|
row0[k] += ((row1[k] + c1) >> 1); // low pass
|
||||||
|
} |
||||||
|
InterleavedToSubbands(destLevel, row0, row1, width); |
||||||
|
row0 = row1; row1 = row2; row2 += width; row3 = row2 + width; |
||||||
|
|
||||||
|
// middle part
|
||||||
|
for (UINT32 i=3; i < height-1; i += 2) { |
||||||
|
ForwardRow(row2, width); |
||||||
|
ForwardRow(row3, width); |
||||||
|
for (UINT32 k=0; k < width; k++) { |
||||||
|
row2[k] -= ((row1[k] + row3[k] + c1) >> 1); // high pass filter
|
||||||
|
row1[k] += ((row0[k] + row2[k] + c2) >> 2); // low pass filter
|
||||||
|
} |
||||||
|
InterleavedToSubbands(destLevel, row1, row2, width); |
||||||
|
row0 = row2; row1 = row3; row2 = row3 + width; row3 = row2 + width; |
||||||
|
} |
||||||
|
|
||||||
|
// bottom border handling
|
||||||
|
if (height & 1) { |
||||||
|
for (UINT32 k=0; k < width; k++) { |
||||||
|
row1[k] += ((row0[k] + c1) >> 1); // low pass
|
||||||
|
} |
||||||
|
InterleavedToSubbands(destLevel, row1, nullptr, width); |
||||||
|
row0 = row1; row1 += width; |
||||||
|
} else { |
||||||
|
ForwardRow(row2, width); |
||||||
|
for (UINT32 k=0; k < width; k++) { |
||||||
|
row2[k] -= row1[k]; // high pass
|
||||||
|
row1[k] += ((row0[k] + row2[k] + c2) >> 2); // low pass
|
||||||
|
} |
||||||
|
InterleavedToSubbands(destLevel, row1, row2, width); |
||||||
|
row0 = row1; row1 = row2; row2 += width; |
||||||
|
} |
||||||
|
} else { |
||||||
|
// if height is too small
|
||||||
|
row0 = src; row1 = row0 + width; |
||||||
|
// first part
|
||||||
|
for (UINT32 k=0; k < height; k += 2) { |
||||||
|
ForwardRow(row0, width); |
||||||
|
ForwardRow(row1, width); |
||||||
|
InterleavedToSubbands(destLevel, row0, row1, width); |
||||||
|
row0 += width << 1; row1 += width << 1; |
||||||
|
} |
||||||
|
// bottom
|
||||||
|
if (height & 1) { |
||||||
|
InterleavedToSubbands(destLevel, row0, nullptr, width); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (quant > 0) { |
||||||
|
// subband quantization (without LL)
|
||||||
|
for (int i=1; i < NSubbands; i++) { |
||||||
|
m_subband[destLevel][i].Quantize(quant); |
||||||
|
} |
||||||
|
// LL subband quantization
|
||||||
|
if (destLevel == m_nLevels - 1) { |
||||||
|
m_subband[destLevel][LL].Quantize(quant); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// free source band
|
||||||
|
srcBand->FreeMemory(); |
||||||
|
return NoError; |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
// Forward transform one row
|
||||||
|
// low pass filter at even positions: 1/8[-1, 2, (6), 2, -1]
|
||||||
|
// high pass filter at odd positions: 1/4[-2, (4), -2]
|
||||||
|
void CWaveletTransform::ForwardRow(DataT* src, UINT32 width) { |
||||||
|
if (width >= FilterSize) { |
||||||
|
UINT32 i = 3; |
||||||
|
|
||||||
|
// left border handling
|
||||||
|
src[1] -= ((src[0] + src[2] + c1) >> 1); // high pass
|
||||||
|
src[0] += ((src[1] + c1) >> 1); // low pass
|
||||||
|
|
||||||
|
// middle part
|
||||||
|
for (; i < width-1; i += 2) { |
||||||
|
src[i] -= ((src[i-1] + src[i+1] + c1) >> 1); // high pass
|
||||||
|
src[i-1] += ((src[i-2] + src[i] + c2) >> 2); // low pass
|
||||||
|
} |
||||||
|
|
||||||
|
// right border handling
|
||||||
|
if (width & 1) { |
||||||
|
src[i-1] += ((src[i-2] + c1) >> 1); // low pass
|
||||||
|
} else { |
||||||
|
src[i] -= src[i-1]; // high pass
|
||||||
|
src[i-1] += ((src[i-2] + src[i] + c2) >> 2); // low pass
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
// Copy transformed and interleaved (L,H,L,H,...) rows loRow and hiRow to subbands LL,HL,LH,HH
|
||||||
|
void CWaveletTransform::InterleavedToSubbands(int destLevel, DataT* loRow, DataT* hiRow, UINT32 width) { |
||||||
|
const UINT32 wquot = width >> 1; |
||||||
|
const bool wrem = (width & 1); |
||||||
|
CSubband &ll = m_subband[destLevel][LL], &hl = m_subband[destLevel][HL]; |
||||||
|
CSubband &lh = m_subband[destLevel][LH], &hh = m_subband[destLevel][HH]; |
||||||
|
|
||||||
|
if (hiRow) { |
||||||
|
for (UINT32 i=0; i < wquot; i++) { |
||||||
|
ll.WriteBuffer(*loRow++); // first access, than increment
|
||||||
|
hl.WriteBuffer(*loRow++); |
||||||
|
lh.WriteBuffer(*hiRow++); // first access, than increment
|
||||||
|
hh.WriteBuffer(*hiRow++); |
||||||
|
} |
||||||
|
if (wrem) { |
||||||
|
ll.WriteBuffer(*loRow); |
||||||
|
lh.WriteBuffer(*hiRow); |
||||||
|
} |
||||||
|
} else { |
||||||
|
for (UINT32 i=0; i < wquot; i++) { |
||||||
|
ll.WriteBuffer(*loRow++); // first access, than increment
|
||||||
|
hl.WriteBuffer(*loRow++); |
||||||
|
} |
||||||
|
if (wrem) ll.WriteBuffer(*loRow); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Compute fast inverse wavelet transform of all 4 subbands of given level and
|
||||||
|
// stores result in LL subband of level - 1.
|
||||||
|
// Inverse wavelet transform used in reading a PGF file
|
||||||
|
// Inverse Transform srcLevel and combine to destBand
|
||||||
|
// low-pass coefficients at even positions, high-pass coefficients at odd positions
|
||||||
|
// inverse filter for even positions: 1/4[-1, (4), -1]
|
||||||
|
// inverse filter for odd positions: 1/8[-1, 4, (6), 4, -1]
|
||||||
|
// @param srcLevel A wavelet transform pyramid level (> 0 && <= Levels())
|
||||||
|
// @param w [out] A pointer to the returned width of subband LL (in pixels)
|
||||||
|
// @param h [out] A pointer to the returned height of subband LL (in pixels)
|
||||||
|
// @param data [out] A pointer to the returned array of image data
|
||||||
|
// @return error in case of a memory allocation problem
|
||||||
|
OSError CWaveletTransform::InverseTransform(int srcLevel, UINT32* w, UINT32* h, DataT** data) { |
||||||
|
ASSERT(srcLevel > 0 && srcLevel < m_nLevels); |
||||||
|
const int destLevel = srcLevel - 1; |
||||||
|
ASSERT(m_subband[destLevel]); |
||||||
|
CSubband* destBand = &m_subband[destLevel][LL]; |
||||||
|
UINT32 width, height; |
||||||
|
|
||||||
|
// allocate memory for the results of the inverse transform
|
||||||
|
if (!destBand->AllocMemory()) return InsufficientMemory; |
||||||
|
DataT *origin = destBand->GetBuffer(), *row0, *row1, *row2, *row3; |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
PGFRect destROI = destBand->GetAlignedROI();
|
||||||
|
const UINT32 destWidth = destROI.Width(); // destination buffer width
|
||||||
|
const UINT32 destHeight = destROI.Height(); // destination buffer height
|
||||||
|
width = destWidth; // destination working width
|
||||||
|
height = destHeight; // destination working height
|
||||||
|
|
||||||
|
// update destination ROI
|
||||||
|
if (destROI.top & 1) { |
||||||
|
destROI.top++; |
||||||
|
origin += destWidth; |
||||||
|
height--; |
||||||
|
} |
||||||
|
if (destROI.left & 1) { |
||||||
|
destROI.left++; |
||||||
|
origin++; |
||||||
|
width--; |
||||||
|
} |
||||||
|
|
||||||
|
// init source buffer position
|
||||||
|
const UINT32 leftD = destROI.left >> 1; |
||||||
|
const UINT32 left0 = m_subband[srcLevel][LL].GetAlignedROI().left; |
||||||
|
const UINT32 left1 = m_subband[srcLevel][HL].GetAlignedROI().left; |
||||||
|
const UINT32 topD = destROI.top >> 1; |
||||||
|
const UINT32 top0 = m_subband[srcLevel][LL].GetAlignedROI().top; |
||||||
|
const UINT32 top1 = m_subband[srcLevel][LH].GetAlignedROI().top; |
||||||
|
ASSERT(m_subband[srcLevel][LH].GetAlignedROI().left == left0); |
||||||
|
ASSERT(m_subband[srcLevel][HH].GetAlignedROI().left == left1); |
||||||
|
ASSERT(m_subband[srcLevel][HL].GetAlignedROI().top == top0); |
||||||
|
ASSERT(m_subband[srcLevel][HH].GetAlignedROI().top == top1); |
||||||
|
|
||||||
|
UINT32 srcOffsetX[2] = { 0, 0 }; |
||||||
|
UINT32 srcOffsetY[2] = { 0, 0 }; |
||||||
|
|
||||||
|
if (leftD >= __max(left0, left1)) { |
||||||
|
srcOffsetX[0] = leftD - left0; |
||||||
|
srcOffsetX[1] = leftD - left1; |
||||||
|
} else { |
||||||
|
if (left0 <= left1) { |
||||||
|
const UINT32 dx = (left1 - leftD) << 1; |
||||||
|
destROI.left += dx; |
||||||
|
origin += dx; |
||||||
|
width -= dx; |
||||||
|
srcOffsetX[0] = left1 - left0; |
||||||
|
} else { |
||||||
|
const UINT32 dx = (left0 - leftD) << 1; |
||||||
|
destROI.left += dx; |
||||||
|
origin += dx; |
||||||
|
width -= dx; |
||||||
|
srcOffsetX[1] = left0 - left1; |
||||||
|
} |
||||||
|
} |
||||||
|
if (topD >= __max(top0, top1)) { |
||||||
|
srcOffsetY[0] = topD - top0; |
||||||
|
srcOffsetY[1] = topD - top1; |
||||||
|
} else { |
||||||
|
if (top0 <= top1) { |
||||||
|
const UINT32 dy = (top1 - topD) << 1; |
||||||
|
destROI.top += dy; |
||||||
|
origin += dy*destWidth; |
||||||
|
height -= dy; |
||||||
|
srcOffsetY[0] = top1 - top0; |
||||||
|
} else { |
||||||
|
const UINT32 dy = (top0 - topD) << 1; |
||||||
|
destROI.top += dy; |
||||||
|
origin += dy*destWidth; |
||||||
|
height -= dy; |
||||||
|
srcOffsetY[1] = top0 - top1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
m_subband[srcLevel][LL].InitBuffPos(srcOffsetX[0], srcOffsetY[0]); |
||||||
|
m_subband[srcLevel][HL].InitBuffPos(srcOffsetX[1], srcOffsetY[0]); |
||||||
|
m_subband[srcLevel][LH].InitBuffPos(srcOffsetX[0], srcOffsetY[1]); |
||||||
|
m_subband[srcLevel][HH].InitBuffPos(srcOffsetX[1], srcOffsetY[1]); |
||||||
|
|
||||||
|
#else |
||||||
|
width = destBand->GetWidth(); |
||||||
|
height = destBand->GetHeight(); |
||||||
|
PGFRect destROI(0, 0, width, height); |
||||||
|
const UINT32 destWidth = width; // destination buffer width
|
||||||
|
const UINT32 destHeight = height; // destination buffer height
|
||||||
|
|
||||||
|
// init source buffer position
|
||||||
|
for (int i = 0; i < NSubbands; i++) { |
||||||
|
m_subband[srcLevel][i].InitBuffPos(); |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
if (destHeight >= FilterSize) { // changed from FilterSizeH to FilterSize
|
||||||
|
// top border handling
|
||||||
|
row0 = origin; row1 = row0 + destWidth; |
||||||
|
SubbandsToInterleaved(srcLevel, row0, row1, width); |
||||||
|
for (UINT32 k = 0; k < width; k++) { |
||||||
|
row0[k] -= ((row1[k] + c1) >> 1); // even
|
||||||
|
} |
||||||
|
|
||||||
|
// middle part
|
||||||
|
row2 = row1 + destWidth; row3 = row2 + destWidth; |
||||||
|
for (UINT32 i = destROI.top + 2; i < destROI.bottom - 1; i += 2) { |
||||||
|
SubbandsToInterleaved(srcLevel, row2, row3, width); |
||||||
|
for (UINT32 k = 0; k < width; k++) { |
||||||
|
row2[k] -= ((row1[k] + row3[k] + c2) >> 2); // even
|
||||||
|
row1[k] += ((row0[k] + row2[k] + c1) >> 1); // odd
|
||||||
|
} |
||||||
|
InverseRow(row0, width); |
||||||
|
InverseRow(row1, width); |
||||||
|
row0 = row2; row1 = row3; row2 = row1 + destWidth; row3 = row2 + destWidth; |
||||||
|
} |
||||||
|
|
||||||
|
// bottom border handling
|
||||||
|
if (height & 1) { |
||||||
|
SubbandsToInterleaved(srcLevel, row2, nullptr, width); |
||||||
|
for (UINT32 k = 0; k < width; k++) { |
||||||
|
row2[k] -= ((row1[k] + c1) >> 1); // even
|
||||||
|
row1[k] += ((row0[k] + row2[k] + c1) >> 1); // odd
|
||||||
|
} |
||||||
|
InverseRow(row0, width); |
||||||
|
InverseRow(row1, width); |
||||||
|
InverseRow(row2, width); |
||||||
|
row0 = row1; row1 = row2; row2 += destWidth; |
||||||
|
} else { |
||||||
|
for (UINT32 k = 0; k < width; k++) { |
||||||
|
row1[k] += row0[k]; |
||||||
|
} |
||||||
|
InverseRow(row0, width); |
||||||
|
InverseRow(row1, width); |
||||||
|
row0 = row1; row1 += destWidth; |
||||||
|
} |
||||||
|
} else { |
||||||
|
// height is too small
|
||||||
|
row0 = origin; row1 = row0 + destWidth; |
||||||
|
// first part
|
||||||
|
for (UINT32 k = 0; k < height; k += 2) { |
||||||
|
SubbandsToInterleaved(srcLevel, row0, row1, width); |
||||||
|
InverseRow(row0, width); |
||||||
|
InverseRow(row1, width); |
||||||
|
row0 += destWidth << 1; row1 += destWidth << 1; |
||||||
|
} |
||||||
|
// bottom
|
||||||
|
if (height & 1) { |
||||||
|
SubbandsToInterleaved(srcLevel, row0, nullptr, width); |
||||||
|
InverseRow(row0, width); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// free memory of the current srcLevel
|
||||||
|
for (int i = 0; i < NSubbands; i++) { |
||||||
|
m_subband[srcLevel][i].FreeMemory(); |
||||||
|
} |
||||||
|
|
||||||
|
// return info
|
||||||
|
*w = destWidth; |
||||||
|
*h = destHeight; |
||||||
|
*data = destBand->GetBuffer(); |
||||||
|
return NoError; |
||||||
|
} |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// Inverse Wavelet Transform of one row
|
||||||
|
// low-pass coefficients at even positions, high-pass coefficients at odd positions
|
||||||
|
// inverse filter for even positions: 1/4[-1, (4), -1]
|
||||||
|
// inverse filter for odd positions: 1/8[-1, 4, (6), 4, -1]
|
||||||
|
void CWaveletTransform::InverseRow(DataT* dest, UINT32 width) { |
||||||
|
if (width >= FilterSize) { |
||||||
|
UINT32 i = 2; |
||||||
|
|
||||||
|
// left border handling
|
||||||
|
dest[0] -= ((dest[1] + c1) >> 1); // even
|
||||||
|
|
||||||
|
// middle part
|
||||||
|
for (; i < width - 1; i += 2) { |
||||||
|
dest[i] -= ((dest[i-1] + dest[i+1] + c2) >> 2); // even
|
||||||
|
dest[i-1] += ((dest[i-2] + dest[i] + c1) >> 1); // odd
|
||||||
|
} |
||||||
|
|
||||||
|
// right border handling
|
||||||
|
if (width & 1) { |
||||||
|
dest[i] -= ((dest[i-1] + c1) >> 1); // even
|
||||||
|
dest[i-1] += ((dest[i-2] + dest[i] + c1) >> 1); // odd
|
||||||
|
} else { |
||||||
|
dest[i-1] += dest[i-2]; // odd
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////
|
||||||
|
// Copy transformed coefficients from subbands LL,HL,LH,HH to interleaved format (L,H,L,H,...)
|
||||||
|
void CWaveletTransform::SubbandsToInterleaved(int srcLevel, DataT* loRow, DataT* hiRow, UINT32 width) { |
||||||
|
const UINT32 wquot = width >> 1; |
||||||
|
const bool wrem = (width & 1); |
||||||
|
CSubband &ll = m_subband[srcLevel][LL], &hl = m_subband[srcLevel][HL]; |
||||||
|
CSubband &lh = m_subband[srcLevel][LH], &hh = m_subband[srcLevel][HH]; |
||||||
|
|
||||||
|
if (hiRow) { |
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
const bool storePos = wquot < ll.BufferWidth(); |
||||||
|
UINT32 llPos = 0, hlPos = 0, lhPos = 0, hhPos = 0; |
||||||
|
|
||||||
|
if (storePos) { |
||||||
|
// save current src buffer positions
|
||||||
|
llPos = ll.GetBuffPos();
|
||||||
|
hlPos = hl.GetBuffPos();
|
||||||
|
lhPos = lh.GetBuffPos();
|
||||||
|
hhPos = hh.GetBuffPos();
|
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
for (UINT32 i=0; i < wquot; i++) { |
||||||
|
*loRow++ = ll.ReadBuffer();// first access, than increment
|
||||||
|
*loRow++ = hl.ReadBuffer();// first access, than increment
|
||||||
|
*hiRow++ = lh.ReadBuffer();// first access, than increment
|
||||||
|
*hiRow++ = hh.ReadBuffer();// first access, than increment
|
||||||
|
} |
||||||
|
|
||||||
|
if (wrem) { |
||||||
|
*loRow++ = ll.ReadBuffer();// first access, than increment
|
||||||
|
*hiRow++ = lh.ReadBuffer();// first access, than increment
|
||||||
|
} |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
if (storePos) { |
||||||
|
// increment src buffer positions
|
||||||
|
ll.IncBuffRow(llPos);
|
||||||
|
hl.IncBuffRow(hlPos);
|
||||||
|
lh.IncBuffRow(lhPos);
|
||||||
|
hh.IncBuffRow(hhPos);
|
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
} else { |
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
const bool storePos = wquot < ll.BufferWidth(); |
||||||
|
UINT32 llPos = 0, hlPos = 0; |
||||||
|
|
||||||
|
if (storePos) { |
||||||
|
// save current src buffer positions
|
||||||
|
llPos = ll.GetBuffPos();
|
||||||
|
hlPos = hl.GetBuffPos();
|
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
for (UINT32 i=0; i < wquot; i++) { |
||||||
|
*loRow++ = ll.ReadBuffer();// first access, than increment
|
||||||
|
*loRow++ = hl.ReadBuffer();// first access, than increment
|
||||||
|
} |
||||||
|
if (wrem) *loRow++ = ll.ReadBuffer(); |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
if (storePos) { |
||||||
|
// increment src buffer positions
|
||||||
|
ll.IncBuffRow(llPos);
|
||||||
|
hl.IncBuffRow(hlPos);
|
||||||
|
} |
||||||
|
#endif |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Compute and store ROIs for nLevels
|
||||||
|
/// @param roi rectangular region of interest at level 0
|
||||||
|
void CWaveletTransform::SetROI(PGFRect roi) { |
||||||
|
const UINT32 delta = (FilterSize >> 1) << m_nLevels; |
||||||
|
|
||||||
|
// create tile indices
|
||||||
|
delete[] m_indices; |
||||||
|
m_indices = new PGFRect[m_nLevels]; |
||||||
|
|
||||||
|
// enlarge rect: add margin
|
||||||
|
roi.left = (roi.left > delta) ? roi.left - delta : 0; |
||||||
|
roi.top = (roi.top > delta) ? roi.top - delta : 0; |
||||||
|
roi.right += delta;
|
||||||
|
roi.bottom += delta;
|
||||||
|
|
||||||
|
for (int l = 0; l < m_nLevels; l++) { |
||||||
|
PGFRect alignedROI; |
||||||
|
PGFRect& indices = m_indices[l]; |
||||||
|
UINT32 nTiles = GetNofTiles(l); |
||||||
|
CSubband& subband = m_subband[l][LL]; |
||||||
|
|
||||||
|
// use roi to determine the necessary tile indices (for all subbands the same) and aligned ROI for LL subband
|
||||||
|
subband.SetNTiles(nTiles); // must be called before TileIndex()
|
||||||
|
subband.TileIndex(true, roi.left, roi.top, indices.left, indices.top, alignedROI.left, alignedROI.top); |
||||||
|
subband.TileIndex(false, roi.right, roi.bottom, indices.right, indices.bottom, alignedROI.right, alignedROI.bottom); |
||||||
|
subband.SetAlignedROI(alignedROI); |
||||||
|
ASSERT(l == 0 || |
||||||
|
(m_indices[l-1].left >= 2*m_indices[l].left && |
||||||
|
m_indices[l-1].top >= 2*m_indices[l].top && |
||||||
|
m_indices[l-1].right <= 2*m_indices[l].right && |
||||||
|
m_indices[l-1].bottom <= 2*m_indices[l].bottom)); |
||||||
|
|
||||||
|
// determine aligned ROI of other three subbands
|
||||||
|
PGFRect aroi; |
||||||
|
UINT32 w, h; |
||||||
|
for (int b = 1; b < NSubbands; b++) { |
||||||
|
CSubband& sb = m_subband[l][b]; |
||||||
|
sb.SetNTiles(nTiles); // must be called before TilePosition()
|
||||||
|
sb.TilePosition(indices.left, indices.top, aroi.left, aroi.top, w, h); |
||||||
|
sb.TilePosition(indices.right - 1, indices.bottom - 1, aroi.right, aroi.bottom, w, h); |
||||||
|
aroi.right += w; |
||||||
|
aroi.bottom += h; |
||||||
|
sb.SetAlignedROI(aroi); |
||||||
|
} |
||||||
|
|
||||||
|
// use aligned ROI of LL subband for next level
|
||||||
|
roi.left = alignedROI.left >> 1; |
||||||
|
roi.top = alignedROI.top >> 1; |
||||||
|
roi.right = (alignedROI.right + 1) >> 1; |
||||||
|
roi.bottom = (alignedROI.bottom + 1) >> 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#endif // __PGFROISUPPORT__
|
@ -0,0 +1,163 @@ |
|||||||
|
/*
|
||||||
|
* The Progressive Graphics File; http://www.libpgf.org
|
||||||
|
*
|
||||||
|
* $Date: 2006-05-18 16:03:32 +0200 (Do, 18 Mai 2006) $ |
||||||
|
* $Revision: 194 $ |
||||||
|
*
|
||||||
|
* This file Copyright (C) 2006 xeraina GmbH, Switzerland |
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE |
||||||
|
* as published by the Free Software Foundation; either version 2.1 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||||
|
*/ |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// @file WaveletTransform.h
|
||||||
|
/// @brief PGF wavelet transform class
|
||||||
|
/// @author C. Stamm
|
||||||
|
|
||||||
|
#ifndef PGF_WAVELETTRANSFORM_H |
||||||
|
#define PGF_WAVELETTRANSFORM_H |
||||||
|
|
||||||
|
#if defined(__GNUC__) |
||||||
|
#pragma GCC diagnostic push |
||||||
|
#pragma GCC diagnostic ignored "-Wignored-qualifiers" |
||||||
|
#endif |
||||||
|
|
||||||
|
#if defined(__APPLE__) |
||||||
|
#pragma clang diagnostic push |
||||||
|
#pragma clang diagnostic ignored "-Wignored-qualifiers" |
||||||
|
#endif |
||||||
|
|
||||||
|
#include "PGFtypes.h" |
||||||
|
#include "Subband.h" |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// Constants
|
||||||
|
const UINT32 FilterSizeL = 5; ///< number of coefficients of the low pass filter
|
||||||
|
const UINT32 FilterSizeH = 3; ///< number of coefficients of the high pass filter
|
||||||
|
const UINT32 FilterSize = __max(FilterSizeL, FilterSizeH); |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// PGF ROI and tile support. This is a helper class for CWaveletTransform.
|
||||||
|
/// @author C. Stamm
|
||||||
|
/// @brief ROI indices
|
||||||
|
class CRoiIndices { |
||||||
|
}; |
||||||
|
#endif //__PGFROISUPPORT__
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// PGF wavelet transform class.
|
||||||
|
/// @author C. Stamm, R. Spuler
|
||||||
|
/// @brief PGF wavelet transform
|
||||||
|
class CWaveletTransform { |
||||||
|
friend class CSubband; |
||||||
|
|
||||||
|
public: |
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Constructor: Constructs a wavelet transform pyramid of given size and levels.
|
||||||
|
/// @param width The width of the original image (at level 0) in pixels
|
||||||
|
/// @param height The height of the original image (at level 0) in pixels
|
||||||
|
/// @param levels The number of levels (>= 0)
|
||||||
|
/// @param data Input data of subband LL at level 0
|
||||||
|
CWaveletTransform(UINT32 width, UINT32 height, int levels, DataT* data = nullptr); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Destructor
|
||||||
|
~CWaveletTransform() { Destroy(); } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Compute fast forward wavelet transform of LL subband at given level and
|
||||||
|
/// stores result in all 4 subbands of level + 1.
|
||||||
|
/// @param level A wavelet transform pyramid level (>= 0 && < Levels())
|
||||||
|
/// @param quant A quantization value (linear scalar quantization)
|
||||||
|
/// @return error in case of a memory allocation problem
|
||||||
|
OSError ForwardTransform(int level, int quant); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Compute fast inverse wavelet transform of all 4 subbands of given level and
|
||||||
|
/// stores result in LL subband of level - 1.
|
||||||
|
/// @param level A wavelet transform pyramid level (> 0 && <= Levels())
|
||||||
|
/// @param width A pointer to the returned width of subband LL (in pixels)
|
||||||
|
/// @param height A pointer to the returned height of subband LL (in pixels)
|
||||||
|
/// @param data A pointer to the returned array of image data
|
||||||
|
/// @return error in case of a memory allocation problem
|
||||||
|
OSError InverseTransform(int level, UINT32* width, UINT32* height, DataT** data); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Get pointer to one of the 4 subband at a given level.
|
||||||
|
/// @param level A wavelet transform pyramid level (>= 0 && <= Levels())
|
||||||
|
/// @param orientation A quarter of the subband (LL, LH, HL, HH)
|
||||||
|
CSubband* GetSubband(int level, Orientation orientation) { |
||||||
|
ASSERT(level >= 0 && level < m_nLevels); |
||||||
|
return &m_subband[level][orientation]; |
||||||
|
} |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Compute and store ROIs for nLevels
|
||||||
|
/// @param rect rectangular region of interest (ROI) at level 0
|
||||||
|
void SetROI(PGFRect rect); |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Checks the relevance of a given tile at given level.
|
||||||
|
/// @param level A valid subband level.
|
||||||
|
/// @param tileX x-index of the given tile
|
||||||
|
/// @param tileY y-index of the given tile
|
||||||
|
const bool TileIsRelevant(int level, UINT32 tileX, UINT32 tileY) const { ASSERT(m_indices); ASSERT(level >= 0 && level < m_nLevels); return m_indices[level].IsInside(tileX, tileY); } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Get number of tiles in x- or y-direction at given level.
|
||||||
|
/// This number is independent of the given ROI.
|
||||||
|
/// @param level A valid subband level.
|
||||||
|
UINT32 GetNofTiles(int level) const { ASSERT(level >= 0 && level < m_nLevels); return 1 << (m_nLevels - level - 1); } |
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
/// Return ROI at given level.
|
||||||
|
/// @param level A valid subband level.
|
||||||
|
const PGFRect& GetAlignedROI(int level) const { return m_subband[level][LL].GetAlignedROI(); } |
||||||
|
|
||||||
|
#endif // __PGFROISUPPORT__
|
||||||
|
|
||||||
|
private: |
||||||
|
void Destroy() {
|
||||||
|
delete[] m_subband; m_subband = nullptr; |
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
delete[] m_indices; m_indices = nullptr; |
||||||
|
#endif |
||||||
|
} |
||||||
|
void InitSubbands(UINT32 width, UINT32 height, DataT* data); |
||||||
|
void ForwardRow(DataT* buff, UINT32 width); |
||||||
|
void InverseRow(DataT* buff, UINT32 width); |
||||||
|
void InterleavedToSubbands(int destLevel, DataT* loRow, DataT* hiRow, UINT32 width); |
||||||
|
void SubbandsToInterleaved(int srcLevel, DataT* loRow, DataT* hiRow, UINT32 width); |
||||||
|
|
||||||
|
#ifdef __PGFROISUPPORT__ |
||||||
|
PGFRect *m_indices; ///< array of length m_nLevels of tile indices
|
||||||
|
#endif //__PGFROISUPPORT__
|
||||||
|
|
||||||
|
int m_nLevels; ///< number of LL levels: one more than header.nLevels in PGFimage
|
||||||
|
CSubband (*m_subband)[NSubbands]; ///< quadtree of subbands: LL HL LH HH
|
||||||
|
}; |
||||||
|
|
||||||
|
#if defined(__GNUC__) |
||||||
|
#pragma GCC diagnostic pop |
||||||
|
#endif |
||||||
|
|
||||||
|
#if defined(__APPLE__) |
||||||
|
#pragma clang diagnostic pop |
||||||
|
#endif |
||||||
|
|
||||||
|
#endif //PGF_WAVELETTRANSFORM_H
|
@ -0,0 +1,471 @@ |
|||||||
|
/* ============================================================
|
||||||
|
* |
||||||
|
* This file is a part of digiKam project |
||||||
|
* https://www.digikam.org
|
||||||
|
* |
||||||
|
* Date : 2009-05-29 |
||||||
|
* Description : static helper methods for PGF image format. |
||||||
|
* |
||||||
|
* Copyright (C) 2009-2019 by Gilles Caulier <caulier dot gilles at gmail dot com> |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it |
||||||
|
* and/or modify it under the terms of the GNU General |
||||||
|
* Public License as published by the Free Software Foundation; |
||||||
|
* either version 2, or (at your option) |
||||||
|
* any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* ============================================================ */ |
||||||
|
|
||||||
|
#include "pgfutils.h" |
||||||
|
|
||||||
|
// C Ansi includes
|
||||||
|
|
||||||
|
extern "C" |
||||||
|
{ |
||||||
|
#include <unistd.h> |
||||||
|
#include <sys/types.h> |
||||||
|
#include <sys/stat.h> |
||||||
|
#include <fcntl.h> |
||||||
|
} |
||||||
|
|
||||||
|
#include <iostream> |
||||||
|
|
||||||
|
// Qt includes
|
||||||
|
|
||||||
|
#include <QImage> |
||||||
|
#include <QByteArray> |
||||||
|
#include <QFile> |
||||||
|
#include <qplatformdefs.h> |
||||||
|
|
||||||
|
// Windows includes
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN32 |
||||||
|
# include <windows.h> |
||||||
|
#endif |
||||||
|
|
||||||
|
// LibPGF includes
|
||||||
|
|
||||||
|
#if defined(Q_CC_CLANG) |
||||||
|
# pragma clang diagnostic push |
||||||
|
# pragma clang diagnostic ignored "-Wkeyword-macro" |
||||||
|
#endif |
||||||
|
|
||||||
|
#include <PGFimage.h> |
||||||
|
|
||||||
|
#if defined(Q_CC_CLANG) |
||||||
|
# pragma clang diagnostic pop |
||||||
|
#endif |
||||||
|
|
||||||
|
// Private method
|
||||||
|
bool writePGFImageDataToStream(const QImage& image, |
||||||
|
CPGFStream& stream, |
||||||
|
int quality, |
||||||
|
UINT32& nWrittenBytes, |
||||||
|
bool verbose); |
||||||
|
|
||||||
|
bool readPGFImageData(const QByteArray& data, |
||||||
|
QImage& img, |
||||||
|
bool verbose) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
if (data.isEmpty()) |
||||||
|
{ |
||||||
|
std::cout << "PGFUtils: PGF image data to decode : size is null"; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
CPGFMemoryStream stream((UINT8*)data.data(), (size_t)data.size()); |
||||||
|
|
||||||
|
if (verbose) |
||||||
|
std::cout << "PGFUtils: image data stream size is : " << stream.GetSize(); |
||||||
|
|
||||||
|
CPGFImage pgfImg; |
||||||
|
// NOTE: see bug #273765 : Loading PGF thumbs with OpenMP support through a separated thread do not work properly with libppgf 6.11.24
|
||||||
|
pgfImg.ConfigureDecoder(false); |
||||||
|
|
||||||
|
pgfImg.Open(&stream); |
||||||
|
|
||||||
|
if (verbose) |
||||||
|
std::cout << "PGFUtils: PGF image is open"; |
||||||
|
|
||||||
|
if (pgfImg.Channels() != 4) |
||||||
|
{ |
||||||
|
std::cout << "PGFUtils: PGF channels not supported"; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
img = QImage(pgfImg.Width(), pgfImg.Height(), QImage::Format_ARGB32); |
||||||
|
pgfImg.Read(); |
||||||
|
|
||||||
|
if (verbose) |
||||||
|
std::cout << "PGFUtils: PGF image is read"; |
||||||
|
|
||||||
|
if (QSysInfo::ByteOrder == QSysInfo::BigEndian) |
||||||
|
{ |
||||||
|
int map[] = {3, 2, 1, 0}; |
||||||
|
pgfImg.GetBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
int map[] = {0, 1, 2, 3}; |
||||||
|
pgfImg.GetBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map); |
||||||
|
} |
||||||
|
|
||||||
|
if (verbose) |
||||||
|
std::cout << "PGFUtils: PGF image is decoded"; |
||||||
|
} |
||||||
|
catch (IOException& e) |
||||||
|
{ |
||||||
|
int err = e.error; |
||||||
|
|
||||||
|
if (err >= AppError) |
||||||
|
{ |
||||||
|
err -= AppError; |
||||||
|
} |
||||||
|
|
||||||
|
std::cout << "PGFUtils: Error running libpgf (" << err << ")!"; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
bool writePGFImageFile(const QImage& image, |
||||||
|
const QString& filePath, |
||||||
|
int quality, |
||||||
|
bool verbose) |
||||||
|
{ |
||||||
|
#ifdef Q_OS_WIN32 |
||||||
|
#ifdef UNICODE |
||||||
|
HANDLE fd = CreateFile((LPCWSTR)(QFile::encodeName(filePath).constData()), GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); |
||||||
|
#else |
||||||
|
HANDLE fd = CreateFile(QFile::encodeName(filePath).constData(), GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); |
||||||
|
#endif |
||||||
|
|
||||||
|
if (fd == INVALID_HANDLE_VALUE) |
||||||
|
{ |
||||||
|
qCDebug(DIGIKAM_GENERAL_LOG) << "PGFUtils: Error: Could not open destination file."; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
#elif defined(__POSIX__) |
||||||
|
int fd = QT_OPEN(QFile::encodeName(filePath).constData(), |
||||||
|
O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
||||||
|
|
||||||
|
if (fd == -1) |
||||||
|
{ |
||||||
|
std::cout << "PGFUtils: Error: Could not open destination file."; |
||||||
|
return false; |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
CPGFFileStream stream(fd); |
||||||
|
UINT32 nWrittenBytes = 0; |
||||||
|
bool ret = writePGFImageDataToStream(image, stream, quality, nWrittenBytes, verbose); |
||||||
|
|
||||||
|
if (!nWrittenBytes) |
||||||
|
{ |
||||||
|
std::cout << "PGFUtils: Written PGF file : data size is null"; |
||||||
|
ret = false; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
if (verbose) |
||||||
|
std::cout << "PGFUtils: file size written : " << nWrittenBytes; |
||||||
|
} |
||||||
|
|
||||||
|
#ifdef Q_OS_WIN32 |
||||||
|
CloseHandle(fd); |
||||||
|
#else |
||||||
|
close(fd); |
||||||
|
#endif |
||||||
|
|
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
bool writePGFImageData(const QImage& image, QByteArray& data, int quality, bool verbose) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
// We will use uncompressed image bytes size to allocate PGF stream in memory. In all case, due to PGF compression ratio,
|
||||||
|
// PGF data will be so far lesser than image raw size.
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) |
||||||
|
int rawSize = image.sizeInBytes(); |
||||||
|
#else |
||||||
|
int rawSize = image.byteCount(); |
||||||
|
#endif |
||||||
|
|
||||||
|
CPGFMemoryStream stream(rawSize); |
||||||
|
|
||||||
|
if (verbose) |
||||||
|
std::cout << "PGFUtils: PGF stream memory allocation in bytes: " << rawSize; |
||||||
|
|
||||||
|
UINT32 nWrittenBytes = 0; |
||||||
|
bool ret = writePGFImageDataToStream(image, stream, quality, nWrittenBytes, verbose); |
||||||
|
int pgfsize = |
||||||
|
#ifdef PGFCodecVersionID |
||||||
|
# if PGFCodecVersionID == 0x061224 |
||||||
|
// Wrap around libpgf 6.12.24 about CPGFMemoryStream bytes size generated to make PGF file data.
|
||||||
|
// It miss 16 bytes at end. This solution fix the problem. Problem have been fixed in 6.12.27.
|
||||||
|
nWrittenBytes + 16; |
||||||
|
# else |
||||||
|
nWrittenBytes; |
||||||
|
# endif |
||||||
|
#else |
||||||
|
nWrittenBytes; |
||||||
|
#endif |
||||||
|
|
||||||
|
data = QByteArray((const char*)stream.GetBuffer(), pgfsize); |
||||||
|
|
||||||
|
if (!pgfsize) |
||||||
|
{ |
||||||
|
std::cout << "PGFUtils: Encoded PGF image : data size is null"; |
||||||
|
ret = false; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
if (verbose) |
||||||
|
std::cout << "PGFUtils: data size written : " << pgfsize; |
||||||
|
} |
||||||
|
|
||||||
|
return ret; |
||||||
|
} |
||||||
|
catch (IOException& e) |
||||||
|
{ |
||||||
|
int err = e.error; |
||||||
|
|
||||||
|
if (err >= AppError) |
||||||
|
{ |
||||||
|
err -= AppError; |
||||||
|
} |
||||||
|
|
||||||
|
std::cout << "PGFUtils: Error running libpgf (" << err << ")!"; |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool writePGFImageDataToStream(const QImage& image, |
||||||
|
CPGFStream& stream, |
||||||
|
int quality, |
||||||
|
UINT32& nWrittenBytes, |
||||||
|
bool verbose) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
if (image.isNull()) |
||||||
|
{ |
||||||
|
std::cout << "PGFUtils: Thumb image is null"; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
QImage img; |
||||||
|
|
||||||
|
// Convert image with Alpha channel.
|
||||||
|
if (image.format() != QImage::Format_ARGB32) |
||||||
|
{ |
||||||
|
img = image.convertToFormat(QImage::Format_ARGB32); |
||||||
|
|
||||||
|
if (verbose) |
||||||
|
std::cout << "PGFUtils: RGB => ARGB"; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
img = image; |
||||||
|
} |
||||||
|
|
||||||
|
CPGFImage pgfImg; |
||||||
|
PGFHeader header; |
||||||
|
header.width = img.width(); |
||||||
|
header.height = img.height(); |
||||||
|
header.nLevels = 0; // Auto.
|
||||||
|
header.quality = quality; |
||||||
|
header.bpp = img.depth(); |
||||||
|
header.channels = 4; |
||||||
|
header.mode = ImageModeRGBA; |
||||||
|
header.usedBitsPerChannel = 0; // Auto
|
||||||
|
|
||||||
|
#ifdef PGFCodecVersionID |
||||||
|
# if PGFCodecVersionID < 0x061142 |
||||||
|
header.background.rgbtBlue = 0; |
||||||
|
header.background.rgbtGreen = 0; |
||||||
|
header.background.rgbtRed = 0; |
||||||
|
# endif |
||||||
|
#endif |
||||||
|
pgfImg.SetHeader(header); |
||||||
|
|
||||||
|
// NOTE: see bug #273765 : Loading PGF thumbs with OpenMP support through a separated thread do not work properly with libppgf 6.11.24
|
||||||
|
pgfImg.ConfigureEncoder(false); |
||||||
|
|
||||||
|
if (verbose) |
||||||
|
{ |
||||||
|
std::cout << "PGFUtils: PGF image settings:"; |
||||||
|
std::cout << "PGFUtils: width: " << header.width; |
||||||
|
std::cout << "PGFUtils: height: " << header.height; |
||||||
|
std::cout << "PGFUtils: nLevels: " << header.nLevels; |
||||||
|
std::cout << "PGFUtils: quality: " << header.quality; |
||||||
|
std::cout << "PGFUtils: bpp: " << header.bpp; |
||||||
|
std::cout << "PGFUtils: channels: " << header.channels; |
||||||
|
std::cout << "PGFUtils: mode: " << header.mode; |
||||||
|
std::cout << "PGFUtils: usedBitsPerChannel: " << header.usedBitsPerChannel; |
||||||
|
} |
||||||
|
|
||||||
|
if (QSysInfo::ByteOrder == QSysInfo::BigEndian) |
||||||
|
{ |
||||||
|
int map[] = {3, 2, 1, 0}; |
||||||
|
pgfImg.ImportBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
int map[] = {0, 1, 2, 3}; |
||||||
|
pgfImg.ImportBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map); |
||||||
|
} |
||||||
|
|
||||||
|
nWrittenBytes = 0; |
||||||
|
|
||||||
|
#ifdef PGFCodecVersionID |
||||||
|
# if PGFCodecVersionID >= 0x061124 |
||||||
|
pgfImg.Write(&stream, &nWrittenBytes); |
||||||
|
# else |
||||||
|
pgfImg.Write(&stream, 0, 0, &nWrittenBytes); |
||||||
|
# endif |
||||||
|
#else |
||||||
|
pgfImg.Write(&stream, 0, 0, &nWrittenBytes); |
||||||
|
#endif |
||||||
|
|
||||||
|
} |
||||||
|
catch (IOException& e) |
||||||
|
{ |
||||||
|
int err = e.error; |
||||||
|
|
||||||
|
if (err >= AppError) |
||||||
|
{ |
||||||
|
err -= AppError; |
||||||
|
} |
||||||
|
|
||||||
|
std::cout << "PGFUtils: Error running libpgf (" << err << ")!"; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
bool loadPGFScaled(QImage& img, const QString& path, int maximumSize) |
||||||
|
{ |
||||||
|
FILE* const file = fopen(QFile::encodeName(path).constData(), "rb"); |
||||||
|
|
||||||
|
if (!file) |
||||||
|
{ |
||||||
|
std::cout << "PGFUtils: Error: Could not open source file."; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
unsigned char header[3]; |
||||||
|
|
||||||
|
if (fread(&header, 3, 1, file) != 1) |
||||||
|
{ |
||||||
|
fclose(file); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
unsigned char pgfID[3] = { 0x50, 0x47, 0x46 }; |
||||||
|
|
||||||
|
if (memcmp(&header[0], &pgfID, 3) != 0) |
||||||
|
{ |
||||||
|
// not a PGF file
|
||||||
|
fclose(file); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
fclose(file); |
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
// Initialize PGF API.
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN32 |
||||||
|
#ifdef UNICODE |
||||||
|
HANDLE fd = CreateFile((LPCWSTR)(QFile::encodeName(path).constData()), GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); |
||||||
|
#else |
||||||
|
HANDLE fd = CreateFile(QFile::encodeName(path).constData(), GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); |
||||||
|
#endif |
||||||
|
|
||||||
|
if (fd == INVALID_HANDLE_VALUE) |
||||||
|
{ |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
#else |
||||||
|
int fd = QT_OPEN(QFile::encodeName(path).constData(), O_RDONLY); |
||||||
|
|
||||||
|
if (fd == -1) |
||||||
|
{ |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
#endif |
||||||
|
|
||||||
|
try |
||||||
|
{ |
||||||
|
CPGFFileStream stream(fd); |
||||||
|
CPGFImage pgf; |
||||||
|
pgf.Open(&stream); |
||||||
|
|
||||||
|
// Try to find the right PGF level to get reduced image accordingly
|
||||||
|
// with preview size wanted.
|
||||||
|
int i = 0; |
||||||
|
|
||||||
|
if (pgf.Levels() > 0) |
||||||
|
{ |
||||||
|
for (i = pgf.Levels()-1 ; i >= 0 ; --i) |
||||||
|
{ |
||||||
|
if (qMin((int)pgf.Width(i), (int)pgf.Height(i)) >= maximumSize) |
||||||
|
{ |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (i < 0) |
||||||
|
{ |
||||||
|
i = 0; |
||||||
|
} |
||||||
|
|
||||||
|
pgf.Read(i); // Read PGF image at reduced level i.
|
||||||
|
img = QImage(pgf.Width(i), pgf.Height(i), QImage::Format_RGB32); |
||||||
|
|
||||||
|
if (QSysInfo::ByteOrder == QSysInfo::BigEndian) |
||||||
|
{ |
||||||
|
int map[] = {3, 2, 1, 0}; |
||||||
|
pgf.GetBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
int map[] = {0, 1, 2, 3}; |
||||||
|
pgf.GetBitmap(img.bytesPerLine(), (UINT8*)img.bits(), img.depth(), map); |
||||||
|
} |
||||||
|
} |
||||||
|
catch (IOException& e) |
||||||
|
{ |
||||||
|
int err = e.error; |
||||||
|
|
||||||
|
if (err >= AppError) |
||||||
|
{ |
||||||
|
err -= AppError; |
||||||
|
} |
||||||
|
|
||||||
|
std::cerr << "PGFUtils: Error running libpgf (" << err << ")!"; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
QString libPGFVersion() |
||||||
|
{ |
||||||
|
return (QLatin1String(PGFCodecVersion)); |
||||||
|
} |
@ -0,0 +1,75 @@ |
|||||||
|
/* ============================================================
|
||||||
|
* |
||||||
|
* This file is a part of digiKam project |
||||||
|
* https://www.digikam.org
|
||||||
|
* |
||||||
|
* Date : 2009-05-29 |
||||||
|
* Description : static helper methods for PGF image format. |
||||||
|
* |
||||||
|
* Copyright (C) 2009-2019 by Gilles Caulier <caulier dot gilles at gmail dot com> |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it |
||||||
|
* and/or modify it under the terms of the GNU General |
||||||
|
* Public License as published by the Free Software Foundation; |
||||||
|
* either version 2, or (at your option) |
||||||
|
* any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* ============================================================ */ |
||||||
|
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
// Qt includes
|
||||||
|
#include <QString> |
||||||
|
#include <QImage> |
||||||
|
#include <QByteArray> |
||||||
|
|
||||||
|
/**
|
||||||
|
* PGF image data to QImage using memory stream. |
||||||
|
* NOTE: Only use this method to manage PGF thumbnails stored in database. |
||||||
|
*/ |
||||||
|
bool readPGFImageData(const QByteArray& data, |
||||||
|
QImage& img, |
||||||
|
bool verbose=false); |
||||||
|
|
||||||
|
/**
|
||||||
|
* QImage to PGF image data using memory stream. 'quality' argument set compression ratio: |
||||||
|
* 0 => lossless compression, as PNG. |
||||||
|
* 1 => Not loss less compression, wavelets based... |
||||||
|
* 2 => ... |
||||||
|
* 3 => ... |
||||||
|
* 4 => Same compression ratio near than JPEG quality=85. |
||||||
|
* Image quality is valid for thumbnails. |
||||||
|
* >= 5 => provide artifacts due to down-sampling. Do not use it... |
||||||
|
* NOTE: Only use this method to manage PGF thumbnails stored in database. |
||||||
|
*/ |
||||||
|
bool writePGFImageData(const QImage& image, |
||||||
|
QByteArray& data, |
||||||
|
int quality, |
||||||
|
bool verbose=false); |
||||||
|
|
||||||
|
/**
|
||||||
|
* QImage to PGF image data using file stream. |
||||||
|
* Same arguments than writePGFImageData() excepted 'filePath' |
||||||
|
* which is PGF target file path. |
||||||
|
*/ |
||||||
|
bool writePGFImageFile(const QImage& image, |
||||||
|
const QString& filePath, |
||||||
|
int quality, |
||||||
|
bool verbose=false); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a reduced version of PGF file |
||||||
|
*/ |
||||||
|
bool loadPGFScaled(QImage& img, |
||||||
|
const QString& path, |
||||||
|
int maximumSize); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a libpgf version string |
||||||
|
*/ |
||||||
|
QString libPGFVersion(); |
Loading…
Reference in new issue