File indexing completed on 2025-01-19 03:56:09

0001 /*
0002  * The Progressive Graphics File; http://www.libpgf.org
0003  *
0004  * $Date: 2006-06-04 22:05:59 +0200 (So, 04 Jun 2006) $
0005  * $Revision: 229 $
0006  *
0007  * This file Copyright (C) 2006 xeraina GmbH, Switzerland
0008  *
0009  * This program is free software; you can redistribute it and/or
0010  * modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
0011  * as published by the Free Software Foundation; either version 2.1
0012  * of the License, or (at your option) any later version.
0013  *
0014  * This program is distributed in the hope that it will be useful,
0015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0017  * GNU General Public License for more details.
0018  *
0019  * You should have received a copy of the GNU General Public License
0020  * along with this program; if not, write to the Free Software
0021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
0022  */
0023 
0024 //////////////////////////////////////////////////////////////////////
0025 /// @file Encoder.h
0026 /// @brief PGF encoder class
0027 /// @author C. Stamm, R. Spuler
0028 
0029 #ifndef PGF_ENCODER_H
0030 #define PGF_ENCODER_H
0031 
0032 #include "PGFstream.h"
0033 #include "BitStream.h"
0034 #include "Subband.h"
0035 #include "WaveletTransform.h"
0036 
0037 #include "digikam_export.h"
0038 
0039 /////////////////////////////////////////////////////////////////////
0040 // Constants
0041 #define BufferLen           (BufferSize/WordWidth)  ///< number of words per buffer
0042 #define CodeBufferLen       BufferSize              ///< number of words in code buffer (CodeBufferLen > BufferLen)
0043 
0044 /////////////////////////////////////////////////////////////////////
0045 /// PGF encoder class.
0046 /// @author C. Stamm
0047 /// @brief PGF encoder
0048 class DIGIKAM_EXPORT CEncoder {
0049     //////////////////////////////////////////////////////////////////////
0050     /// PGF encoder macro block class.
0051     /// @author C. Stamm, I. Bauersachs
0052     /// @brief A macro block is an encoding unit of fixed size (uncoded)
0053     class CMacroBlock {
0054     public:
0055         //////////////////////////////////////////////////////////////////////
0056         /// Constructor: Initializes new macro block.
0057         /// @param encoder Pointer to outer class.
0058         CMacroBlock(CEncoder *encoder)
0059 #ifdef _MSC_VER
0060 #pragma warning( suppress : 4351 )
0061 #endif
0062         : m_value()
0063         , m_codeBuffer()
0064         , m_header(0)
0065         , m_encoder(encoder)
0066         , m_sigFlagVector()
0067         {
0068             ASSERT(m_encoder);
0069             Init(-1);
0070         }
0071 
0072         //////////////////////////////////////////////////////////////////////
0073         /// Reinitialzes this macro block (allows reusage).
0074         /// @param lastLevelIndex Level length directory index of last encoded level: [0, nLevels)
0075         void Init(int lastLevelIndex) {             // initialize for reusage
0076             m_valuePos = 0;
0077             m_maxAbsValue = 0;
0078             m_codePos = 0;
0079             m_lastLevelIndex = lastLevelIndex;
0080         }
0081 
0082         //////////////////////////////////////////////////////////////////////
0083         /// Encodes this macro block into internal code buffer.
0084         /// Several macro blocks can be encoded in parallel.
0085         /// Call CEncoder::WriteMacroBlock after this method.
0086         void BitplaneEncode();
0087 
0088         DataT   m_value[BufferSize];                ///< input buffer of values with index m_valuePos
0089         UINT32  m_codeBuffer[CodeBufferLen];        ///< output buffer for encoded bitstream
0090         ROIBlockHeader m_header;                    ///< block header
0091         UINT32  m_valuePos;                         ///< current buffer position
0092         UINT32  m_maxAbsValue;                      ///< maximum absolute coefficient in each buffer
0093         UINT32  m_codePos;                          ///< current position in encoded bitstream
0094         int     m_lastLevelIndex;                   ///< index of last encoded level: [0, nLevels); used because a level-end can occur before a buffer is full
0095 
0096     private:
0097         UINT32 RLESigns(UINT32 codePos, UINT32* signBits, UINT32 signLen);
0098         UINT32 DecomposeBitplane(UINT32 bufferSize, UINT32 planeMask, UINT32 codePos, UINT32* sigBits, UINT32* refBits, UINT32* signBits, UINT32& signLen, UINT32& codeLen);
0099         UINT8  NumberOfBitplanes();
0100         bool   GetBitAtPos(UINT32 pos, UINT32 planeMask) const  { return (abs(m_value[pos]) & planeMask) > 0; }
0101 
0102         CEncoder *m_encoder;                        // encoder instance
0103         bool    m_sigFlagVector[BufferSize+1];      // see paper from Malvar, Fast Progressive Wavelet Coder
0104     };
0105 
0106 public:
0107     /////////////////////////////////////////////////////////////////////
0108     /// Write pre-header, header, post-Header, and levelLength.
0109     /// It might throw an IOException.
0110     /// @param stream A PGF stream
0111     /// @param preHeader A already filled in PGF pre-header
0112     /// @param header An already filled in PGF header
0113     /// @param postHeader [in] An already filled in PGF post-header (containing color table, user data, ...)
0114     /// @param userDataPos [out] File position of user data
0115     /// @param useOMP If true, then the encoder will use multi-threading based on openMP
0116     CEncoder(CPGFStream* stream, PGFPreHeader preHeader, PGFHeader header, const PGFPostHeader& postHeader,
0117         UINT64& userDataPos, bool useOMP); // throws IOException
0118 
0119     /////////////////////////////////////////////////////////////////////
0120     /// Destructor
0121     ~CEncoder();
0122 
0123     /////////////////////////////////////////////////////////////////////
0124     /// Encoder favors speed over compression size
0125     void FavorSpeedOverSize() { m_favorSpeed = true; }
0126 
0127     /////////////////////////////////////////////////////////////////////
0128     /// Pad buffer with zeros and encode buffer.
0129     /// It might throw an IOException.
0130     void Flush();
0131 
0132     /////////////////////////////////////////////////////////////////////
0133     /// Increase post-header size and write new size into stream.
0134     /// @param preHeader An already filled in PGF pre-header
0135     /// It might throw an IOException.
0136     void UpdatePostHeaderSize(PGFPreHeader preHeader);
0137 
0138     /////////////////////////////////////////////////////////////////////
0139     /// Create level length data structure and write a place holder into stream.
0140     /// It might throw an IOException.
0141     /// @param levelLength A reference to an integer array, large enough to save the relative file positions of all PGF levels
0142     /// @return number of bytes written into stream
0143     UINT32 WriteLevelLength(UINT32*& levelLength);
0144 
0145     /////////////////////////////////////////////////////////////////////
0146     /// Write new levelLength into stream.
0147     /// It might throw an IOException.
0148     /// @return Written image bytes.
0149     UINT32 UpdateLevelLength();
0150 
0151     /////////////////////////////////////////////////////////////////////
0152     /// Partitions a rectangular region of a given subband.
0153     /// Partitioning scheme: The plane is partitioned in squares of side length LinBlockSize.
0154     /// Write wavelet coefficients from subband into the input buffer of a macro block.
0155     /// It might throw an IOException.
0156     /// @param band A subband
0157     /// @param width The width of the rectangle
0158     /// @param height The height of the rectangle
0159     /// @param startPos The absolute subband position of the top left corner of the rectangular region
0160     /// @param pitch The number of bytes in row of the subband
0161     void Partition(CSubband* band, int width, int height, int startPos, int pitch);
0162 
0163     /////////////////////////////////////////////////////////////////////
0164     /// Informs the encoder about the encoded level.
0165     /// @param currentLevel encoded level [0, nLevels)
0166     void SetEncodedLevel(int currentLevel) { ASSERT(currentLevel >= 0); m_currentBlock->m_lastLevelIndex = m_nLevels - currentLevel - 1; m_forceWriting = true; }
0167 
0168     /////////////////////////////////////////////////////////////////////
0169     /// Write a single value into subband at given position.
0170     /// It might throw an IOException.
0171     /// @param band A subband
0172     /// @param bandPos A valid position in subband band
0173     void WriteValue(CSubband* band, int bandPos);
0174 
0175     /////////////////////////////////////////////////////////////////////
0176     /// Compute stream length of header.
0177     /// @return header length
0178     INT64 ComputeHeaderLength() const { return m_levelLengthPos - m_startPosition; }
0179 
0180     /////////////////////////////////////////////////////////////////////
0181     /// Compute stream length of encoded buffer.
0182     /// @return encoded buffer length
0183     INT64 ComputeBufferLength() const { return m_stream->GetPos() - m_bufferStartPos; }
0184 
0185     /////////////////////////////////////////////////////////////////////
0186     /// Compute file offset between real and expected levelLength position.
0187     /// @return file offset
0188     INT64 ComputeOffset() const { return m_stream->GetPos() - m_levelLengthPos; }
0189 
0190     ////////////////////////////////////////////////////////////////////
0191     /// Resets stream position to beginning of PGF pre-header
0192     void SetStreamPosToStart() { ASSERT(m_stream); m_stream->SetPos(FSFromStart, m_startPosition); }
0193 
0194     /////////////////////////////////////////////////////////////////////
0195     /// Save current stream position as beginning of current level.
0196     void SetBufferStartPos() { m_bufferStartPos = m_stream->GetPos(); }
0197 
0198 #ifdef __PGFROISUPPORT__
0199     /////////////////////////////////////////////////////////////////////
0200     /// Encodes tile buffer and writes it into stream
0201     /// It might throw an IOException.
0202     void EncodeTileBuffer() { ASSERT(m_currentBlock && m_currentBlock->m_valuePos >= 0 && m_currentBlock->m_valuePos <= BufferSize); EncodeBuffer(ROIBlockHeader(m_currentBlock->m_valuePos, true)); }
0203 
0204     /////////////////////////////////////////////////////////////////////
0205     /// Enables region of interest (ROI) status.
0206     void SetROI()                   { m_roi = true; }
0207 #endif
0208 
0209 #ifdef TRACE
0210     void DumpBuffer() const;
0211 #endif
0212 
0213 private:
0214     void EncodeBuffer(ROIBlockHeader h); // throws IOException
0215     void WriteMacroBlock(CMacroBlock* block); // throws IOException
0216 
0217     CPGFStream *m_stream;                       ///< output PMF stream
0218     UINT64  m_startPosition;                    ///< stream position of PGF start (PreHeader)
0219     UINT64  m_levelLengthPos;                   ///< stream position of Metadata
0220     UINT64  m_bufferStartPos;                   ///< stream position of encoded buffer
0221 
0222     CMacroBlock **m_macroBlocks;                ///< array of macroblocks
0223     int     m_macroBlockLen;                    ///< array length
0224     int     m_lastMacroBlock;                   ///< array index of the last created macro block
0225     CMacroBlock *m_currentBlock;                ///< current macro block (used by main thread)
0226 
0227     UINT32* m_levelLength;                      ///< temporary saves the level index
0228     int     m_currLevelIndex;                   ///< counts where (=index) to save next value
0229     UINT8   m_nLevels;                          ///< number of levels
0230     bool    m_favorSpeed;                       ///< favor speed over size
0231     bool    m_forceWriting;                     ///< all macro blocks have to be written into the stream
0232 #ifdef __PGFROISUPPORT__
0233     bool    m_roi;                              ///< true: ensures region of interest (ROI) encoding
0234 #endif
0235 };
0236 
0237 #endif //PGF_ENCODER