summaryrefslogtreecommitdiffstats
path: root/kviewshell/plugins/djvu/libdjvu/JB2Image.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kviewshell/plugins/djvu/libdjvu/JB2Image.cpp')
-rw-r--r--kviewshell/plugins/djvu/libdjvu/JB2Image.cpp1427
1 files changed, 1427 insertions, 0 deletions
diff --git a/kviewshell/plugins/djvu/libdjvu/JB2Image.cpp b/kviewshell/plugins/djvu/libdjvu/JB2Image.cpp
new file mode 100644
index 00000000..7aad9261
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/JB2Image.cpp
@@ -0,0 +1,1427 @@
+//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: JB2Image.cpp,v 1.10 2004/04/17 23:56:11 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// From: Leon Bottou, 1/31/2002
+// Lizardtech has split the corresponding cpp file into a decoder and an encoder.
+// Only superficial changes. The meat is mine.
+
+#include "JB2Image.h"
+#include "GThreads.h"
+#include "GRect.h"
+#include "GBitmap.h"
+#include <string.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+////////////////////////////////////////
+//// CLASS JB2Codec::Decode: DECLARATION
+////////////////////////////////////////
+
+// This class is accessed via the decode
+// functions of class JB2Image
+
+
+//**** Class JB2Codec
+// This class implements the JB2 decoder.
+// Contains all contextual information for decoding a JB2Image.
+
+class JB2Dict::JB2Codec::Decode : public JB2Dict::JB2Codec
+{
+public:
+ Decode(void);
+ void init(const GP<ByteStream> &gbs);
+// virtual
+ void code(const GP<JB2Image> &jim);
+ void code(JB2Image *jim) {const GP<JB2Image> gjim(jim);code(gjim);}
+ void code(const GP<JB2Dict> &jim);
+ void code(JB2Dict *jim) {const GP<JB2Dict> gjim(jim);code(gjim);}
+ void set_dict_callback(JB2DecoderCallback *cb, void *arg);
+protected:
+ int CodeNum(const int lo, const int hi, NumContext &ctx);
+
+// virtual
+ bool CodeBit(const bool bit, BitContext &ctx);
+ void code_comment(GUTF8String &comment);
+ void code_record_type(int &rectype);
+ int code_match_index(int &index, JB2Dict &jim);
+ void code_inherited_shape_count(JB2Dict &jim);
+ void code_image_size(JB2Dict &jim);
+ void code_image_size(JB2Image &jim);
+ void code_absolute_location(JB2Blit *jblt, int rows, int columns);
+ void code_absolute_mark_size(GBitmap &bm, int border=0);
+ void code_relative_mark_size(GBitmap &bm, int cw, int ch, int border=0);
+ void code_bitmap_directly(GBitmap &bm,const int dw, int dy,
+ unsigned char *up2, unsigned char *up1, unsigned char *up0 );
+ void code_bitmap_by_cross_coding (GBitmap &bm, GBitmap &cbm,
+ const int xd2c, const int dw, int dy, int cy,
+ unsigned char *up1, unsigned char *up0, unsigned char *xup1,
+ unsigned char *xup0, unsigned char *xdn1 );
+ int get_diff(const int x_diff,NumContext &rel_loc);
+
+private:
+ GP<ZPCodec> gzp;
+ JB2DecoderCallback *cbfunc;
+ void *cbarg;
+};
+
+////////////////////////////////////////
+//// CLASS JB2DICT: IMPLEMENTATION
+////////////////////////////////////////
+
+
+JB2Dict::JB2Dict()
+ : inherited_shapes(0)
+{
+}
+
+void
+JB2Dict::init()
+{
+ inherited_shapes = 0;
+ inherited_dict = 0;
+ shapes.empty();
+}
+
+JB2Shape &
+JB2Dict::get_shape(const int shapeno)
+{
+ JB2Shape *retval;
+ if(shapeno >= inherited_shapes)
+ {
+ retval=&shapes[shapeno - inherited_shapes];
+ }else if(inherited_dict)
+ {
+ retval=&(inherited_dict->get_shape(shapeno));
+ }else
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ return *retval;
+}
+
+const JB2Shape &
+JB2Dict::get_shape(const int shapeno) const
+{
+ const JB2Shape *retval;
+ if(shapeno >= inherited_shapes)
+ {
+ retval=&shapes[shapeno - inherited_shapes];
+ }else if(inherited_dict)
+ {
+ retval=&(inherited_dict->get_shape(shapeno));
+ }else
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ return *retval;
+}
+
+void
+JB2Dict::set_inherited_dict(const GP<JB2Dict> &dict)
+{
+ if (shapes.size() > 0)
+ G_THROW( ERR_MSG("JB2Image.cant_set") );
+ if (inherited_dict)
+ G_THROW( ERR_MSG("JB2Image.cant_change") );
+ inherited_dict = dict;
+ inherited_shapes = dict->get_shape_count();
+ // Make sure that inherited bitmaps are marked as shared
+ for (int i=0; i<inherited_shapes; i++)
+ {
+ JB2Shape &jshp = dict->get_shape(i);
+ if (jshp.bits) jshp.bits->share();
+ }
+}
+
+void
+JB2Dict::compress()
+{
+ for (int i=shapes.lbound(); i<=shapes.hbound(); i++)
+ shapes[i].bits->compress();
+}
+
+unsigned int
+JB2Dict::get_memory_usage() const
+{
+ unsigned int usage = sizeof(JB2Dict);
+ usage += sizeof(JB2Shape) * shapes.size();
+ for (int i=shapes.lbound(); i<=shapes.hbound(); i++)
+ if (shapes[i].bits)
+ usage += shapes[i].bits->get_memory_usage();
+ return usage;
+}
+
+int
+JB2Dict::add_shape(const JB2Shape &shape)
+{
+ if (shape.parent >= get_shape_count())
+ G_THROW( ERR_MSG("JB2Image.bad_parent_shape") );
+ int index = shapes.size();
+ shapes.touch(index);
+ shapes[index] = shape;
+ return index + inherited_shapes;
+}
+
+void
+JB2Dict::decode(const GP<ByteStream> &gbs, JB2DecoderCallback *cb, void *arg)
+{
+ init();
+ JB2Codec::Decode codec;
+ codec.init(gbs);
+ codec.set_dict_callback(cb,arg);
+ codec.code(this);
+}
+
+
+
+////////////////////////////////////////
+//// CLASS JB2IMAGE: IMPLEMENTATION
+////////////////////////////////////////
+
+
+JB2Image::JB2Image(void)
+ : width(0), height(0), reproduce_old_bug(false)
+{
+}
+
+void
+JB2Image::init(void)
+{
+ width = height = 0;
+ blits.empty();
+ JB2Dict::init();
+}
+
+unsigned int
+JB2Image::get_memory_usage() const
+{
+ unsigned int usage = JB2Dict::get_memory_usage();
+ usage += sizeof(JB2Image) - sizeof(JB2Dict);
+ usage += sizeof(JB2Blit) * blits.size();
+ return usage;
+}
+
+void
+JB2Image::set_dimension(int awidth, int aheight)
+{
+ width = awidth;
+ height = aheight;
+}
+
+int
+JB2Image::add_blit(const JB2Blit &blit)
+{
+ if (blit.shapeno >= (unsigned int)get_shape_count())
+ G_THROW( ERR_MSG("JB2Image.bad_shape") );
+ int index = blits.size();
+ blits.touch(index);
+ blits[index] = blit;
+ return index;
+}
+
+GP<GBitmap>
+JB2Image::get_bitmap(int subsample, int align) const
+{
+ if (width==0 || height==0)
+ G_THROW( ERR_MSG("JB2Image.cant_create") );
+ int swidth = (width + subsample - 1) / subsample;
+ int sheight = (height + subsample - 1) / subsample;
+ int border = ((swidth + align - 1) & ~(align - 1)) - swidth;
+ GP<GBitmap> bm = GBitmap::create(sheight, swidth, border);
+ bm->set_grays(1+subsample*subsample);
+ for (int blitno = 0; blitno < get_blit_count(); blitno++)
+ {
+ const JB2Blit *pblit = get_blit(blitno);
+ const JB2Shape &pshape = get_shape(pblit->shapeno);
+ if (pshape.bits)
+ bm->blit(pshape.bits, pblit->left, pblit->bottom, subsample);
+ }
+ return bm;
+}
+
+GP<GBitmap>
+JB2Image::get_bitmap(const GRect &rect, int subsample, int align, int dispy) const
+{
+ if (width==0 || height==0)
+ G_THROW( ERR_MSG("JB2Image.cant_create") );
+ int rxmin = rect.xmin * subsample;
+ int rymin = rect.ymin * subsample;
+ int swidth = rect.width();
+ int sheight = rect.height();
+ int border = ((swidth + align - 1) & ~(align - 1)) - swidth;
+ GP<GBitmap> bm = GBitmap::create(sheight, swidth, border);
+ bm->set_grays(1+subsample*subsample);
+ for (int blitno = 0; blitno < get_blit_count(); blitno++)
+ {
+ const JB2Blit *pblit = get_blit(blitno);
+ const JB2Shape &pshape = get_shape(pblit->shapeno);
+ if (pshape.bits)
+ bm->blit(pshape.bits, pblit->left-rxmin, pblit->bottom-rymin+dispy, subsample);
+ }
+ return bm;
+}
+
+void
+JB2Image::decode(const GP<ByteStream> &gbs, JB2DecoderCallback *cb, void *arg)
+{
+ init();
+ JB2Codec::Decode codec;
+ codec.init(gbs);
+ codec.set_dict_callback(cb,arg);
+ codec.code(this);
+}
+
+
+
+////////////////////////////////////////
+//// CLASS JB2CODEC : IMPLEMENTATION
+////////////////////////////////////////
+
+
+
+#define START_OF_DATA (0)
+#define NEW_MARK (1)
+#define NEW_MARK_LIBRARY_ONLY (2)
+#define NEW_MARK_IMAGE_ONLY (3)
+#define MATCHED_REFINE (4)
+#define MATCHED_REFINE_LIBRARY_ONLY (5)
+#define MATCHED_REFINE_IMAGE_ONLY (6)
+#define MATCHED_COPY (7)
+#define NON_MARK_DATA (8)
+#define REQUIRED_DICT_OR_RESET (9)
+#define PRESERVED_COMMENT (10)
+#define END_OF_DATA (11)
+
+
+
+// STATIC DATA MEMBERS
+
+static const int BIGPOSITIVE = 262142;
+static const int BIGNEGATIVE = -262143;
+static const int CELLCHUNK = 20000;
+static const int CELLEXTRA = 500;
+
+
+// CONSTRUCTOR
+
+JB2Dict::JB2Codec::Decode::Decode(void)
+: JB2Dict::JB2Codec(0), cbfunc(0), cbarg(0) {}
+
+void
+JB2Dict::JB2Codec::Decode::init(const GP<ByteStream> &gbs)
+{
+ gzp=ZPCodec::create(gbs,false,true);
+}
+
+JB2Dict::JB2Codec::JB2Codec(const bool xencoding)
+ : encoding(xencoding),
+ cur_ncell(0),
+ gbitcells(bitcells,CELLCHUNK+CELLEXTRA),
+ gleftcell(leftcell,CELLCHUNK+CELLEXTRA),
+ grightcell(rightcell,CELLCHUNK+CELLEXTRA),
+ refinementp(false),
+ gotstartrecordp(0),
+ dist_comment_byte(0),
+ dist_comment_length(0),
+ dist_record_type(0),
+ dist_match_index(0),
+ dist_refinement_flag(0),
+ abs_loc_x(0),
+ abs_loc_y(0),
+ abs_size_x(0),
+ abs_size_y(0),
+ image_size_dist(0),
+ inherited_shape_count_dist(0),
+ offset_type_dist(0),
+ rel_loc_x_current(0),
+ rel_loc_x_last(0),
+ rel_loc_y_current(0),
+ rel_loc_y_last(0),
+ rel_size_x(0),
+ rel_size_y(0)
+{
+ memset(bitdist, 0, sizeof(bitdist));
+ memset(cbitdist, 0, sizeof(cbitdist));
+ // Initialize numcoder
+ bitcells[0] = 0; // dummy cell
+ leftcell[0] = rightcell[0] = 0;
+ cur_ncell = 1;
+}
+
+JB2Dict::JB2Codec::~JB2Codec() {}
+
+void
+JB2Dict::JB2Codec::reset_numcoder()
+{
+ dist_comment_byte = 0;
+ dist_comment_length = 0;
+ dist_record_type = 0;
+ dist_match_index = 0;
+ abs_loc_x = 0;
+ abs_loc_y = 0;
+ abs_size_x = 0;
+ abs_size_y = 0;
+ image_size_dist = 0;
+ inherited_shape_count_dist = 0;
+ rel_loc_x_current = 0;
+ rel_loc_x_last = 0;
+ rel_loc_y_current = 0;
+ rel_loc_y_last = 0;
+ rel_size_x = 0;
+ rel_size_y = 0;
+ gbitcells.clear();
+ gleftcell.clear();
+ grightcell.clear();
+ cur_ncell = 1;
+}
+
+
+void
+JB2Dict::JB2Codec::Decode::set_dict_callback(JB2DecoderCallback *cb, void *arg)
+{
+ cbfunc = cb;
+ cbarg = arg;
+}
+
+
+// CODE NUMBERS
+
+inline bool
+JB2Dict::JB2Codec::Decode::CodeBit(const bool, BitContext &ctx)
+{
+ return gzp->decoder(ctx)?true:false;
+}
+
+int
+JB2Dict::JB2Codec::Decode::CodeNum(int low, int high, NumContext &ctx)
+{
+ return JB2Codec::CodeNum(low,high,&ctx,0);
+}
+
+int
+JB2Dict::JB2Codec::CodeNum(int low, int high, NumContext *pctx, int v)
+{
+ bool negative=false;
+ int cutoff;
+ // Check
+ if (!pctx || ((int)*pctx >= cur_ncell))
+ G_THROW( ERR_MSG("JB2Image.bad_numcontext") );
+ // Start all phases
+ cutoff = 0;
+ for(int phase=1,range=0xffffffff;range != 1;)
+ {
+ if (! *pctx)
+ {
+ const int max_ncell=gbitcells;
+ if (cur_ncell >= max_ncell)
+ {
+ const int nmax_ncell = max_ncell+CELLCHUNK;
+ gbitcells.resize(nmax_ncell);
+ gleftcell.resize(nmax_ncell);
+ grightcell.resize(nmax_ncell);
+ }
+ *pctx = cur_ncell ++;
+ bitcells[*pctx] = 0;
+ leftcell[*pctx] = rightcell[*pctx] = 0;
+ }
+ // encode
+ const bool decision = encoding
+ ? ((low < cutoff && high >= cutoff)
+ ? CodeBit((v>=cutoff),bitcells[*pctx])
+ : (v >= cutoff))
+ : ((low>=cutoff)||((high>=cutoff)&&CodeBit(false,bitcells[*pctx])));
+ // context for new bit
+ pctx = decision?(&rightcell[*pctx]):(&leftcell[*pctx]);
+ // phase dependent part
+ switch (phase)
+ {
+ case 1:
+ negative = !decision;
+ if (negative)
+ {
+ if (encoding)
+ v = - v - 1;
+ const int temp = - low - 1;
+ low = - high - 1;
+ high = temp;
+ }
+ phase = 2; cutoff = 1;
+ break;
+
+ case 2:
+ if (!decision)
+ {
+ phase = 3;
+ range = (cutoff + 1) / 2;
+ if (range == 1)
+ cutoff = 0;
+ else
+ cutoff -= range / 2;
+ }
+ else
+ {
+ cutoff += cutoff + 1;
+ }
+ break;
+
+ case 3:
+ range /= 2;
+ if (range != 1)
+ {
+ if (!decision)
+ cutoff -= range / 2;
+ else
+ cutoff += range / 2;
+ }
+ else if (!decision)
+ {
+ cutoff --;
+ }
+ break;
+ }
+ }
+ return (negative)?(- cutoff - 1):cutoff;
+}
+
+
+
+// CODE COMMENTS
+
+void
+JB2Dict::JB2Codec::Decode::code_comment(GUTF8String &comment)
+{
+ int size=CodeNum(0, BIGPOSITIVE, dist_comment_length);
+ comment.empty();
+ char *combuf = comment.getbuf(size);
+ for (int i=0; i<size; i++)
+ {
+ combuf[i]=CodeNum(0, 255, dist_comment_byte);
+ }
+ comment.getbuf();
+}
+
+
+// LIBRARY
+
+
+void
+JB2Dict::JB2Codec::init_library(JB2Dict &jim)
+{
+ int nshape = jim.get_inherited_shape_count();
+ shape2lib.resize(0,nshape-1);
+ lib2shape.resize(0,nshape-1);
+ libinfo.resize(0,nshape-1);
+ for (int i=0; i<nshape; i++)
+ {
+ shape2lib[i] = i;
+ lib2shape[i] = i;
+ JB2Shape &jshp = jim.get_shape(i);
+ libinfo[i].compute_bounding_box(*(jshp.bits));
+ }
+}
+
+int
+JB2Dict::JB2Codec::add_library(const int shapeno, JB2Shape &jshp)
+{
+ const int libno = lib2shape.hbound() + 1;
+ lib2shape.touch(libno);
+ lib2shape[libno] = shapeno;
+ shape2lib.touch(shapeno);
+ shape2lib[shapeno] = libno;
+ libinfo.touch(libno);
+ libinfo[libno].compute_bounding_box(*(jshp.bits));
+ return libno;
+}
+
+
+// CODE SIMPLE VALUES
+
+inline void
+JB2Dict::JB2Codec::Decode::code_record_type(int &rectype)
+{
+ rectype=CodeNum( START_OF_DATA, END_OF_DATA, dist_record_type);
+}
+
+int
+JB2Dict::JB2Codec::Decode::code_match_index(int &index, JB2Dict &)
+{
+ int match=CodeNum(0, lib2shape.hbound(), dist_match_index);
+ index = lib2shape[match];
+ return match;
+}
+
+
+// HANDLE SHORT LIST
+
+int
+JB2Dict::JB2Codec::update_short_list(const int v)
+{
+ if (++ short_list_pos == 3)
+ short_list_pos = 0;
+ int * const s = short_list;
+ s[short_list_pos] = v;
+
+ return (s[0] >= s[1])
+ ?((s[0] > s[2])?((s[1] >= s[2])?s[1]:s[2]):s[0])
+ :((s[0] < s[2])?((s[1] >= s[2])?s[2]:s[1]):s[0]);
+}
+
+
+
+// CODE PAIRS
+
+
+void
+JB2Dict::JB2Codec::Decode::code_inherited_shape_count(JB2Dict &jim)
+{
+ int size=CodeNum(0, BIGPOSITIVE, inherited_shape_count_dist);
+ {
+ GP<JB2Dict> dict = jim.get_inherited_dict();
+ if (!dict && size>0)
+ {
+ // Call callback function to obtain dictionary
+ if (cbfunc)
+ dict = (*cbfunc)(cbarg);
+ if (dict)
+ jim.set_inherited_dict(dict);
+ }
+ if (!dict && size>0)
+ G_THROW( ERR_MSG("JB2Image.need_dict") );
+ if (dict && size!=dict->get_shape_count())
+ G_THROW( ERR_MSG("JB2Image.bad_dict") );
+ }
+}
+
+void
+JB2Dict::JB2Codec::Decode::code_image_size(JB2Dict &jim)
+{
+ int w=CodeNum(0, BIGPOSITIVE, image_size_dist);
+ int h=CodeNum(0, BIGPOSITIVE, image_size_dist);
+ if (w || h)
+ G_THROW( ERR_MSG("JB2Image.bad_dict2") );
+ JB2Codec::code_image_size(jim);
+}
+
+void
+JB2Dict::JB2Codec::code_image_size(JB2Dict &)
+{
+ last_left = 1;
+ last_row_left = 0;
+ last_row_bottom = 0;
+ last_right = 0;
+ fill_short_list(last_row_bottom);
+ gotstartrecordp = 1;
+}
+
+void
+JB2Dict::JB2Codec::Decode::code_image_size(JB2Image &jim)
+{
+ image_columns=CodeNum(0, BIGPOSITIVE, image_size_dist);
+ image_rows=CodeNum(0, BIGPOSITIVE, image_size_dist);
+ if (!image_columns || !image_rows)
+ G_THROW( ERR_MSG("JB2Image.zero_dim") );
+ jim.set_dimension(image_columns, image_rows);
+ JB2Codec::code_image_size(jim);
+}
+
+void
+JB2Dict::JB2Codec::code_image_size(JB2Image &)
+{
+ last_left = 1 + image_columns;
+ last_row_left = 0;
+ last_row_bottom = image_rows;
+ last_right = 0;
+ fill_short_list(last_row_bottom);
+ gotstartrecordp = 1;
+}
+
+inline int
+JB2Dict::JB2Codec::Decode::get_diff(int,NumContext &rel_loc)
+{
+ return CodeNum(BIGNEGATIVE, BIGPOSITIVE, rel_loc);
+}
+
+void
+JB2Dict::JB2Codec::code_relative_location(JB2Blit *jblt, int rows, int columns)
+{
+ // Check start record
+ if (!gotstartrecordp)
+ G_THROW( ERR_MSG("JB2Image.no_start") );
+ // Find location
+ int bottom=0, left=0, top=0, right=0;
+ int x_diff, y_diff;
+ if (encoding)
+ {
+ left = jblt->left + 1;
+ bottom = jblt->bottom + 1;
+ right = left + columns - 1;
+ top = bottom + rows - 1;
+ }
+ // Code offset type
+ int new_row=CodeBit((left<last_left), offset_type_dist);
+ if (new_row)
+ {
+ // Begin a new row
+ x_diff=get_diff(left-last_row_left,rel_loc_x_last);
+ y_diff=get_diff(top-last_row_bottom,rel_loc_y_last);
+ if (!encoding)
+ {
+ left = last_row_left + x_diff;
+ top = last_row_bottom + y_diff;
+ right = left + columns - 1;
+ bottom = top - rows + 1;
+ }
+ last_left = last_row_left = left;
+ last_right = right;
+ last_bottom = last_row_bottom = bottom;
+ fill_short_list(bottom);
+ }
+ else
+ {
+ // Same row
+ x_diff=get_diff(left-last_right,rel_loc_x_current);
+ y_diff=get_diff(bottom-last_bottom,rel_loc_y_current);
+ if (!encoding)
+ {
+ left = last_right + x_diff;
+ bottom = last_bottom + y_diff;
+ right = left + columns - 1;
+ top = bottom + rows - 1;
+ }
+ last_left = left;
+ last_right = right;
+ last_bottom = update_short_list(bottom);
+ }
+ // Store in blit record
+ if (!encoding)
+ {
+ jblt->bottom = bottom - 1;
+ jblt->left = left - 1;
+ }
+}
+
+void
+JB2Dict::JB2Codec::Decode::code_absolute_location(JB2Blit *jblt, int rows, int columns)
+{
+ // Check start record
+ if (!gotstartrecordp)
+ G_THROW( ERR_MSG("JB2Image.no_start") );
+ int left=CodeNum(1, image_columns, abs_loc_x);
+ int top=CodeNum(1, image_rows, abs_loc_y);
+ jblt->bottom = top - rows + 1 - 1;
+ jblt->left = left - 1;
+}
+
+void
+JB2Dict::JB2Codec::Decode::code_absolute_mark_size(GBitmap &bm, int border)
+{
+ int xsize=CodeNum(0, BIGPOSITIVE, abs_size_x);
+ int ysize=CodeNum(0, BIGPOSITIVE, abs_size_y);
+ if ((xsize!=(unsigned short)xsize) || (ysize!=(unsigned short)ysize))
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ bm.init(ysize, xsize, border);
+}
+
+void
+JB2Dict::JB2Codec::Decode::code_relative_mark_size(GBitmap &bm, int cw, int ch, int border)
+{
+ int xdiff=CodeNum(BIGNEGATIVE, BIGPOSITIVE, rel_size_x);
+ int ydiff=CodeNum(BIGNEGATIVE, BIGPOSITIVE, rel_size_y);
+ int xsize = cw + xdiff;
+ int ysize = ch + ydiff;
+ if ((xsize!=(unsigned short)xsize) || (ysize!=(unsigned short)ysize))
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ bm.init(ysize, xsize, border);
+}
+
+
+
+
+// CODE BITMAP DIRECTLY
+
+void
+JB2Dict::JB2Codec::code_bitmap_directly (GBitmap &bm)
+{
+ // Make sure bitmap will not be disturbed
+ GMonitorLock lock(bm.monitor());
+ // ensure borders are adequate
+ bm.minborder(3);
+ // initialize row pointers
+ int dy = bm.rows() - 1;
+ code_bitmap_directly(bm,bm.columns(),dy,bm[dy+2],bm[dy+1],bm[dy]);
+}
+
+void
+JB2Dict::JB2Codec::Decode::code_bitmap_directly(
+ GBitmap &bm,const int dw, int dy,
+ unsigned char *up2, unsigned char *up1, unsigned char *up0 )
+{
+ ZPCodec &zp=*gzp;
+ // iterate on rows (decoding)
+ while (dy >= 0)
+ {
+ int context=get_direct_context(up2, up1, up0, 0);
+ for(int dx=0;dx < dw;)
+ {
+ int n = zp.decoder(bitdist[context]);
+ up0[dx++] = n;
+ context=shift_direct_context(context, n, up2, up1, up0, dx);
+ }
+ // next row
+ dy -= 1;
+ up2 = up1;
+ up1 = up0;
+ up0 = bm[dy];
+ }
+#ifndef NDEBUG
+ bm.check_border();
+#endif
+}
+
+
+
+
+
+// CODE BITMAP BY CROSS CODING
+
+void
+JB2Dict::JB2Codec::code_bitmap_by_cross_coding (GBitmap &bm, GP<GBitmap> &cbm, const int libno)
+{
+ // Make sure bitmaps will not be disturbed
+ GP<GBitmap> copycbm=GBitmap::create();
+ if (cbm->monitor())
+ {
+ // Perform a copy when the bitmap is explicitely shared
+ GMonitorLock lock2(cbm->monitor());
+ copycbm->init(*cbm);
+ cbm = copycbm;
+ }
+ GMonitorLock lock1(bm.monitor());
+ // Center bitmaps
+ const int cw = cbm->columns();
+ const int dw = bm.columns();
+ const int dh = bm.rows();
+ const LibRect &l = libinfo[libno];
+ const int xd2c = (dw/2 - dw + 1) - ((l.right - l.left + 1)/2 - l.right);
+ const int yd2c = (dh/2 - dh + 1) - ((l.top - l.bottom + 1)/2 - l.top);
+ // Ensure borders are adequate
+ bm.minborder(2);
+ cbm->minborder(2-xd2c);
+ cbm->minborder(2+dw+xd2c-cw);
+ // Initialize row pointers
+ const int dy = dh - 1;
+ const int cy = dy + yd2c;
+#ifndef NDEBUG
+ bm.check_border();
+ cbm->check_border();
+#endif
+ code_bitmap_by_cross_coding (bm,*cbm, xd2c, dw, dy, cy, bm[dy+1], bm[dy],
+ (*cbm)[cy+1] + xd2c, (*cbm)[cy ] + xd2c, (*cbm)[cy-1] + xd2c);
+}
+
+void
+JB2Dict::JB2Codec::Decode::code_bitmap_by_cross_coding (GBitmap &bm, GBitmap &cbm,
+ const int xd2c, const int dw, int dy, int cy,
+ unsigned char *up1, unsigned char *up0, unsigned char *xup1,
+ unsigned char *xup0, unsigned char *xdn1 )
+{
+ ZPCodec &zp=*gzp;
+ // iterate on rows (decoding)
+ while (dy >= 0)
+ {
+ int context=get_cross_context(
+ up1, up0, xup1, xup0, xdn1, 0);
+ for(int dx=0;dx < dw;)
+ {
+ const int n = zp.decoder(cbitdist[context]);
+ up0[dx++] = n;
+ context=shift_cross_context(context, n,
+ up1, up0, xup1, xup0, xdn1, dx);
+ }
+ // next row
+ up1 = up0;
+ up0 = bm[--dy];
+ xup1 = xup0;
+ xup0 = xdn1;
+ xdn1 = cbm[(--cy)-1] + xd2c;
+#ifndef NDEBUG
+ bm.check_border();
+#endif
+ }
+}
+
+
+
+
+// CODE JB2DICT RECORD
+
+void
+JB2Dict::JB2Codec::code_record(
+ int &rectype, const GP<JB2Dict> &gjim, JB2Shape *xjshp)
+{
+ GP<GBitmap> cbm;
+ GP<GBitmap> bm;
+ int shapeno = -1;
+
+ // Code record type
+ code_record_type(rectype);
+
+ // Pre-coding actions
+ switch(rectype)
+ {
+ case NEW_MARK_LIBRARY_ONLY:
+ case MATCHED_REFINE_LIBRARY_ONLY:
+ {
+ if(!xjshp)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Shape &jshp=*xjshp;
+ if (!encoding)
+ {
+ jshp.bits = GBitmap::create();
+ jshp.parent = -1;
+ }
+ bm = jshp.bits;
+ break;
+ }
+ }
+ // Coding actions
+ switch (rectype)
+ {
+ case START_OF_DATA:
+ {
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Dict &jim=*gjim;
+ code_image_size (jim);
+ code_eventual_lossless_refinement ();
+ if (! encoding)
+ init_library(jim);
+ break;
+ }
+ case NEW_MARK_LIBRARY_ONLY:
+ {
+ code_absolute_mark_size (*bm, 4);
+ code_bitmap_directly (*bm);
+ break;
+ }
+ case MATCHED_REFINE_LIBRARY_ONLY:
+ {
+ if(!xjshp||!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Dict &jim=*gjim;
+ JB2Shape &jshp=*xjshp;
+ int match = code_match_index (jshp.parent, jim);
+ cbm = jim.get_shape(jshp.parent).bits;
+ LibRect &l = libinfo[match];
+ code_relative_mark_size (*bm, l.right-l.left+1, l.top-l.bottom+1, 4);
+ code_bitmap_by_cross_coding (*bm, cbm, jshp.parent);
+ break;
+ }
+ case PRESERVED_COMMENT:
+ {
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Dict &jim=*gjim;
+ code_comment(jim.comment);
+ break;
+ }
+ case REQUIRED_DICT_OR_RESET:
+ {
+ if (! gotstartrecordp)
+ {
+ // Indicates need for a shape dictionary
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ code_inherited_shape_count(*gjim);
+ }else
+ // Reset all numerical contexts to zero
+ reset_numcoder();
+ break;
+ }
+ case END_OF_DATA:
+ {
+ break;
+ }
+ default:
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_type") );
+ }
+ }
+ // Post-coding action
+ if (!encoding)
+ {
+ // add shape to dictionary
+ switch(rectype)
+ {
+ case NEW_MARK_LIBRARY_ONLY:
+ case MATCHED_REFINE_LIBRARY_ONLY:
+ {
+ if(!xjshp||!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Shape &jshp=*xjshp;
+ shapeno = gjim->add_shape(jshp);
+ add_library(shapeno, jshp);
+ break;
+ }
+ }
+ // make sure everything is compacted
+ // decompaction will occur automatically when needed
+ if (bm)
+ bm->compress();
+ }
+}
+
+
+// CODE JB2DICT
+
+void
+JB2Dict::JB2Codec::Decode::code(const GP<JB2Dict> &gjim)
+{
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Dict &jim=*gjim;
+ // -------------------------
+ // THIS IS THE DECODING PART
+ // -------------------------
+ int rectype;
+ JB2Shape tmpshape;
+ do
+ {
+ code_record(rectype, gjim, &tmpshape);
+ }
+ while(rectype != END_OF_DATA);
+ if (!gotstartrecordp)
+ G_THROW( ERR_MSG("JB2Image.no_start") );
+ jim.compress();
+}
+
+
+
+// CODE JB2IMAGE RECORD
+
+void
+JB2Dict::JB2Codec::code_record(
+ int &rectype, const GP<JB2Image> &gjim, JB2Shape *xjshp, JB2Blit *jblt)
+{
+ GP<GBitmap> bm;
+ GP<GBitmap> cbm;
+ int shapeno = -1;
+ int match;
+
+ // Code record type
+ code_record_type(rectype);
+
+ // Pre-coding actions
+ switch(rectype)
+ {
+ case NEW_MARK:
+ case NEW_MARK_LIBRARY_ONLY:
+ case NEW_MARK_IMAGE_ONLY:
+ case MATCHED_REFINE:
+ case MATCHED_REFINE_LIBRARY_ONLY:
+ case MATCHED_REFINE_IMAGE_ONLY:
+ case NON_MARK_DATA:
+ {
+ if(!xjshp)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Shape &jshp=*xjshp;
+ if (!encoding)
+ {
+ jshp.bits = GBitmap::create();
+ jshp.parent = -1;
+ if (rectype == NON_MARK_DATA)
+ jshp.parent = -2;
+ }
+ bm = jshp.bits;
+ break;
+ }
+ }
+ // Coding actions
+ switch (rectype)
+ {
+ case START_OF_DATA:
+ {
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Image &jim=*gjim;
+ code_image_size (jim);
+ code_eventual_lossless_refinement ();
+ if (! encoding)
+ init_library(jim);
+ break;
+ }
+ case NEW_MARK:
+ {
+ code_absolute_mark_size (*bm, 4);
+ code_bitmap_directly (*bm);
+ code_relative_location (jblt, bm->rows(), bm->columns() );
+ break;
+ }
+ case NEW_MARK_LIBRARY_ONLY:
+ {
+ code_absolute_mark_size (*bm, 4);
+ code_bitmap_directly (*bm);
+ break;
+ }
+ case NEW_MARK_IMAGE_ONLY:
+ {
+ code_absolute_mark_size (*bm, 3);
+ code_bitmap_directly (*bm);
+ code_relative_location (jblt, bm->rows(), bm->columns() );
+ break;
+ }
+ case MATCHED_REFINE:
+ {
+ if(!xjshp || !gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Shape &jshp=*xjshp;
+ JB2Image &jim=*gjim;
+ match = code_match_index (jshp.parent, jim);
+ cbm = jim.get_shape(jshp.parent).bits;
+ LibRect &l = libinfo[match];
+ code_relative_mark_size (*bm, l.right-l.left+1, l.top-l.bottom+1, 4);
+ code_bitmap_by_cross_coding (*bm, cbm, match);
+ code_relative_location (jblt, bm->rows(), bm->columns() );
+ break;
+ }
+ case MATCHED_REFINE_LIBRARY_ONLY:
+ {
+ if(!xjshp||!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Image &jim=*gjim;
+ JB2Shape &jshp=*xjshp;
+ match = code_match_index (jshp.parent, jim);
+ cbm = jim.get_shape(jshp.parent).bits;
+ LibRect &l = libinfo[match];
+ code_relative_mark_size (*bm, l.right-l.left+1, l.top-l.bottom+1, 4);
+ break;
+ }
+ case MATCHED_REFINE_IMAGE_ONLY:
+ {
+ if(!xjshp||!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Image &jim=*gjim;
+ JB2Shape &jshp=*xjshp;
+ match = code_match_index (jshp.parent, jim);
+ cbm = jim.get_shape(jshp.parent).bits;
+ LibRect &l = libinfo[match];
+ code_relative_mark_size (*bm, l.right-l.left+1, l.top-l.bottom+1, 4);
+ code_bitmap_by_cross_coding (*bm, cbm, match);
+ code_relative_location (jblt, bm->rows(), bm->columns() );
+ break;
+ }
+ case MATCHED_COPY:
+ {
+ int temp;
+ if (encoding) temp = jblt->shapeno;
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Image &jim=*gjim;
+ match = code_match_index (temp, jim);
+ if (!encoding) jblt->shapeno = temp;
+ bm = jim.get_shape(jblt->shapeno).bits;
+ LibRect &l = libinfo[match];
+ jblt->left += l.left;
+ jblt->bottom += l.bottom;
+ if (jim.reproduce_old_bug)
+ code_relative_location (jblt, bm->rows(), bm->columns() );
+ else
+ code_relative_location (jblt, l.top-l.bottom+1, l.right-l.left+1 );
+ jblt->left -= l.left;
+ jblt->bottom -= l.bottom;
+ break;
+ }
+ case NON_MARK_DATA:
+ {
+ code_absolute_mark_size (*bm, 3);
+ code_bitmap_directly (*bm);
+ code_absolute_location (jblt, bm->rows(), bm->columns() );
+ break;
+ }
+ case PRESERVED_COMMENT:
+ {
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Image &jim=*gjim;
+ code_comment(jim.comment);
+ break;
+ }
+ case REQUIRED_DICT_OR_RESET:
+ {
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Image &jim=*gjim;
+ if (! gotstartrecordp)
+ // Indicates need for a shape dictionary
+ code_inherited_shape_count(jim);
+ else
+ // Reset all numerical contexts to zero
+ reset_numcoder();
+ break;
+ }
+ case END_OF_DATA:
+ {
+ break;
+ }
+ default:
+ {
+ G_THROW( ERR_MSG("JB2Image.unknown_type") );
+ }
+ }
+
+ // Post-coding action
+ if (!encoding)
+ {
+ // add shape to image
+ switch(rectype)
+ {
+ case NEW_MARK:
+ case NEW_MARK_LIBRARY_ONLY:
+ case NEW_MARK_IMAGE_ONLY:
+ case MATCHED_REFINE:
+ case MATCHED_REFINE_LIBRARY_ONLY:
+ case MATCHED_REFINE_IMAGE_ONLY:
+ case NON_MARK_DATA:
+ {
+ if(!xjshp||!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Shape &jshp=*xjshp;
+ shapeno = gjim->add_shape(jshp);
+ shape2lib.touch(shapeno);
+ shape2lib[shapeno] = -1;
+ break;
+ }
+ }
+ // add shape to library
+ switch(rectype)
+ {
+ case NEW_MARK:
+ case NEW_MARK_LIBRARY_ONLY:
+ case MATCHED_REFINE:
+ case MATCHED_REFINE_LIBRARY_ONLY:
+ if(!xjshp)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ add_library(shapeno, *xjshp);
+ break;
+ }
+ // make sure everything is compacted
+ // decompaction will occur automatically on cross-coding bitmaps
+ if (bm)
+ bm->compress();
+ // add blit to image
+ switch (rectype)
+ {
+ case NEW_MARK:
+ case NEW_MARK_IMAGE_ONLY:
+ case MATCHED_REFINE:
+ case MATCHED_REFINE_IMAGE_ONLY:
+ case NON_MARK_DATA:
+ jblt->shapeno = shapeno;
+ case MATCHED_COPY:
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ gjim->add_blit(* jblt);
+ break;
+ }
+ }
+}
+
+
+// CODE JB2IMAGE
+
+void
+JB2Dict::JB2Codec::Decode::code(const GP<JB2Image> &gjim)
+{
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Image &jim=*gjim;
+ // -------------------------
+ // THIS IS THE DECODING PART
+ // -------------------------
+ int rectype;
+ JB2Blit tmpblit;
+ JB2Shape tmpshape;
+ do
+ {
+ code_record(rectype, gjim, &tmpshape, &tmpblit);
+ }
+ while(rectype!=END_OF_DATA);
+ if (!gotstartrecordp)
+ G_THROW( ERR_MSG("JB2Image.no_start") );
+ jim.compress();
+}
+
+
+
+////////////////////////////////////////
+//// HELPERS
+////////////////////////////////////////
+
+void
+JB2Dict::JB2Codec::LibRect::compute_bounding_box(const GBitmap &bm)
+{
+ // First lock the stuff.
+ GMonitorLock lock(bm.monitor());
+ // Get size
+ const int w = bm.columns();
+ const int h = bm.rows();
+ const int s = bm.rowsize();
+ // Right border
+ for(right=w-1;right >= 0;--right)
+ {
+ unsigned char const *p = bm[0] + right;
+ unsigned char const * const pe = p+(s*h);
+ for (;(p<pe)&&(!*p);p+=s)
+ continue;
+ if (p<pe)
+ break;
+ }
+ // Top border
+ for(top=h-1;top >= 0;--top)
+ {
+ unsigned char const *p = bm[top];
+ unsigned char const * const pe = p+w;
+ for (;(p<pe)&&(!*p); ++p)
+ continue;
+ if (p<pe)
+ break;
+ }
+ // Left border
+ for (left=0;left <= right;++left)
+ {
+ unsigned char const *p = bm[0] + left;
+ unsigned char const * const pe=p+(s*h);
+ for (;(p<pe)&&(!*p);p+=s)
+ continue;
+ if (p<pe)
+ break;
+ }
+ // Bottom border
+ for(bottom=0;bottom <= top;++bottom)
+ {
+ unsigned char const *p = bm[bottom];
+ unsigned char const * const pe = p+w;
+ for (;(p<pe)&&(!*p); ++p)
+ continue;
+ if (p<pe)
+ break;
+ }
+}
+
+GP<JB2Dict>
+JB2Dict::create(void)
+{
+ return new JB2Dict();
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif