From 47d455dd55be855e4cc691c32f687f723d9247ee Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdegraphics@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- .../plugins/djvu/libdjvu/IW44EncodeCodec.cpp | 1797 ++++++++++++++++++++ 1 file changed, 1797 insertions(+) create mode 100644 kviewshell/plugins/djvu/libdjvu/IW44EncodeCodec.cpp (limited to 'kviewshell/plugins/djvu/libdjvu/IW44EncodeCodec.cpp') diff --git a/kviewshell/plugins/djvu/libdjvu/IW44EncodeCodec.cpp b/kviewshell/plugins/djvu/libdjvu/IW44EncodeCodec.cpp new file mode 100644 index 00000000..c63eda7d --- /dev/null +++ b/kviewshell/plugins/djvu/libdjvu/IW44EncodeCodec.cpp @@ -0,0 +1,1797 @@ +//C- -*- C++ -*- +//C- ------------------------------------------------------------------- +//C- DjVuLibre-3.5 +//C- Copyright (c) 2002 Leon Bottou and Yann Le Cun. +//C- Copyright (c) 2001 AT&T +//C- +//C- This software is subject to, and may be distributed under, the +//C- GNU General Public License, Version 2. The license should have +//C- accompanied the software or you may obtain a copy of the license +//C- from the Free Software Foundation at http://www.fsf.org . +//C- +//C- This program is distributed in the hope that it will be useful, +//C- but WITHOUT ANY WARRANTY; without even the implied warranty of +//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//C- GNU General Public License for more details. +//C- +//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library +//C- distributed by Lizardtech Software. On July 19th 2002, Lizardtech +//C- Software authorized us to replace the original DjVu(r) Reference +//C- Library notice by the following text (see doc/lizard2002.djvu): +//C- +//C- ------------------------------------------------------------------ +//C- | DjVu (r) Reference Library (v. 3.5) +//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved. +//C- | The DjVu Reference Library is protected by U.S. Pat. No. +//C- | 6,058,214 and patents pending. +//C- | +//C- | This software is subject to, and may be distributed under, the +//C- | GNU General Public License, Version 2. The license should have +//C- | accompanied the software or you may obtain a copy of the license +//C- | from the Free Software Foundation at http://www.fsf.org . +//C- | +//C- | The computer code originally released by LizardTech under this +//C- | license and unmodified by other parties is deemed "the LIZARDTECH +//C- | ORIGINAL CODE." Subject to any third party intellectual property +//C- | claims, LizardTech grants recipient a worldwide, royalty-free, +//C- | non-exclusive license to make, use, sell, or otherwise dispose of +//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the +//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU +//C- | General Public License. This grant only confers the right to +//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to +//C- | the extent such infringement is reasonably necessary to enable +//C- | recipient to make, have made, practice, sell, or otherwise dispose +//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to +//C- | any greater extent that may be necessary to utilize further +//C- | modifications or combinations. +//C- | +//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY +//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF +//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. +//C- +------------------------------------------------------------------ +// +// $Id: IW44EncodeCodec.cpp,v 1.11 2004/08/06 15:11:29 leonb Exp $ +// $Name: release_3_5_15 $ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#if NEED_GNUG_PRAGMAS +# pragma implementation +#endif + +// - Author: Leon Bottou, 08/1998 +// From: Leon Bottou, 1/31/2002 +// Lizardtech has split this file into a decoder and an encoder. +// Only superficial changes. The meat is mine. + +#define IW44IMAGE_IMPLIMENTATION /* */ + + + +#include "IW44Image.h" +#include "ZPCodec.h" +#include "GBitmap.h" +#include "GPixmap.h" +#include "IFFByteStream.h" +#include "GRect.h" + +#include +#include +#include +#include "MMX.h" +#undef IWTRANSFORM_TIMER +#ifdef IWTRANSFORM_TIMER +#include "GOS.h" +#endif + +#include +#include +#include + +#ifndef NEED_DECODER_ONLY + + +#ifdef HAVE_NAMESPACES +namespace DJVU { +# ifdef NOT_DEFINED // Just to fool emacs c++ mode +} +#endif +#endif + +#define IWALLOCSIZE 4080 +#define IWCODEC_MAJOR 1 +#define IWCODEC_MINOR 2 +#define DECIBEL_PRUNE 5.0 + + +////////////////////////////////////////////////////// +// WAVELET DECOMPOSITION CONSTANTS +////////////////////////////////////////////////////// + +// Parameters for IW44 wavelet. +// - iw_norm: norm of all wavelets (for db estimation) +// - iw_shift: scale applied before decomposition + + +static const float iw_norm[16] = { + 2.627989e+03F, + 1.832893e+02F, 1.832959e+02F, 5.114690e+01F, + 4.583344e+01F, 4.583462e+01F, 1.279225e+01F, + 1.149671e+01F, 1.149712e+01F, 3.218888e+00F, + 2.999281e+00F, 2.999476e+00F, 8.733161e-01F, + 1.074451e+00F, 1.074511e+00F, 4.289318e-01F +}; + +static const int iw_shift = 6; +static const int iw_round = (1<<(iw_shift-1)); + +static const struct { int start; int size; } +bandbuckets[] = +{ + // Code first bucket and number of buckets in each band + { 0, 1 }, // -- band zero contains all lores info + { 1, 1 }, { 2, 1 }, { 3, 1 }, + { 4, 4 }, { 8, 4 }, { 12,4 }, + { 16,16 }, { 32,16 }, { 48,16 }, +}; + + +/** IW44 encoded gray-level image. This class provided functions for managing + a gray level image represented as a collection of IW44 wavelet + coefficients. The coefficients are stored in a memory efficient data + structure. Member function \Ref{get_bitmap} renders an arbitrary segment + of the image into a \Ref{GBitmap}. Member functions \Ref{decode_iff} and + \Ref{encode_iff} read and write DjVu IW44 files (see \Ref{IW44Image.h}). + Both the copy constructor and the copy operator are declared as private + members. It is therefore not possible to make multiple copies of instances + of this class. */ + +class IWBitmap::Encode : public IWBitmap +{ +public: + /// Destructor + virtual ~Encode(void); + /** Null constructor. Constructs an empty IWBitmap object. This object does + not contain anything meaningful. You must call function \Ref{init}, + \Ref{decode_iff} or \Ref{decode_chunk} to populate the wavelet + coefficient data structure. */ + Encode(void); + /** Initializes an IWBitmap with image #bm#. This constructor + performs the wavelet decomposition of image #bm# and records the + corresponding wavelet coefficient. Argument #mask# is an optional + bilevel image specifying the masked pixels (see \Ref{IW44Image.h}). */ + void init(const GBitmap &bm, const GP mask=0); + // CODER + /** Encodes one data chunk into ByteStream #bs#. Parameter #parms# controls + how much data is generated. The chunk data is written to ByteStream + #bs# with no IFF header. Successive calls to #encode_chunk# encode + successive chunks. You must call #close_codec# after encoding the last + chunk of a file. */ + virtual int encode_chunk(GP gbs, const IWEncoderParms &parms); + /** Writes a gray level image into DjVu IW44 file. This function creates a + composite chunk (identifier #FORM:BM44#) composed of #nchunks# chunks + (identifier #BM44#). Data for each chunk is generated with + #encode_chunk# using the corresponding parameters in array #parms#. */ + virtual void encode_iff(IFFByteStream &iff, int nchunks, const IWEncoderParms *parms); + /** Resets the encoder/decoder state. The first call to #decode_chunk# or + #encode_chunk# initializes the coder for encoding or decoding. Function + #close_codec# must be called after processing the last chunk in order to + reset the coder and release the associated memory. */ + virtual void close_codec(void); +protected: + Codec::Encode *ycodec_enc; +}; + +/** IW44 encoded color image. This class provided functions for managing a + color image represented as a collection of IW44 wavelet coefficients. The + coefficients are stored in a memory efficient data structure. Member + function \Ref{get_pixmap} renders an arbitrary segment of the image into a + \Ref{GPixmap}. Member functions \Ref{decode_iff} and \Ref{encode_iff} + read and write DjVu IW44 files (see \Ref{IW44Image.h}). Both the copy + constructor and the copy operator are declared as private members. It is + therefore not possible to make multiple copies of instances of this + class. */ + +class IWPixmap::Encode : public IWPixmap +{ +public: + enum CRCBMode { + CRCBnone=IW44Image::CRCBnone, + CRCBhalf=IW44Image::CRCBhalf, + CRCBnormal=IW44Image::CRCBnormal, + CRCBfull=IW44Image::CRCBfull }; + /// Destructor + virtual ~Encode(void); + /** Null constructor. Constructs an empty IWPixmap object. This object does + not contain anything meaningful. You must call function \Ref{init}, + \Ref{decode_iff} or \Ref{decode_chunk} to populate the wavelet + coefficient data structure. */ + Encode(void); + /** Initializes an IWPixmap with color image #bm#. This constructor + performs the wavelet decomposition of image #bm# and records the + corresponding wavelet coefficient. Argument #mask# is an optional + bilevel image specifying the masked pixels (see \Ref{IW44Image.h}). + Argument #crcbmode# specifies how the chrominance information should be + encoded (see \Ref{CRCBMode}). */ + void init(const GPixmap &bm, const GP mask=0, CRCBMode crcbmode=CRCBnormal); + // CODER + /** Encodes one data chunk into ByteStream #bs#. Parameter #parms# controls + how much data is generated. The chunk data is written to ByteStream + #bs# with no IFF header. Successive calls to #encode_chunk# encode + successive chunks. You must call #close_codec# after encoding the last + chunk of a file. */ + virtual int encode_chunk(GP gbs, const IWEncoderParms &parms); + /** Writes a color image into a DjVu IW44 file. This function creates a + composite chunk (identifier #FORM:PM44#) composed of #nchunks# chunks + (identifier #PM44#). Data for each chunk is generated with + #encode_chunk# using the corresponding parameters in array #parms#. */ + virtual void encode_iff(IFFByteStream &iff, int nchunks, const IWEncoderParms *parms); + /** Resets the encoder/decoder state. The first call to #decode_chunk# or + #encode_chunk# initializes the coder for encoding or decoding. Function + #close_codec# must be called after processing the last chunk in order to + reset the coder and release the associated memory. */ + virtual void close_codec(void); +protected: + Codec::Encode *ycodec_enc, *cbcodec_enc, *crcodec_enc; +}; + +class IW44Image::Map::Encode : public IW44Image::Map // DJVU_CLASS +{ +public: + Encode(const int w, const int h) : Map(w,h) {} + // creation (from image) + void create(const signed char *img8, int imgrowsize, + const signed char *msk8=0, int mskrowsize=0); + // slash resolution + void slashres(int res); +}; + +class IW44Image::Codec::Encode : public IW44Image::Codec +{ +public: + Encode(IW44Image::Map &map); + // Coding + virtual int code_slice(ZPCodec &zp); + float estimate_decibel(float frac); + // Data + void encode_buckets(ZPCodec &zp, int bit, int band, + IW44Image::Block &blk, IW44Image::Block &eblk, int fbucket, int nbucket); + int encode_prepare(int band, int fbucket, int nbucket, IW44Image::Block &blk, IW44Image::Block &eblk); + IW44Image::Map emap; +}; + +IW44Image::Codec::Encode::Encode(IW44Image::Map &map) +: Codec(map), emap(map.iw,map.ih) {} + +////////////////////////////////////////////////////// +/** IW44Image::Transform::Encode +*/ + +class IW44Image::Transform::Encode : IW44Image::Transform +{ + public: + // WAVELET TRANSFORM + /** Forward transform. */ + static void forward(short *p, int w, int h, int rowsize, int begin, int end); + + // COLOR TRANSFORM + /** Extracts Y */ + static void RGB_to_Y(const GPixel *p, int w, int h, int rowsize, + signed char *out, int outrowsize); + /** Extracts Cb */ + static void RGB_to_Cb(const GPixel *p, int w, int h, int rowsize, + signed char *out, int outrowsize); + /** Extracts Cr */ + static void RGB_to_Cr(const GPixel *p, int w, int h, int rowsize, + signed char *out, int outrowsize); +}; + + +////////////////////////////////////////////////////// +// MMX IMPLEMENTATION HELPERS +////////////////////////////////////////////////////// + + +// Note: +// MMX implementation for vertical transforms only. +// Speedup is basically related to faster memory transfer +// The IW44 transform is not CPU bound, it is memory bound. + +#ifdef MMX + +static const short w9[] = {9,9,9,9}; +static const short w1[] = {1,1,1,1}; +static const int d8[] = {8,8}; +static const int d16[] = {16,16}; + + +static inline void +mmx_fv_1 ( short* &q, short* e, int s, int s3 ) +{ + while (q>4); + q++; + } + while (q+3>5); + q ++; + } + while (q+3=3 && y+30) + mmx_fv_1(q, e, s, s3); +#endif + while (q>4); + q += scale; + } + } + else if (y>1); + q += scale; + q1 += scale; + } + } + } + // 2-Update + { + short *q = p-s3; + short *e = q+w; + if (y>=6 && y0) + mmx_fv_2(q, e, s, s3); +#endif + while (q>5); + q += scale; + } + } + else if (y>=3) + { + // Special cases + short *q1 = (y-2=6) + { + while (q>5); + q += scale; + if (q1) q1 += scale; + if (q3) q3 += scale; + } + } + else if (y>=4) + { + while (q>5); + q += scale; + if (q1) q1 += scale; + if (q3) q3 += scale; + } + } + else + { + while (q>5); + q += scale; + if (q1) q1 += scale; + if (q3) q3 += scale; + } + } + } + } + y += 2; + p += s+s; + } +} + +static void +filter_fh(short *p, int w, int h, int rowsize, int scale) +{ + int y = 0; + int s = scale; + int s3 = s+s+s; + rowsize *= scale; + while (y>1); + q[0] = b3; + q += s+s; + } + while (q+s3 < e) + { + // Generic case + a0=a1; + a1=a2; + a2=a3; + a3=q[s3]; + b0=b1; + b1=b2; + b2=b3; + b3 = q[0] - ((((a1+a2)<<3)+(a1+a2)-a0-a3+8) >> 4); + q[0] = b3; + q[-s3] = q[-s3] + ((((b1+b2)<<3)+(b1+b2)-b0-b3+16) >> 5); + q += s+s; + } + while (q < e) + { + // Special case: w-3 <= x < w + a1=a2; + a2=a3; + b0=b1; + b1=b2; + b2=b3; + b3 = q[0] - ((a1+a2+1)>>1); + q[0] = b3; + q[-s3] = q[-s3] + ((((b1+b2)<<3)+(b1+b2)-b0-b3+16) >> 5); + q += s+s; + } + while (q-s3 < e) + { + // Special case w <= x < w+3 + b0=b1; + b1=b2; + b2=b3; + b3=0; + if (q-s3 >= p) + q[-s3] = q[-s3] + ((((b1+b2)<<3)+(b1+b2)-b0-b3+16) >> 5); + q += s+s; + } + y += scale; + p += rowsize; + } +} + + +////////////////////////////////////////////////////// +// WAVELET TRANSFORM +////////////////////////////////////////////////////// + + +//---------------------------------------------------- +// Function for applying bidimensional IW44 between +// scale intervals begin(inclusive) and end(exclusive) + +void +IW44Image::Transform::Encode::forward(short *p, int w, int h, int rowsize, int begin, int end) +{ + + // PREPARATION + filter_begin(w,h); + // LOOP ON SCALES + for (int scale=begin; scaler] + gmul[p2->g] + bmul[p2->b] + 32768; + *out2 = (y>>16) - 128; + } + } +} + +#ifdef min +#undef min +#endif +static inline int min(const int x,const int y) {return (xy)?x:y;} + +/* Extracts Cb */ +void +IW44Image::Transform::Encode::RGB_to_Cb(const GPixel *p, int w, int h, int rowsize, + signed char *out, int outrowsize) +{ + int rmul[256], gmul[256], bmul[256]; + for (int k=0; k<256; k++) + { + rmul[k] = (int)(k*0x10000*rgb_to_ycc[2][0]); + gmul[k] = (int)(k*0x10000*rgb_to_ycc[2][1]); + bmul[k] = (int)(k*0x10000*rgb_to_ycc[2][2]); + } + for (int i=0; ir] + gmul[p2->g] + bmul[p2->b] + 32768; + *out2 = max(-128, min(127, c>>16)); + } + } +} + +/* Extracts Cr */ +void +IW44Image::Transform::Encode::RGB_to_Cr(const GPixel *p, int w, int h, int rowsize, + signed char *out, int outrowsize) +{ + int rmul[256], gmul[256], bmul[256]; + for (int k=0; k<256; k++) + { + rmul[k] = (int)((k*0x10000)*rgb_to_ycc[1][0]); + gmul[k] = (int)((k*0x10000)*rgb_to_ycc[1][1]); + bmul[k] = (int)((k*0x10000)*rgb_to_ycc[1][2]); + } + for (int i=0; ir] + gmul[p2->g] + bmul[p2->b] + 32768; + *out2 = max(-128, min(127, c>>16)); + } + } +} + + +////////////////////////////////////////////////////// +// MASKING DECOMPOSITION +////////////////////////////////////////////////////// + +//---------------------------------------------------- +// Function for applying bidimensional IW44 between +// scale intervals begin(inclusive) and end(exclusive) +// with a MASK bitmap + + +static void +interpolate_mask(short *data16, int w, int h, int rowsize, + const signed char *mask8, int mskrowsize) +{ + int i,j; + // count masked bits + short *count; + GPBuffer gcount(count,w*h); + short *cp = count; + for (i=0; i gsdata(sdata,w*h); + short *p = sdata; + short *q = data16; + for (i=0; ih) + { + istart -= scale; + cpp -= w*scale; + qq -= w*scale; + } + int jstart = j; + if (jstart+split>w) + jstart -= scale; + // compute gray level + for (ii=istart; ii0) + { + npix += cpp[jj]; + gray += cpp[jj] * qq[jj]; + } + else if (ii>=i && jj>=j) + { + gotz = 1; + } + } + // process result + if (npix == 0) + { + // continue to next resolution + again = 1; + cp[j] = 0; + } + else + { + gray = gray / npix; + // check whether initial image require fix + if (gotz) + { + cpp = cp; + qq = p; + for (ii=i; ii>2; + q[j] = gray; + } + } + // double resolution + split = scale; + scale = scale+scale; + } +} + + +static void +forward_mask(short *data16, int w, int h, int rowsize, int begin, int end, + const signed char *mask8, int mskrowsize ) +{ + int i,j; + signed char *m; + short *p; + short *d; + // Allocate buffers + short *sdata; + GPBuffer gsdata(sdata,w*h); + signed char *smask; + GPBuffer gsmask(smask,w*h); + // Copy mask + m = smask; + for (i=0; i=w || m[j+scale])) + m[j] = 1; + else + m[j] = 0; + m = m1 + w*scale; + } + } + // Free buffers +} + +void +IW44Image::Map::Encode::create(const signed char *img8, int imgrowsize, + const signed char *msk8, int mskrowsize ) +{ + int i, j; + // Progress + DJVU_PROGRESS_TASK(transf,"create iw44 map",3); + // Allocate decomposition buffer + short *data16; + GPBuffer gdata16(data16,bw*bh); + // Copy pixels + short *p = data16; + const signed char *row = img8; + for (i=0; iread_liftblock(liftblock, this); + block++; + } + // next row of blocks + p += 32*bw; + } +} + +void +IW44Image::Map::Encode::slashres(int res) +{ + int minbucket = 1; + if (res < 2) + return; + else if (res < 4) + minbucket=16; + else if (res < 8) + minbucket=4; + for (int blockno=0; blockno=thres || (int)(pcoeff[i])<=-thres) + cstatetmp = NEW|UNK; + cstate[i] = cstatetmp; + bstatetmp |= cstatetmp; + } + } + else + { + for (int i=0; i<16; i++) + { + int cstatetmp = UNK; + if (epcoeff[i]) + cstatetmp = ACTIVE; + else if ((int)(pcoeff[i])>=thres || (int)(pcoeff[i])<=-thres) + cstatetmp = NEW|UNK; + cstate[i] = cstatetmp; + bstatetmp |= cstatetmp; + } + } + bucketstate[buckno] = bstatetmp; + bbstate |= bstatetmp; + } + } + else + { + // Band zero ( fbucket==0 implies band==zero and nbucket==1 ) + const short *pcoeff = blk.data(0, &map); + const short *epcoeff = eblk.data(0, &emap); + char *cstate = coeffstate; + for (int i=0; i<16; i++) + { + int thres = quant_lo[i]; + int cstatetmp = cstate[i]; + if (cstatetmp != ZERO) + { + cstatetmp = UNK; + if (epcoeff[i]) + cstatetmp = ACTIVE; + else if ((int)(pcoeff[i])>=thres || (int)(pcoeff[i])<=-thres) + cstatetmp = NEW|UNK; + } + cstate[i] = cstatetmp; + bbstate |= cstatetmp; + } + bucketstate[0] = bbstate; + } + return bbstate; +} + +// encode_buckets +// -- code a sequence of buckets in a given block +void +IW44Image::Codec::Encode::encode_buckets(ZPCodec &zp, int bit, int band, + IW44Image::Block &blk, IW44Image::Block &eblk, + int fbucket, int nbucket) +{ + // compute state of all coefficients in all buckets + int bbstate = encode_prepare(band, fbucket, nbucket, blk, eblk); + + // code root bit + if ((nbucket<16) || (bbstate&ACTIVE)) + { + bbstate |= NEW; + } + else if (bbstate & UNK) + { + zp.encoder( (bbstate&NEW) ? 1 : 0 , ctxRoot); +#ifdef TRACE + DjVuPrintMessage("bbstate[bit=%d,band=%d] = %d\n", bit, band, bbstate); +#endif + } + + // code bucket bits + if (bbstate & NEW) + for (int buckno=0; buckno0) + { + int k = (fbucket+buckno)<<2; + const short *b = eblk.data(k>>4); + if (b) + { + k = k & 0xf; + if (b[k]) + ctx += 1; + if (b[k+1]) + ctx += 1; + if (b[k+2]) + ctx += 1; + if (ctx<3 && b[k+3]) + ctx += 1; + } + } +#endif +#ifndef NOCTX_BUCKET_ACTIVE + if (bbstate & ACTIVE) + ctx |= 4; +#endif + // Code + zp.encoder( (bucketstate[buckno]&NEW) ? 1 : 0, ctxBucket[band][ctx] ); +#ifdef TRACE + DjVuPrintMessage(" bucketstate[bit=%d,band=%d,buck=%d] = %d\n", + bit, band, buckno, bucketstate[buckno] & ~ZERO); +#endif + } + } + + // code new active coefficient (with their sign) + if (bbstate & NEW) + { + int thres = quant_hi[band]; + char *cstate = coeffstate; + for (int buckno=0; buckno=maxgotcha) + ctx = maxgotcha; + else + ctx = gotcha; +#endif +#ifndef NOCTX_ACTIVE + if (bucketstate[buckno] & ACTIVE) + ctx |= 8; +#endif + // Code + zp.encoder( (cstate[i]&NEW) ? 1 : 0, ctxStart[ctx] ); + if (cstate[i] & NEW) + { + // Code sign + zp.IWencoder( (pcoeff[i]<0) ? 1 : 0 ); + // Set encoder state + if (band==0) + thres = quant_lo[i]; + epcoeff[i] = thres + (thres>>1); + } +#ifndef NOCTX_EXPECT + if (cstate[i] & NEW) + gotcha = 0; + else if (gotcha > 0) + gotcha -= 1; +#endif +#ifdef TRACE + DjVuPrintMessage(" coeffstate[bit=%d,band=%d,buck=%d,c=%d] = %d\n", + bit, band, buckno, i, cstate[i]); +#endif + } + } + } + } + + // code mantissa bits + if (bbstate & ACTIVE) + { + int thres = quant_hi[band]; + char *cstate = coeffstate; + for (int buckno=0; buckno= ecoeff) + pix = 1; + // encode second or lesser mantissa bit + if (ecoeff <= 3*thres) + zp.encoder(pix, ctxMant); + else + zp.IWencoder(!!pix); + // adjust epcoeff + epcoeff[i] = ecoeff - (pix ? 0 : thres) + (thres>>1); + } + } + } +} + +// IW44Image::Codec::estimate_decibel +// -- estimate encoding error (after code_slice) in decibels. +float +IW44Image::Codec::Encode::estimate_decibel(float frac) +{ + int i,j; + const float *q; + // Fill norm arrays + float norm_lo[16]; + float norm_hi[10]; + // -- lo coefficients + q = iw_norm; + for (i=j=0; i<4; j++) + norm_lo[i++] = *q++; + for (j=0; j<4; j++) + norm_lo[i++] = *q; + q += 1; + for (j=0; j<4; j++) + norm_lo[i++] = *q; + q += 1; + for (j=0; j<4; j++) + norm_lo[i++] = *q; + q += 1; + // -- hi coefficients + norm_hi[0] = 0; + for (j=1; j<10; j++) + norm_hi[j] = *q++; + // Initialize mse array + float *xmse; + GPBuffer gxmse(xmse,map.nb); + // Compute mse in each block + for (int blockno=0; blocknom ? m : (p<0 ? 0 : p)); + float pivot = 0; + // Partition array + while (n < p) + { + int l = n; + int h = m; + if (xmse[l] > xmse[h]) { float tmp=xmse[l]; xmse[l]=xmse[h]; xmse[h]=tmp; } + pivot = xmse[(l+h)/2]; + if (pivot < xmse[l]) { float tmp=pivot; pivot=xmse[l]; xmse[l]=tmp; } + if (pivot > xmse[h]) { float tmp=pivot; pivot=xmse[h]; xmse[h]=tmp; } + while (l < h) + { + if (xmse[l] > xmse[h]) { float tmp=xmse[l]; xmse[l]=xmse[h]; xmse[h]=tmp; } + while (xmse[l]pivot) h--; + } + if (p>=l) + n = l; + else + m = l-1; + } + // Compute average mse + float mse = 0; + for (i=p; i gbs) +{ + gbs->write8(serial); + gbs->write8(slices); +} + +void +IW44Image::SecondaryHeader::encode(GP gbs) +{ + gbs->write8(major); + gbs->write8(minor); +} + +void +IW44Image::TertiaryHeader::encode(GP gbs) +{ + gbs->write8(xhi); + gbs->write8(xlo); + gbs->write8(yhi); + gbs->write8(ylo); + gbs->write8(crcbdelay); +} + + + +GP +IW44Image::create_encode(const ImageType itype) +{ + switch(itype) + { + case COLOR: + return new IWPixmap::Encode(); + case GRAY: + return new IWBitmap::Encode(); + default: + return 0; + } +} + +GP +IW44Image::create_encode(const GBitmap &bm, const GP mask) +{ + IWBitmap::Encode *bit=new IWBitmap::Encode(); + GP retval=bit; + bit->init(bm, mask); + return retval; +} + + +IWBitmap::Encode::Encode(void) +: IWBitmap(), ycodec_enc(0) +{} + +IWBitmap::Encode::~Encode() +{ + close_codec(); +} + +void +IWBitmap::Encode::init(const GBitmap &bm, const GP gmask) +{ + // Free + close_codec(); + delete ymap; + ymap = 0; + // Init + int i, j; + int w = bm.columns(); + int h = bm.rows(); + int g = bm.get_grays()-1; + signed char *buffer; + GPBuffer gbuffer(buffer,w*h); + // Prepare gray level conversion table + signed char bconv[256]; + for (i=0; i<256; i++) + bconv[i] = max(0,min(255,i*255/g)) - 128; + // Perform decomposition + // Prepare mask information + const signed char *msk8 = 0; + int mskrowsize = 0; + GBitmap *mask=gmask; + if (gmask) + { + msk8 = (const signed char*)((*mask)[0]); + mskrowsize = mask->rowsize(); + } + // Prepare a buffer of signed bytes + for (i=0; icreate(buffer, w, msk8, mskrowsize); +} + +void +IWBitmap::Encode::close_codec(void) +{ + delete ycodec_enc; + ycodec_enc = 0; + IWBitmap::close_codec(); +} + +int +IWBitmap::Encode::encode_chunk(GP gbs, const IWEncoderParms &parm) +{ + // Check + if (parm.slices==0 && parm.bytes==0 && parm.decibels==0) + G_THROW( ERR_MSG("IW44Image.need_stop") ); + if (! ymap) + G_THROW( ERR_MSG("IW44Image.empty_object") ); + // Open codec + if (!ycodec_enc) + { + cslice = cserial = cbytes = 0; + ycodec_enc = new Codec::Encode(*ymap); + } + // Adjust cbytes + cbytes += sizeof(struct IW44Image::PrimaryHeader); + if (cserial == 0) + cbytes += sizeof(struct IW44Image::SecondaryHeader) + sizeof(struct IW44Image::TertiaryHeader); + // Prepare zcoded slices + int flag = 1; + int nslices = 0; + GP gmbs=ByteStream::create(); + ByteStream &mbs=*gmbs; + DJVU_PROGRESS_TASK(chunk,"encode chunk",parm.slices-cslice); + { + float estdb = -1.0; + GP gzp=ZPCodec::create(gmbs, true, true); + ZPCodec &zp=*gzp; + while (flag) + { + if (parm.decibels>0 && estdb>=parm.decibels) + break; + if (parm.bytes>0 && mbs.tell()+cbytes>=parm.bytes) + break; + if (parm.slices>0 && nslices+cslice>=parm.slices) + break; + DJVU_PROGRESS_RUN(chunk, (1+nslices-cslice)|0xf); + flag = ycodec_enc->code_slice(zp); + if (flag && parm.decibels>0.0) + if (ycodec_enc->curband==0 || estdb>=parm.decibels-DECIBEL_PRUNE) + estdb = ycodec_enc->estimate_decibel(db_frac); + nslices++; + } + } + // Write primary header + struct IW44Image::PrimaryHeader primary; + primary.serial = cserial; + primary.slices = nslices; + primary.encode(gbs); + // Write auxilliary headers + if (cserial == 0) + { + struct IW44Image::SecondaryHeader secondary; + secondary.major = IWCODEC_MAJOR + 0x80; + secondary.minor = IWCODEC_MINOR; + secondary.encode(gbs); + struct IW44Image::TertiaryHeader tertiary; + tertiary.xhi = (ymap->iw >> 8) & 0xff; + tertiary.xlo = (ymap->iw >> 0) & 0xff; + tertiary.yhi = (ymap->ih >> 8) & 0xff; + tertiary.ylo = (ymap->ih >> 0) & 0xff; + tertiary.crcbdelay = 0; + tertiary.encode(gbs); + } + // Write slices + mbs.seek(0); + gbs->copy(mbs); + // Return + cbytes += mbs.tell(); + cslice += nslices; + cserial += 1; + return flag; +} + +void +IWBitmap::Encode::encode_iff(IFFByteStream &iff, int nchunks, const IWEncoderParms *parms) +{ + if (ycodec_enc) + G_THROW( ERR_MSG("IW44Image.left_open1") ); + int flag = 1; + iff.put_chunk("FORM:BM44", 1); + DJVU_PROGRESS_TASK(iff,"encode iff chunk",nchunks); + for (int i=0; flag && i +IW44Image::create_encode( + const GPixmap &pm, const GP gmask, CRCBMode crcbmode) +{ + IWPixmap::Encode *pix=new IWPixmap::Encode(); + GP retval=pix; + pix->init(pm, gmask,(IWPixmap::Encode::CRCBMode)crcbmode); + return retval; +} + +IWPixmap::Encode::Encode(void) +: IWPixmap(), ycodec_enc(0), cbcodec_enc(0), crcodec_enc(0) +{} + +IWPixmap::Encode::~Encode() +{ + close_codec(); +} + +void +IWPixmap::Encode::init(const GPixmap &pm, const GP gmask, CRCBMode crcbmode) +{ + /* Free */ + close_codec(); + delete ymap; + delete cbmap; + delete crmap; + ymap = cbmap = crmap = 0; + /* Create */ + int w = pm.columns(); + int h = pm.rows(); + signed char *buffer; + GPBuffer gbuffer(buffer,w*h); + // Create maps + Map::Encode *eymap = new Map::Encode(w,h); + ymap = eymap; + // Handle CRCB mode + switch (crcbmode) + { + case CRCBnone: crcb_half=1; crcb_delay=-1; break; + case CRCBhalf: crcb_half=1; crcb_delay=10; break; + case CRCBnormal: crcb_half=0; crcb_delay=10; break; + case CRCBfull: crcb_half=0; crcb_delay= 0; break; + } + // Prepare mask information + const signed char *msk8 = 0; + int mskrowsize = 0; + GBitmap *mask=gmask; + if (mask) + { + msk8 = (signed char const *)((*mask)[0]); + mskrowsize = mask->rowsize(); + } + // Fill buffer with luminance information + DJVU_PROGRESS_TASK(create,"initialize pixmap",3); + DJVU_PROGRESS_RUN(create,(crcb_delay>=0 ? 1 : 3)); + Transform::Encode::RGB_to_Y(pm[0], w, h, pm.rowsize(), buffer, w); + if (crcb_delay < 0) + { + // Stupid inversion for gray images + signed char *e = buffer + w*h; + for (signed char *b=buffer; bcreate(buffer, w, msk8, mskrowsize); + // Create chrominance maps + if (crcb_delay >= 0) + { + Map::Encode *ecbmap = new Map::Encode(w,h); + cbmap = ecbmap; + Map::Encode *ecrmap = new Map::Encode(w,h); + crmap = ecrmap; + // Process CB information + DJVU_PROGRESS_RUN(create,2); + Transform::Encode::RGB_to_Cb(pm[0], w, h, pm.rowsize(), buffer, w); + ecbmap->create(buffer, w, msk8, mskrowsize); + // Process CR information + DJVU_PROGRESS_RUN(create,3); + Transform::Encode::RGB_to_Cr(pm[0], w, h, pm.rowsize(), buffer, w); + ecrmap->create(buffer, w, msk8, mskrowsize); + // Perform chrominance reduction (CRCBhalf) + if (crcb_half) + { + ecbmap->slashres(2); + ecrmap->slashres(2); + } + } +} + +void +IWPixmap::Encode::encode_iff(IFFByteStream &iff, int nchunks, const IWEncoderParms *parms) +{ + if (ycodec_enc) + G_THROW( ERR_MSG("IW44Image.left_open3") ); + int flag = 1; + iff.put_chunk("FORM:PM44", 1); + DJVU_PROGRESS_TASK(iff,"encode pixmap chunk", nchunks); + for (int i=0; flag && i gbs, const IWEncoderParms &parm) +{ + // Check + if (parm.slices==0 && parm.bytes==0 && parm.decibels==0) + G_THROW( ERR_MSG("IW44Image.need_stop2") ); + if (!ymap) + G_THROW( ERR_MSG("IW44Image.empty_object2") ); + // Open + if (!ycodec_enc) + { + cslice = cserial = cbytes = 0; + ycodec_enc = new Codec::Encode(*ymap); + if (crmap && cbmap) + { + cbcodec_enc = new Codec::Encode(*cbmap); + crcodec_enc = new Codec::Encode(*crmap); + } + } + + // Adjust cbytes + cbytes += sizeof(struct IW44Image::PrimaryHeader); + if (cserial == 0) + cbytes += sizeof(struct IW44Image::SecondaryHeader) + sizeof(struct IW44Image::TertiaryHeader); + // Prepare zcodec slices + int flag = 1; + int nslices = 0; + GP gmbs=ByteStream::create(); + ByteStream &mbs=*gmbs; + DJVU_PROGRESS_TASK(chunk, "encode pixmap chunk", parm.slices-cslice); + { + float estdb = -1.0; + GP gzp=ZPCodec::create(gmbs, true, true); + ZPCodec &zp=*gzp; + while (flag) + { + if (parm.decibels>0 && estdb>=parm.decibels) + break; + if (parm.bytes>0 && mbs.tell()+cbytes>=parm.bytes) + break; + if (parm.slices>0 && nslices+cslice>=parm.slices) + break; + DJVU_PROGRESS_RUN(chunk,(1+nslices-cslice)|0xf); + flag = ycodec_enc->code_slice(zp); + if (flag && parm.decibels>0) + if (ycodec_enc->curband==0 || estdb>=parm.decibels-DECIBEL_PRUNE) + estdb = ycodec_enc->estimate_decibel(db_frac); + if (crcodec_enc && cbcodec_enc && cslice+nslices>=crcb_delay) + { + flag |= cbcodec_enc->code_slice(zp); + flag |= crcodec_enc->code_slice(zp); + } + nslices++; + } + } + // Write primary header + struct IW44Image::PrimaryHeader primary; + primary.serial = cserial; + primary.slices = nslices; + primary.encode(gbs); + // Write secondary header + if (cserial == 0) + { + struct IW44Image::SecondaryHeader secondary; + secondary.major = IWCODEC_MAJOR; + secondary.minor = IWCODEC_MINOR; + if (! (crmap && cbmap)) + secondary.major |= 0x80; + secondary.encode(gbs); + struct IW44Image::TertiaryHeader tertiary; + tertiary.xhi = (ymap->iw >> 8) & 0xff; + tertiary.xlo = (ymap->iw >> 0) & 0xff; + tertiary.yhi = (ymap->ih >> 8) & 0xff; + tertiary.ylo = (ymap->ih >> 0) & 0xff; + tertiary.crcbdelay = (crcb_half ? 0x00 : 0x80); + tertiary.crcbdelay |= (crcb_delay>=0 ? crcb_delay : 0x00); + tertiary.encode(gbs); + } + // Write slices + mbs.seek(0); + gbs->copy(mbs); + // Return + cbytes += mbs.tell(); + cslice += nslices; + cserial += 1; + return flag; +} + +// code_slice +// -- read/write a slice of datafile + +int +IW44Image::Codec::Encode::code_slice(ZPCodec &zp) +{ + // Check that code_slice can still run + if (curbit < 0) + return 0; + // Perform coding + if (! is_null_slice(curbit, curband)) + { + for (int blockno=0; blockno