1 //C- -*- C++ -*-
2 //C- -------------------------------------------------------------------
3 //C- DjVuLibre-3.5
4 //C- Copyright (c) 2002 Leon Bottou and Yann Le Cun.
5 //C- Copyright (c) 2001 AT&T
6 //C-
7 //C- This software is subject to, and may be distributed under, the
8 //C- GNU General Public License, either Version 2 of the license,
9 //C- or (at your option) any later version. The license should have
10 //C- accompanied the software or you may obtain a copy of the license
11 //C- from the Free Software Foundation at http://www.fsf.org .
12 //C-
13 //C- This program is distributed in the hope that it will be useful,
14 //C- but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 //C- GNU General Public License for more details.
17 //C-
18 //C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library from
19 //C- Lizardtech Software. Lizardtech Software has authorized us to
20 //C- replace the original DjVu(r) Reference Library notice by the following
21 //C- text (see doc/lizard2002.djvu and doc/lizardtech2007.djvu):
22 //C-
23 //C- ------------------------------------------------------------------
24 //C- | DjVu (r) Reference Library (v. 3.5)
25 //C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
26 //C- | The DjVu Reference Library is protected by U.S. Pat. No.
27 //C- | 6,058,214 and patents pending.
28 //C- |
29 //C- | This software is subject to, and may be distributed under, the
30 //C- | GNU General Public License, either Version 2 of the license,
31 //C- | or (at your option) any later version. The license should have
32 //C- | accompanied the software or you may obtain a copy of the license
33 //C- | from the Free Software Foundation at http://www.fsf.org .
34 //C- |
35 //C- | The computer code originally released by LizardTech under this
36 //C- | license and unmodified by other parties is deemed "the LIZARDTECH
37 //C- | ORIGINAL CODE." Subject to any third party intellectual property
38 //C- | claims, LizardTech grants recipient a worldwide, royalty-free,
39 //C- | non-exclusive license to make, use, sell, or otherwise dispose of
40 //C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
41 //C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
42 //C- | General Public License. This grant only confers the right to
43 //C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
44 //C- | the extent such infringement is reasonably necessary to enable
45 //C- | recipient to make, have made, practice, sell, or otherwise dispose
46 //C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
47 //C- | any greater extent that may be necessary to utilize further
48 //C- | modifications or combinations.
49 //C- |
50 //C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
51 //C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
52 //C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
53 //C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
54 //C- +------------------------------------------------------------------
55
56 #ifdef HAVE_CONFIG_H
57 # include "config.h"
58 #endif
59 #if NEED_GNUG_PRAGMAS
60 # pragma implementation
61 #endif
62
63 // From: Leon Bottou, 1/31/2002
64 // Lizardtech has split the corresponding cpp file into a decoder and an encoder.
65 // Only superficial changes. The meat is mine.
66
67 #include "JB2Image.h"
68 #include "GThreads.h"
69 #include "GRect.h"
70 #include "GBitmap.h"
71 #include <string.h>
72
73
74 #ifdef HAVE_NAMESPACES
75 namespace DJVU {
76 # ifdef NOT_DEFINED // Just to fool emacs c++ mode
77 }
78 #endif
79 #endif
80
81 ////////////////////////////////////////
82 //// CLASS JB2Codec::Decode: DECLARATION
83 ////////////////////////////////////////
84
85 // This class is accessed via the decode
86 // functions of class JB2Image
87
88
89 //**** Class JB2Codec
90 // This class implements the JB2 decoder.
91 // Contains all contextual information for decoding a JB2Image.
92
93 class JB2Dict::JB2Codec::Decode : public JB2Dict::JB2Codec
94 {
95 public:
96 Decode(void);
97 void init(const GP<ByteStream> &gbs);
98 // virtual
99 void code(const GP<JB2Image> &jim);
code(JB2Image * jim)100 void code(JB2Image *jim) {const GP<JB2Image> gjim(jim);code(gjim);}
101 void code(const GP<JB2Dict> &jim);
code(JB2Dict * jim)102 void code(JB2Dict *jim) {const GP<JB2Dict> gjim(jim);code(gjim);}
103 void set_dict_callback(JB2DecoderCallback *cb, void *arg);
104 protected:
105 int CodeNum(const int lo, const int hi, NumContext &ctx);
106
107 // virtual
108 bool CodeBit(const bool bit, BitContext &ctx);
109 void code_comment(GUTF8String &comment);
110 void code_record_type(int &rectype);
111 int code_match_index(int &index, JB2Dict &jim);
112 void code_inherited_shape_count(JB2Dict &jim);
113 void code_image_size(JB2Dict &jim);
114 void code_image_size(JB2Image &jim);
115 void code_absolute_location(JB2Blit *jblt, int rows, int columns);
116 void code_absolute_mark_size(GBitmap &bm, int border=0);
117 void code_relative_mark_size(GBitmap &bm, int cw, int ch, int border=0);
118 void code_bitmap_directly(GBitmap &bm,const int dw, int dy,
119 unsigned char *up2, unsigned char *up1, unsigned char *up0 );
120 void code_bitmap_by_cross_coding (GBitmap &bm, GBitmap &cbm,
121 const int xd2c, const int dw, int dy, int cy,
122 unsigned char *up1, unsigned char *up0, unsigned char *xup1,
123 unsigned char *xup0, unsigned char *xdn1 );
124 int get_diff(const int x_diff,NumContext &rel_loc);
125
126 private:
127 GP<ZPCodec> gzp;
128 JB2DecoderCallback *cbfunc;
129 void *cbarg;
130 };
131
132 ////////////////////////////////////////
133 //// CLASS JB2DICT: IMPLEMENTATION
134 ////////////////////////////////////////
135
136
JB2Dict()137 JB2Dict::JB2Dict()
138 : inherited_shapes(0)
139 {
140 }
141
142 void
init()143 JB2Dict::init()
144 {
145 inherited_shapes = 0;
146 inherited_dict = 0;
147 shapes.empty();
148 }
149
150 JB2Shape &
get_shape(const int shapeno)151 JB2Dict::get_shape(const int shapeno)
152 {
153 JB2Shape *retval;
154 if(shapeno >= inherited_shapes)
155 {
156 retval=&shapes[shapeno - inherited_shapes];
157 }else if(inherited_dict)
158 {
159 retval=&(inherited_dict->get_shape(shapeno));
160 }else
161 {
162 G_THROW( ERR_MSG("JB2Image.bad_number") );
163 }
164 return *retval;
165 }
166
167 const JB2Shape &
get_shape(const int shapeno) const168 JB2Dict::get_shape(const int shapeno) const
169 {
170 const JB2Shape *retval;
171 if(shapeno >= inherited_shapes)
172 {
173 retval=&shapes[shapeno - inherited_shapes];
174 }else if(inherited_dict)
175 {
176 retval=&(inherited_dict->get_shape(shapeno));
177 }else
178 {
179 G_THROW( ERR_MSG("JB2Image.bad_number") );
180 }
181 return *retval;
182 }
183
184 void
set_inherited_dict(const GP<JB2Dict> & dict)185 JB2Dict::set_inherited_dict(const GP<JB2Dict> &dict)
186 {
187 if (shapes.size() > 0)
188 G_THROW( ERR_MSG("JB2Image.cant_set") );
189 if (inherited_dict)
190 G_THROW( ERR_MSG("JB2Image.cant_change") );
191 inherited_dict = dict;
192 inherited_shapes = dict->get_shape_count();
193 // Make sure that inherited bitmaps are marked as shared
194 for (int i=0; i<inherited_shapes; i++)
195 {
196 JB2Shape &jshp = dict->get_shape(i);
197 if (jshp.bits) jshp.bits->share();
198 }
199 }
200
201 void
compress()202 JB2Dict::compress()
203 {
204 for (int i=shapes.lbound(); i<=shapes.hbound(); i++)
205 shapes[i].bits->compress();
206 }
207
208 unsigned int
get_memory_usage() const209 JB2Dict::get_memory_usage() const
210 {
211 unsigned int usage = sizeof(JB2Dict);
212 usage += sizeof(JB2Shape) * shapes.size();
213 for (int i=shapes.lbound(); i<=shapes.hbound(); i++)
214 if (shapes[i].bits)
215 usage += shapes[i].bits->get_memory_usage();
216 return usage;
217 }
218
219 int
add_shape(const JB2Shape & shape)220 JB2Dict::add_shape(const JB2Shape &shape)
221 {
222 if (shape.parent >= get_shape_count())
223 G_THROW( ERR_MSG("JB2Image.bad_parent_shape") );
224 int index = shapes.size();
225 shapes.touch(index);
226 shapes[index] = shape;
227 return index + inherited_shapes;
228 }
229
230 void
decode(const GP<ByteStream> & gbs,JB2DecoderCallback * cb,void * arg)231 JB2Dict::decode(const GP<ByteStream> &gbs, JB2DecoderCallback *cb, void *arg)
232 {
233 init();
234 JB2Codec::Decode codec;
235 codec.init(gbs);
236 codec.set_dict_callback(cb,arg);
237 codec.code(this);
238 }
239
240
241
242 ////////////////////////////////////////
243 //// CLASS JB2IMAGE: IMPLEMENTATION
244 ////////////////////////////////////////
245
246
JB2Image(void)247 JB2Image::JB2Image(void)
248 : width(0), height(0), reproduce_old_bug(false)
249 {
250 }
251
252 void
init(void)253 JB2Image::init(void)
254 {
255 width = height = 0;
256 blits.empty();
257 JB2Dict::init();
258 }
259
260 unsigned int
get_memory_usage() const261 JB2Image::get_memory_usage() const
262 {
263 unsigned int usage = JB2Dict::get_memory_usage();
264 usage += sizeof(JB2Image) - sizeof(JB2Dict);
265 usage += sizeof(JB2Blit) * blits.size();
266 return usage;
267 }
268
269 void
set_dimension(int awidth,int aheight)270 JB2Image::set_dimension(int awidth, int aheight)
271 {
272 width = awidth;
273 height = aheight;
274 }
275
276 int
add_blit(const JB2Blit & blit)277 JB2Image::add_blit(const JB2Blit &blit)
278 {
279 if (blit.shapeno >= (unsigned int)get_shape_count())
280 G_THROW( ERR_MSG("JB2Image.bad_shape") );
281 int index = blits.size();
282 blits.touch(index);
283 blits[index] = blit;
284 return index;
285 }
286
287 GP<GBitmap>
get_bitmap(int subsample,int align) const288 JB2Image::get_bitmap(int subsample, int align) const
289 {
290 if (width==0 || height==0)
291 G_THROW( ERR_MSG("JB2Image.cant_create") );
292 int swidth = (width + subsample - 1) / subsample;
293 int sheight = (height + subsample - 1) / subsample;
294 int border = ((swidth + align - 1) & ~(align - 1)) - swidth;
295 GP<GBitmap> bm = GBitmap::create(sheight, swidth, border);
296 bm->set_grays(1+subsample*subsample);
297 for (int blitno = 0; blitno < get_blit_count(); blitno++)
298 {
299 const JB2Blit *pblit = get_blit(blitno);
300 const JB2Shape &pshape = get_shape(pblit->shapeno);
301 if (pshape.bits)
302 bm->blit(pshape.bits, pblit->left, pblit->bottom, subsample);
303 }
304 return bm;
305 }
306
307 GP<GBitmap>
get_bitmap(const GRect & rect,int subsample,int align,int dispy) const308 JB2Image::get_bitmap(const GRect &rect, int subsample, int align, int dispy) const
309 {
310 if (width==0 || height==0)
311 G_THROW( ERR_MSG("JB2Image.cant_create") );
312 int rxmin = rect.xmin * subsample;
313 int rymin = rect.ymin * subsample;
314 int swidth = rect.width();
315 int sheight = rect.height();
316 int border = ((swidth + align - 1) & ~(align - 1)) - swidth;
317 GP<GBitmap> bm = GBitmap::create(sheight, swidth, border);
318 bm->set_grays(1+subsample*subsample);
319 for (int blitno = 0; blitno < get_blit_count(); blitno++)
320 {
321 const JB2Blit *pblit = get_blit(blitno);
322 const JB2Shape &pshape = get_shape(pblit->shapeno);
323 if (pshape.bits)
324 bm->blit(pshape.bits, pblit->left-rxmin, pblit->bottom-rymin+dispy, subsample);
325 }
326 return bm;
327 }
328
329 void
decode(const GP<ByteStream> & gbs,JB2DecoderCallback * cb,void * arg)330 JB2Image::decode(const GP<ByteStream> &gbs, JB2DecoderCallback *cb, void *arg)
331 {
332 init();
333 JB2Codec::Decode codec;
334 codec.init(gbs);
335 codec.set_dict_callback(cb,arg);
336 codec.code(this);
337 }
338
339
340
341 ////////////////////////////////////////
342 //// CLASS JB2CODEC : IMPLEMENTATION
343 ////////////////////////////////////////
344
345
346
347 #define START_OF_DATA (0)
348 #define NEW_MARK (1)
349 #define NEW_MARK_LIBRARY_ONLY (2)
350 #define NEW_MARK_IMAGE_ONLY (3)
351 #define MATCHED_REFINE (4)
352 #define MATCHED_REFINE_LIBRARY_ONLY (5)
353 #define MATCHED_REFINE_IMAGE_ONLY (6)
354 #define MATCHED_COPY (7)
355 #define NON_MARK_DATA (8)
356 #define REQUIRED_DICT_OR_RESET (9)
357 #define PRESERVED_COMMENT (10)
358 #define END_OF_DATA (11)
359
360
361
362 // STATIC DATA MEMBERS
363
364 static const int BIGPOSITIVE = 262142;
365 static const int BIGNEGATIVE = -262143;
366 static const int CELLCHUNK = 20000;
367 static const int CELLEXTRA = 500;
368
369
370 // CONSTRUCTOR
371
Decode(void)372 JB2Dict::JB2Codec::Decode::Decode(void)
373 : JB2Dict::JB2Codec(0), cbfunc(0), cbarg(0) {}
374
375 void
init(const GP<ByteStream> & gbs)376 JB2Dict::JB2Codec::Decode::init(const GP<ByteStream> &gbs)
377 {
378 gzp=ZPCodec::create(gbs,false,true);
379 }
380
JB2Codec(const bool xencoding)381 JB2Dict::JB2Codec::JB2Codec(const bool xencoding)
382 : encoding(xencoding),
383 cur_ncell(0),
384 gbitcells(bitcells,CELLCHUNK+CELLEXTRA),
385 gleftcell(leftcell,CELLCHUNK+CELLEXTRA),
386 grightcell(rightcell,CELLCHUNK+CELLEXTRA),
387 refinementp(false),
388 gotstartrecordp(0),
389 dist_comment_byte(0),
390 dist_comment_length(0),
391 dist_record_type(0),
392 dist_match_index(0),
393 dist_refinement_flag(0),
394 abs_loc_x(0),
395 abs_loc_y(0),
396 abs_size_x(0),
397 abs_size_y(0),
398 image_size_dist(0),
399 inherited_shape_count_dist(0),
400 offset_type_dist(0),
401 rel_loc_x_current(0),
402 rel_loc_x_last(0),
403 rel_loc_y_current(0),
404 rel_loc_y_last(0),
405 rel_size_x(0),
406 rel_size_y(0)
407 {
408 memset(bitdist, 0, sizeof(bitdist));
409 memset(cbitdist, 0, sizeof(cbitdist));
410 // Initialize numcoder
411 bitcells[0] = 0; // dummy cell
412 leftcell[0] = rightcell[0] = 0;
413 cur_ncell = 1;
414 }
415
~JB2Codec()416 JB2Dict::JB2Codec::~JB2Codec() {}
417
418 void
reset_numcoder()419 JB2Dict::JB2Codec::reset_numcoder()
420 {
421 dist_comment_byte = 0;
422 dist_comment_length = 0;
423 dist_record_type = 0;
424 dist_match_index = 0;
425 abs_loc_x = 0;
426 abs_loc_y = 0;
427 abs_size_x = 0;
428 abs_size_y = 0;
429 image_size_dist = 0;
430 inherited_shape_count_dist = 0;
431 rel_loc_x_current = 0;
432 rel_loc_x_last = 0;
433 rel_loc_y_current = 0;
434 rel_loc_y_last = 0;
435 rel_size_x = 0;
436 rel_size_y = 0;
437 gbitcells.clear();
438 gleftcell.clear();
439 grightcell.clear();
440 cur_ncell = 1;
441 }
442
443
444 void
set_dict_callback(JB2DecoderCallback * cb,void * arg)445 JB2Dict::JB2Codec::Decode::set_dict_callback(JB2DecoderCallback *cb, void *arg)
446 {
447 cbfunc = cb;
448 cbarg = arg;
449 }
450
451
452 // CODE NUMBERS
453
454 inline bool
CodeBit(const bool,BitContext & ctx)455 JB2Dict::JB2Codec::Decode::CodeBit(const bool, BitContext &ctx)
456 {
457 return gzp->decoder(ctx)?true:false;
458 }
459
460 int
CodeNum(int low,int high,NumContext & ctx)461 JB2Dict::JB2Codec::Decode::CodeNum(int low, int high, NumContext &ctx)
462 {
463 return JB2Codec::CodeNum(low,high,&ctx,0);
464 }
465
466 int
CodeNum(int low,int high,NumContext * pctx,int v)467 JB2Dict::JB2Codec::CodeNum(int low, int high, NumContext *pctx, int v)
468 {
469 bool negative=false;
470 int cutoff;
471 // Check
472 if (!pctx || ((int)*pctx >= cur_ncell))
473 G_THROW( ERR_MSG("JB2Image.bad_numcontext") );
474 // Start all phases
475 cutoff = 0;
476 for(int phase=1,range=0xffffffff;range != 1;)
477 {
478 if (! *pctx)
479 {
480 const int max_ncell=gbitcells;
481 if (cur_ncell >= max_ncell)
482 {
483 const int nmax_ncell = max_ncell+CELLCHUNK;
484 gbitcells.resize(nmax_ncell);
485 gleftcell.resize(nmax_ncell);
486 grightcell.resize(nmax_ncell);
487 }
488 *pctx = cur_ncell ++;
489 bitcells[*pctx] = 0;
490 leftcell[*pctx] = rightcell[*pctx] = 0;
491 }
492 // encode
493 const bool decision = encoding
494 ? ((low < cutoff && high >= cutoff)
495 ? CodeBit((v>=cutoff),bitcells[*pctx])
496 : (v >= cutoff))
497 : ((low>=cutoff)||((high>=cutoff)&&CodeBit(false,bitcells[*pctx])));
498 // context for new bit
499 pctx = decision?(&rightcell[*pctx]):(&leftcell[*pctx]);
500 // phase dependent part
501 switch (phase)
502 {
503 case 1:
504 negative = !decision;
505 if (negative)
506 {
507 if (encoding)
508 v = - v - 1;
509 const int temp = - low - 1;
510 low = - high - 1;
511 high = temp;
512 }
513 phase = 2; cutoff = 1;
514 break;
515
516 case 2:
517 if (!decision)
518 {
519 phase = 3;
520 range = (cutoff + 1) / 2;
521 if (range == 1)
522 cutoff = 0;
523 else
524 cutoff -= range / 2;
525 }
526 else
527 {
528 cutoff += cutoff + 1;
529 }
530 break;
531
532 case 3:
533 range /= 2;
534 if (range != 1)
535 {
536 if (!decision)
537 cutoff -= range / 2;
538 else
539 cutoff += range / 2;
540 }
541 else if (!decision)
542 {
543 cutoff --;
544 }
545 break;
546 }
547 }
548 return (negative)?(- cutoff - 1):cutoff;
549 }
550
551
552
553 // CODE COMMENTS
554
555 void
code_comment(GUTF8String & comment)556 JB2Dict::JB2Codec::Decode::code_comment(GUTF8String &comment)
557 {
558 int size=CodeNum(0, BIGPOSITIVE, dist_comment_length);
559 comment.empty();
560 char *combuf = comment.getbuf(size);
561 for (int i=0; i<size; i++)
562 {
563 combuf[i]=CodeNum(0, 255, dist_comment_byte);
564 }
565 comment.getbuf();
566 }
567
568
569 // LIBRARY
570
571
572 void
init_library(JB2Dict & jim)573 JB2Dict::JB2Codec::init_library(JB2Dict &jim)
574 {
575 int nshape = jim.get_inherited_shape_count();
576 shape2lib.resize(0,nshape-1);
577 lib2shape.resize(0,nshape-1);
578 libinfo.resize(0,nshape-1);
579 for (int i=0; i<nshape; i++)
580 {
581 shape2lib[i] = i;
582 lib2shape[i] = i;
583 jim.get_bounding_box(i, libinfo[i]);
584 }
585 }
586
587 int
add_library(const int shapeno,JB2Shape & jshp)588 JB2Dict::JB2Codec::add_library(const int shapeno, JB2Shape &jshp)
589 {
590 const int libno = lib2shape.hbound() + 1;
591 lib2shape.touch(libno);
592 lib2shape[libno] = shapeno;
593 shape2lib.touch(shapeno);
594 shape2lib[shapeno] = libno;
595 libinfo.touch(libno);
596 libinfo[libno].compute_bounding_box(*(jshp.bits));
597 return libno;
598 }
599
600
601 // CODE SIMPLE VALUES
602
603 inline void
code_record_type(int & rectype)604 JB2Dict::JB2Codec::Decode::code_record_type(int &rectype)
605 {
606 rectype=CodeNum( START_OF_DATA, END_OF_DATA, dist_record_type);
607 }
608
609 int
code_match_index(int & index,JB2Dict &)610 JB2Dict::JB2Codec::Decode::code_match_index(int &index, JB2Dict &)
611 {
612 int match=CodeNum(0, lib2shape.hbound(), dist_match_index);
613 index = lib2shape[match];
614 return match;
615 }
616
617
618 // HANDLE SHORT LIST
619
620 int
update_short_list(const int v)621 JB2Dict::JB2Codec::update_short_list(const int v)
622 {
623 if (++ short_list_pos == 3)
624 short_list_pos = 0;
625 int * const s = short_list;
626 s[short_list_pos] = v;
627
628 return (s[0] >= s[1])
629 ?((s[0] > s[2])?((s[1] >= s[2])?s[1]:s[2]):s[0])
630 :((s[0] < s[2])?((s[1] >= s[2])?s[2]:s[1]):s[0]);
631 }
632
633
634
635 // CODE PAIRS
636
637
638 void
code_inherited_shape_count(JB2Dict & jim)639 JB2Dict::JB2Codec::Decode::code_inherited_shape_count(JB2Dict &jim)
640 {
641 int size=CodeNum(0, BIGPOSITIVE, inherited_shape_count_dist);
642 {
643 GP<JB2Dict> dict = jim.get_inherited_dict();
644 if (!dict && size>0)
645 {
646 // Call callback function to obtain dictionary
647 if (cbfunc)
648 dict = (*cbfunc)(cbarg);
649 if (dict)
650 jim.set_inherited_dict(dict);
651 }
652 if (!dict && size>0)
653 G_THROW( ERR_MSG("JB2Image.need_dict") );
654 if (dict && size!=dict->get_shape_count())
655 G_THROW( ERR_MSG("JB2Image.bad_dict") );
656 }
657 }
658
659 void
code_image_size(JB2Dict & jim)660 JB2Dict::JB2Codec::Decode::code_image_size(JB2Dict &jim)
661 {
662 int w=CodeNum(0, BIGPOSITIVE, image_size_dist);
663 int h=CodeNum(0, BIGPOSITIVE, image_size_dist);
664 if (w || h)
665 G_THROW( ERR_MSG("JB2Image.bad_dict2") );
666 JB2Codec::code_image_size(jim);
667 }
668
669 void
code_image_size(JB2Dict &)670 JB2Dict::JB2Codec::code_image_size(JB2Dict &)
671 {
672 last_left = 1;
673 last_row_left = 0;
674 last_row_bottom = 0;
675 last_right = 0;
676 fill_short_list(last_row_bottom);
677 gotstartrecordp = 1;
678 }
679
680 void
code_image_size(JB2Image & jim)681 JB2Dict::JB2Codec::Decode::code_image_size(JB2Image &jim)
682 {
683 image_columns=CodeNum(0, BIGPOSITIVE, image_size_dist);
684 image_rows=CodeNum(0, BIGPOSITIVE, image_size_dist);
685 if (!image_columns || !image_rows)
686 G_THROW( ERR_MSG("JB2Image.zero_dim") );
687 jim.set_dimension(image_columns, image_rows);
688 JB2Codec::code_image_size(jim);
689 }
690
691 void
code_image_size(JB2Image &)692 JB2Dict::JB2Codec::code_image_size(JB2Image &)
693 {
694 last_left = 1 + image_columns;
695 last_row_left = 0;
696 last_row_bottom = image_rows;
697 last_right = 0;
698 fill_short_list(last_row_bottom);
699 gotstartrecordp = 1;
700 }
701
702 inline int
get_diff(int,NumContext & rel_loc)703 JB2Dict::JB2Codec::Decode::get_diff(int,NumContext &rel_loc)
704 {
705 return CodeNum(BIGNEGATIVE, BIGPOSITIVE, rel_loc);
706 }
707
708 void
code_relative_location(JB2Blit * jblt,int rows,int columns)709 JB2Dict::JB2Codec::code_relative_location(JB2Blit *jblt, int rows, int columns)
710 {
711 // Check start record
712 if (!gotstartrecordp)
713 G_THROW( ERR_MSG("JB2Image.no_start") );
714 // Find location
715 int bottom=0, left=0, top=0, right=0;
716 int x_diff, y_diff;
717 if (encoding)
718 {
719 left = jblt->left + 1;
720 bottom = jblt->bottom + 1;
721 right = left + columns - 1;
722 top = bottom + rows - 1;
723 }
724 // Code offset type
725 int new_row=CodeBit((left<last_left), offset_type_dist);
726 if (new_row)
727 {
728 // Begin a new row
729 x_diff=get_diff(left-last_row_left,rel_loc_x_last);
730 y_diff=get_diff(top-last_row_bottom,rel_loc_y_last);
731 if (!encoding)
732 {
733 left = last_row_left + x_diff;
734 top = last_row_bottom + y_diff;
735 right = left + columns - 1;
736 bottom = top - rows + 1;
737 }
738 last_left = last_row_left = left;
739 last_right = right;
740 last_bottom = last_row_bottom = bottom;
741 fill_short_list(bottom);
742 }
743 else
744 {
745 // Same row
746 x_diff=get_diff(left-last_right,rel_loc_x_current);
747 y_diff=get_diff(bottom-last_bottom,rel_loc_y_current);
748 if (!encoding)
749 {
750 left = last_right + x_diff;
751 bottom = last_bottom + y_diff;
752 right = left + columns - 1;
753 top = bottom + rows - 1;
754 }
755 last_left = left;
756 last_right = right;
757 last_bottom = update_short_list(bottom);
758 }
759 // Store in blit record
760 if (!encoding)
761 {
762 jblt->bottom = bottom - 1;
763 jblt->left = left - 1;
764 }
765 }
766
767 void
code_absolute_location(JB2Blit * jblt,int rows,int columns)768 JB2Dict::JB2Codec::Decode::code_absolute_location(JB2Blit *jblt, int rows, int columns)
769 {
770 // Check start record
771 if (!gotstartrecordp)
772 G_THROW( ERR_MSG("JB2Image.no_start") );
773 int left=CodeNum(1, image_columns, abs_loc_x);
774 int top=CodeNum(1, image_rows, abs_loc_y);
775 jblt->bottom = top - rows + 1 - 1;
776 jblt->left = left - 1;
777 }
778
779 void
code_absolute_mark_size(GBitmap & bm,int border)780 JB2Dict::JB2Codec::Decode::code_absolute_mark_size(GBitmap &bm, int border)
781 {
782 int xsize=CodeNum(0, BIGPOSITIVE, abs_size_x);
783 int ysize=CodeNum(0, BIGPOSITIVE, abs_size_y);
784 if ((xsize!=(unsigned short)xsize) || (ysize!=(unsigned short)ysize))
785 G_THROW( ERR_MSG("JB2Image.bad_number") );
786 bm.init(ysize, xsize, border);
787 }
788
789 void
code_relative_mark_size(GBitmap & bm,int cw,int ch,int border)790 JB2Dict::JB2Codec::Decode::code_relative_mark_size(GBitmap &bm, int cw, int ch, int border)
791 {
792 int xdiff=CodeNum(BIGNEGATIVE, BIGPOSITIVE, rel_size_x);
793 int ydiff=CodeNum(BIGNEGATIVE, BIGPOSITIVE, rel_size_y);
794 int xsize = cw + xdiff;
795 int ysize = ch + ydiff;
796 if ((xsize!=(unsigned short)xsize) || (ysize!=(unsigned short)ysize))
797 G_THROW( ERR_MSG("JB2Image.bad_number") );
798 bm.init(ysize, xsize, border);
799 }
800
801
802
803
804 // CODE BITMAP DIRECTLY
805
806 void
code_bitmap_directly(GBitmap & bm)807 JB2Dict::JB2Codec::code_bitmap_directly (GBitmap &bm)
808 {
809 // Make sure bitmap will not be disturbed
810 GMonitorLock lock(bm.monitor());
811 // ensure borders are adequate
812 bm.minborder(3);
813 // initialize row pointers
814 int dy = bm.rows() - 1;
815 code_bitmap_directly(bm,bm.columns(),dy,bm[dy+2],bm[dy+1],bm[dy]);
816 }
817
818 void
code_bitmap_directly(GBitmap & bm,const int dw,int dy,unsigned char * up2,unsigned char * up1,unsigned char * up0)819 JB2Dict::JB2Codec::Decode::code_bitmap_directly(
820 GBitmap &bm,const int dw, int dy,
821 unsigned char *up2, unsigned char *up1, unsigned char *up0 )
822 {
823 ZPCodec &zp=*gzp;
824 // iterate on rows (decoding)
825 while (dy >= 0)
826 {
827 int context=get_direct_context(up2, up1, up0, 0);
828 for(int dx=0;dx < dw;)
829 {
830 int n = zp.decoder(bitdist[context]);
831 up0[dx++] = n;
832 context=shift_direct_context(context, n, up2, up1, up0, dx);
833 }
834 // next row
835 dy -= 1;
836 up2 = up1;
837 up1 = up0;
838 up0 = bm[dy];
839 }
840 #ifndef NDEBUG
841 bm.check_border();
842 #endif
843 }
844
845
846
847
848
849 // CODE BITMAP BY CROSS CODING
850
851 void
code_bitmap_by_cross_coding(GBitmap & bm,GP<GBitmap> & cbm,const int libno)852 JB2Dict::JB2Codec::code_bitmap_by_cross_coding (GBitmap &bm, GP<GBitmap> &cbm, const int libno)
853 {
854 // Make sure bitmaps will not be disturbed
855 GP<GBitmap> copycbm=GBitmap::create();
856 if (cbm->monitor())
857 {
858 // Perform a copy when the bitmap is explicitely shared
859 GMonitorLock lock2(cbm->monitor());
860 copycbm->init(*cbm);
861 cbm = copycbm;
862 }
863 GMonitorLock lock1(bm.monitor());
864 // Center bitmaps
865 const int cw = cbm->columns();
866 const int dw = bm.columns();
867 const int dh = bm.rows();
868 const LibRect &l = libinfo[libno];
869 const int xd2c = (dw/2 - dw + 1) - ((l.right - l.left + 1)/2 - l.right);
870 const int yd2c = (dh/2 - dh + 1) - ((l.top - l.bottom + 1)/2 - l.top);
871 // Ensure borders are adequate
872 bm.minborder(2);
873 cbm->minborder(2-xd2c);
874 cbm->minborder(2+dw+xd2c-cw);
875 // Initialize row pointers
876 const int dy = dh - 1;
877 const int cy = dy + yd2c;
878 #ifndef NDEBUG
879 bm.check_border();
880 cbm->check_border();
881 #endif
882 code_bitmap_by_cross_coding (bm,*cbm, xd2c, dw, dy, cy, bm[dy+1], bm[dy],
883 (*cbm)[cy+1] + xd2c, (*cbm)[cy ] + xd2c, (*cbm)[cy-1] + xd2c);
884 }
885
886 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)887 JB2Dict::JB2Codec::Decode::code_bitmap_by_cross_coding (GBitmap &bm, GBitmap &cbm,
888 const int xd2c, const int dw, int dy, int cy,
889 unsigned char *up1, unsigned char *up0, unsigned char *xup1,
890 unsigned char *xup0, unsigned char *xdn1 )
891 {
892 ZPCodec &zp=*gzp;
893 // iterate on rows (decoding)
894 while (dy >= 0)
895 {
896 int context=get_cross_context(
897 up1, up0, xup1, xup0, xdn1, 0);
898 for(int dx=0;dx < dw;)
899 {
900 const int n = zp.decoder(cbitdist[context]);
901 up0[dx++] = n;
902 context=shift_cross_context(context, n,
903 up1, up0, xup1, xup0, xdn1, dx);
904 }
905 // next row
906 up1 = up0;
907 up0 = bm[--dy];
908 xup1 = xup0;
909 xup0 = xdn1;
910 xdn1 = cbm[(--cy)-1] + xd2c;
911 #ifndef NDEBUG
912 bm.check_border();
913 #endif
914 }
915 }
916
917
918
919
920 // CODE JB2DICT RECORD
921
922 void
code_record(int & rectype,const GP<JB2Dict> & gjim,JB2Shape * xjshp)923 JB2Dict::JB2Codec::code_record(
924 int &rectype, const GP<JB2Dict> &gjim, JB2Shape *xjshp)
925 {
926 GP<GBitmap> cbm;
927 GP<GBitmap> bm;
928 int shapeno = -1;
929
930 // Code record type
931 code_record_type(rectype);
932
933 // Pre-coding actions
934 switch(rectype)
935 {
936 case NEW_MARK_LIBRARY_ONLY:
937 case MATCHED_REFINE_LIBRARY_ONLY:
938 {
939 if(!xjshp)
940 {
941 G_THROW( ERR_MSG("JB2Image.bad_number") );
942 }
943 JB2Shape &jshp=*xjshp;
944 if (!encoding)
945 {
946 jshp.bits = GBitmap::create();
947 jshp.parent = -1;
948 }
949 bm = jshp.bits;
950 break;
951 }
952 }
953 // Coding actions
954 switch (rectype)
955 {
956 case START_OF_DATA:
957 {
958 if(!gjim)
959 {
960 G_THROW( ERR_MSG("JB2Image.bad_number") );
961 }
962 JB2Dict &jim=*gjim;
963 code_image_size (jim);
964 code_eventual_lossless_refinement ();
965 if (! encoding)
966 init_library(jim);
967 break;
968 }
969 case NEW_MARK_LIBRARY_ONLY:
970 {
971 code_absolute_mark_size (*bm, 4);
972 code_bitmap_directly (*bm);
973 break;
974 }
975 case MATCHED_REFINE_LIBRARY_ONLY:
976 {
977 if(!xjshp||!gjim)
978 {
979 G_THROW( ERR_MSG("JB2Image.bad_number") );
980 }
981 JB2Dict &jim=*gjim;
982 JB2Shape &jshp=*xjshp;
983 int match = code_match_index (jshp.parent, jim);
984 cbm = jim.get_shape(jshp.parent).bits;
985 LibRect &l = libinfo[match];
986 code_relative_mark_size (*bm, l.right-l.left+1, l.top-l.bottom+1, 4);
987 code_bitmap_by_cross_coding (*bm, cbm, jshp.parent);
988 break;
989 }
990 case PRESERVED_COMMENT:
991 {
992 if(!gjim)
993 {
994 G_THROW( ERR_MSG("JB2Image.bad_number") );
995 }
996 JB2Dict &jim=*gjim;
997 code_comment(jim.comment);
998 break;
999 }
1000 case REQUIRED_DICT_OR_RESET:
1001 {
1002 if (! gotstartrecordp)
1003 {
1004 // Indicates need for a shape dictionary
1005 if(!gjim)
1006 {
1007 G_THROW( ERR_MSG("JB2Image.bad_number") );
1008 }
1009 code_inherited_shape_count(*gjim);
1010 }else
1011 // Reset all numerical contexts to zero
1012 reset_numcoder();
1013 break;
1014 }
1015 case END_OF_DATA:
1016 {
1017 break;
1018 }
1019 default:
1020 {
1021 G_THROW( ERR_MSG("JB2Image.bad_type") );
1022 }
1023 }
1024 // Post-coding action
1025 if (!encoding)
1026 {
1027 // add shape to dictionary
1028 switch(rectype)
1029 {
1030 case NEW_MARK_LIBRARY_ONLY:
1031 case MATCHED_REFINE_LIBRARY_ONLY:
1032 {
1033 if(!xjshp||!gjim)
1034 {
1035 G_THROW( ERR_MSG("JB2Image.bad_number") );
1036 }
1037 JB2Shape &jshp=*xjshp;
1038 shapeno = gjim->add_shape(jshp);
1039 add_library(shapeno, jshp);
1040 break;
1041 }
1042 }
1043 // make sure everything is compacted
1044 // decompaction will occur automatically when needed
1045 if (bm)
1046 bm->compress();
1047 }
1048 }
1049
1050
1051 // CODE JB2DICT
1052
1053 void
code(const GP<JB2Dict> & gjim)1054 JB2Dict::JB2Codec::Decode::code(const GP<JB2Dict> &gjim)
1055 {
1056 if(!gjim)
1057 {
1058 G_THROW( ERR_MSG("JB2Image.bad_number") );
1059 }
1060 JB2Dict &jim=*gjim;
1061 // -------------------------
1062 // THIS IS THE DECODING PART
1063 // -------------------------
1064 int rectype;
1065 JB2Shape tmpshape;
1066 do {
1067 code_record(rectype, gjim, &tmpshape);
1068 } while(rectype != END_OF_DATA);
1069 if (!gotstartrecordp)
1070 G_THROW( ERR_MSG("JB2Image.no_start") );
1071 // cache bounding boxes
1072 int nshapes = jim.get_shape_count();
1073 int ishapes = jim.get_inherited_shape_count();
1074 jim.boxes.resize(0, nshapes-ishapes-1);
1075 for (int i = ishapes; i < nshapes; i++)
1076 jim.boxes[i-ishapes] = libinfo[i];
1077 // compress
1078 jim.compress();
1079 }
1080
1081
1082
1083 // CODE JB2IMAGE RECORD
1084
1085 void
code_record(int & rectype,const GP<JB2Image> & gjim,JB2Shape * xjshp,JB2Blit * jblt)1086 JB2Dict::JB2Codec::code_record(
1087 int &rectype, const GP<JB2Image> &gjim, JB2Shape *xjshp, JB2Blit *jblt)
1088 {
1089 GP<GBitmap> bm;
1090 GP<GBitmap> cbm;
1091 int shapeno = -1;
1092 int match;
1093
1094 // Code record type
1095 code_record_type(rectype);
1096
1097 // Pre-coding actions
1098 switch(rectype)
1099 {
1100 case NEW_MARK:
1101 case NEW_MARK_LIBRARY_ONLY:
1102 case NEW_MARK_IMAGE_ONLY:
1103 case MATCHED_REFINE:
1104 case MATCHED_REFINE_LIBRARY_ONLY:
1105 case MATCHED_REFINE_IMAGE_ONLY:
1106 case NON_MARK_DATA:
1107 {
1108 if(!xjshp)
1109 {
1110 G_THROW( ERR_MSG("JB2Image.bad_number") );
1111 }
1112 JB2Shape &jshp=*xjshp;
1113 if (!encoding)
1114 {
1115 jshp.bits = GBitmap::create();
1116 jshp.parent = -1;
1117 if (rectype == NON_MARK_DATA)
1118 jshp.parent = -2;
1119 }
1120 bm = jshp.bits;
1121 break;
1122 }
1123 }
1124 // Coding actions
1125 switch (rectype)
1126 {
1127 case START_OF_DATA:
1128 {
1129 if(!gjim)
1130 {
1131 G_THROW( ERR_MSG("JB2Image.bad_number") );
1132 }
1133 JB2Image &jim=*gjim;
1134 code_image_size (jim);
1135 code_eventual_lossless_refinement ();
1136 if (! encoding)
1137 init_library(jim);
1138 break;
1139 }
1140 case NEW_MARK:
1141 {
1142 code_absolute_mark_size (*bm, 4);
1143 code_bitmap_directly (*bm);
1144 code_relative_location (jblt, bm->rows(), bm->columns() );
1145 break;
1146 }
1147 case NEW_MARK_LIBRARY_ONLY:
1148 {
1149 code_absolute_mark_size (*bm, 4);
1150 code_bitmap_directly (*bm);
1151 break;
1152 }
1153 case NEW_MARK_IMAGE_ONLY:
1154 {
1155 code_absolute_mark_size (*bm, 3);
1156 code_bitmap_directly (*bm);
1157 code_relative_location (jblt, bm->rows(), bm->columns() );
1158 break;
1159 }
1160 case MATCHED_REFINE:
1161 {
1162 if(!xjshp || !gjim)
1163 {
1164 G_THROW( ERR_MSG("JB2Image.bad_number") );
1165 }
1166 JB2Shape &jshp=*xjshp;
1167 JB2Image &jim=*gjim;
1168 match = code_match_index (jshp.parent, jim);
1169 cbm = jim.get_shape(jshp.parent).bits;
1170 LibRect &l = libinfo[match];
1171 code_relative_mark_size (*bm, l.right-l.left+1, l.top-l.bottom+1, 4);
1172 code_bitmap_by_cross_coding (*bm, cbm, match);
1173 code_relative_location (jblt, bm->rows(), bm->columns() );
1174 break;
1175 }
1176 case MATCHED_REFINE_LIBRARY_ONLY:
1177 {
1178 if(!xjshp||!gjim)
1179 {
1180 G_THROW( ERR_MSG("JB2Image.bad_number") );
1181 }
1182 JB2Image &jim=*gjim;
1183 JB2Shape &jshp=*xjshp;
1184 match = code_match_index (jshp.parent, jim);
1185 cbm = jim.get_shape(jshp.parent).bits;
1186 LibRect &l = libinfo[match];
1187 code_relative_mark_size (*bm, l.right-l.left+1, l.top-l.bottom+1, 4);
1188 break;
1189 }
1190 case MATCHED_REFINE_IMAGE_ONLY:
1191 {
1192 if(!xjshp||!gjim)
1193 {
1194 G_THROW( ERR_MSG("JB2Image.bad_number") );
1195 }
1196 JB2Image &jim=*gjim;
1197 JB2Shape &jshp=*xjshp;
1198 match = code_match_index (jshp.parent, jim);
1199 cbm = jim.get_shape(jshp.parent).bits;
1200 LibRect &l = libinfo[match];
1201 code_relative_mark_size (*bm, l.right-l.left+1, l.top-l.bottom+1, 4);
1202 code_bitmap_by_cross_coding (*bm, cbm, match);
1203 code_relative_location (jblt, bm->rows(), bm->columns() );
1204 break;
1205 }
1206 case MATCHED_COPY:
1207 {
1208 int temp;
1209 if (encoding) temp = jblt->shapeno;
1210 if(!gjim)
1211 {
1212 G_THROW( ERR_MSG("JB2Image.bad_number") );
1213 }
1214 JB2Image &jim=*gjim;
1215 match = code_match_index (temp, jim);
1216 if (!encoding) jblt->shapeno = temp;
1217 bm = jim.get_shape(jblt->shapeno).bits;
1218 LibRect &l = libinfo[match];
1219 jblt->left += l.left;
1220 jblt->bottom += l.bottom;
1221 if (jim.reproduce_old_bug)
1222 code_relative_location (jblt, bm->rows(), bm->columns() );
1223 else
1224 code_relative_location (jblt, l.top-l.bottom+1, l.right-l.left+1 );
1225 jblt->left -= l.left;
1226 jblt->bottom -= l.bottom;
1227 break;
1228 }
1229 case NON_MARK_DATA:
1230 {
1231 code_absolute_mark_size (*bm, 3);
1232 code_bitmap_directly (*bm);
1233 code_absolute_location (jblt, bm->rows(), bm->columns() );
1234 break;
1235 }
1236 case PRESERVED_COMMENT:
1237 {
1238 if(!gjim)
1239 {
1240 G_THROW( ERR_MSG("JB2Image.bad_number") );
1241 }
1242 JB2Image &jim=*gjim;
1243 code_comment(jim.comment);
1244 break;
1245 }
1246 case REQUIRED_DICT_OR_RESET:
1247 {
1248 if(!gjim)
1249 {
1250 G_THROW( ERR_MSG("JB2Image.bad_number") );
1251 }
1252 JB2Image &jim=*gjim;
1253 if (! gotstartrecordp)
1254 // Indicates need for a shape dictionary
1255 code_inherited_shape_count(jim);
1256 else
1257 // Reset all numerical contexts to zero
1258 reset_numcoder();
1259 break;
1260 }
1261 case END_OF_DATA:
1262 {
1263 break;
1264 }
1265 default:
1266 {
1267 G_THROW( ERR_MSG("JB2Image.unknown_type") );
1268 }
1269 }
1270
1271 // Post-coding action
1272 if (!encoding)
1273 {
1274 // add shape to image
1275 switch(rectype)
1276 {
1277 case NEW_MARK:
1278 case NEW_MARK_LIBRARY_ONLY:
1279 case NEW_MARK_IMAGE_ONLY:
1280 case MATCHED_REFINE:
1281 case MATCHED_REFINE_LIBRARY_ONLY:
1282 case MATCHED_REFINE_IMAGE_ONLY:
1283 case NON_MARK_DATA:
1284 {
1285 if(!xjshp||!gjim)
1286 {
1287 G_THROW( ERR_MSG("JB2Image.bad_number") );
1288 }
1289 JB2Shape &jshp=*xjshp;
1290 shapeno = gjim->add_shape(jshp);
1291 shape2lib.touch(shapeno);
1292 shape2lib[shapeno] = -1;
1293 break;
1294 }
1295 }
1296 // add shape to library
1297 switch(rectype)
1298 {
1299 case NEW_MARK:
1300 case NEW_MARK_LIBRARY_ONLY:
1301 case MATCHED_REFINE:
1302 case MATCHED_REFINE_LIBRARY_ONLY:
1303 if(!xjshp)
1304 {
1305 G_THROW( ERR_MSG("JB2Image.bad_number") );
1306 }
1307 add_library(shapeno, *xjshp);
1308 break;
1309 }
1310 // make sure everything is compacted
1311 // decompaction will occur automatically on cross-coding bitmaps
1312 if (bm)
1313 bm->compress();
1314 // add blit to image
1315 switch (rectype)
1316 {
1317 case NEW_MARK:
1318 case NEW_MARK_IMAGE_ONLY:
1319 case MATCHED_REFINE:
1320 case MATCHED_REFINE_IMAGE_ONLY:
1321 case NON_MARK_DATA:
1322 jblt->shapeno = shapeno;
1323 case MATCHED_COPY:
1324 if(!gjim)
1325 {
1326 G_THROW( ERR_MSG("JB2Image.bad_number") );
1327 }
1328 gjim->add_blit(* jblt);
1329 break;
1330 }
1331 }
1332 }
1333
1334
1335 // CODE JB2IMAGE
1336
1337 void
code(const GP<JB2Image> & gjim)1338 JB2Dict::JB2Codec::Decode::code(const GP<JB2Image> &gjim)
1339 {
1340 if(!gjim)
1341 {
1342 G_THROW( ERR_MSG("JB2Image.bad_number") );
1343 }
1344 JB2Image &jim=*gjim;
1345 // -------------------------
1346 // THIS IS THE DECODING PART
1347 // -------------------------
1348 int rectype;
1349 JB2Blit tmpblit;
1350 JB2Shape tmpshape;
1351 do
1352 {
1353 code_record(rectype, gjim, &tmpshape, &tmpblit);
1354 }
1355 while(rectype!=END_OF_DATA);
1356 if (!gotstartrecordp)
1357 G_THROW( ERR_MSG("JB2Image.no_start") );
1358 jim.compress();
1359 }
1360
1361
1362
1363 ////////////////////////////////////////
1364 //// HELPERS
1365 ////////////////////////////////////////
1366
1367 void
compute_bounding_box(const GBitmap & bm)1368 JB2Dict::LibRect::compute_bounding_box(const GBitmap &bm)
1369 {
1370 // Avoid trouble
1371 GMonitorLock lock(bm.monitor());
1372 // Get size
1373 const int w = bm.columns();
1374 const int h = bm.rows();
1375 const int s = bm.rowsize();
1376 // Right border
1377 for(right=w-1;right >= 0;--right)
1378 {
1379 unsigned char const *p = bm[0] + right;
1380 unsigned char const * const pe = p+(s*h);
1381 for (;(p<pe)&&(!*p);p+=s)
1382 continue;
1383 if (p<pe)
1384 break;
1385 }
1386 // Top border
1387 for(top=h-1;top >= 0;--top)
1388 {
1389 unsigned char const *p = bm[top];
1390 unsigned char const * const pe = p+w;
1391 for (;(p<pe)&&(!*p); ++p)
1392 continue;
1393 if (p<pe)
1394 break;
1395 }
1396 // Left border
1397 for (left=0;left <= right;++left)
1398 {
1399 unsigned char const *p = bm[0] + left;
1400 unsigned char const * const pe=p+(s*h);
1401 for (;(p<pe)&&(!*p);p+=s)
1402 continue;
1403 if (p<pe)
1404 break;
1405 }
1406 // Bottom border
1407 for(bottom=0;bottom <= top;++bottom)
1408 {
1409 unsigned char const *p = bm[bottom];
1410 unsigned char const * const pe = p+w;
1411 for (;(p<pe)&&(!*p); ++p)
1412 continue;
1413 if (p<pe)
1414 break;
1415 }
1416 }
1417
1418
1419 void
get_bounding_box(int shapeno,LibRect & dest)1420 JB2Dict::get_bounding_box(int shapeno, LibRect &dest)
1421 {
1422 if (shapeno < inherited_shapes && inherited_dict)
1423 {
1424 inherited_dict->get_bounding_box(shapeno, dest);
1425 }
1426 else if (shapeno >= inherited_shapes &&
1427 shapeno < inherited_shapes + boxes.size())
1428 {
1429 dest = boxes[shapeno - inherited_shapes];
1430 }
1431 else
1432 {
1433 JB2Shape &jshp = get_shape(shapeno);
1434 dest.compute_bounding_box(*(jshp.bits));
1435 }
1436 }
1437
1438
1439 GP<JB2Dict>
create(void)1440 JB2Dict::create(void)
1441 {
1442 return new JB2Dict();
1443 }
1444
1445
1446 #ifdef HAVE_NAMESPACES
1447 }
1448 # ifndef NOT_USING_DJVU_NAMESPACE
1449 using namespace DJVU;
1450 # endif
1451 #endif
1452