1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251
|
/* Copyright (C) 2001-2019 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
implied.
This software is distributed under license and may not be copied,
modified or distributed except as expressly authorized under the terms
of the license contained in the file LICENSE in this distribution.
Refer to licensing information at http://www.artifex.com or contact
Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
CA 94945, U.S.A., +1(415)492-9861, for further information.
*/
/*
jbig2dec
*/
/**
* Generic region handlers.
**/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "os_types.h"
#include <stddef.h>
#include <string.h> /* memcpy(), memset() */
#ifdef OUTPUT_PBM
#include <stdio.h>
#endif
#include "jbig2.h"
#include "jbig2_priv.h"
#include "jbig2_arith.h"
#include "jbig2_generic.h"
#include "jbig2_image.h"
#include "jbig2_mmr.h"
#include "jbig2_page.h"
#include "jbig2_segment.h"
#if !defined (UINT32_MAX)
#define UINT32_MAX 0xffffffff
#endif
/*
This is an explanation of the unoptimized and optimized generic
region decoder implementations below, wherein we try to explain
all the magic numbers.
The generic region decoders decode the output pixels one row at a
time, top to bottom. Within each row the pixels are decoded left
to right. The input for the arithmetic integer decoder used to
decode each pixel is a context consisting of up to 16 previously
decoded pixels. These pixels are chosen according to a predefined
template placed relative to the location of the pixel to be
decoded (6.2.5.3 figures 3, 4, 5 and 6). There are four different
template that may be used (6.2.5.3). The template to use is
determined by GBTEMPLATE. GBTEMPLATE is set in the symbol
dictionary (6.5.8.1), generic region (7.4.6.4), or when decoding
a halftone region's gray-scale image (annex C.5).
Most of the pixels in each template have fixed locations relative
to the pixel to be decoded. However, all templates have at least
one adaptive pixel. The adaptive pixels have nominal locations,
but these locations may be changed by GBAT. GBAT is set in the
symbol dictionary (7.4.2.1.2), generic region (7.4.6.1), or hard
coded as for halftone patterns (6.7.5).
Adaptive pixels are restricted to fall within a field of
previously decoded pixels relative to the pixel to be decoded
(figure 7). The relative Y-coordinate for these adaptive pixels
may vary between -128 and 0. The relative X-coordinate may vary
between -128 and +127 (however, if the Y-coordinate is 0 the
range of the X-coordinate is further restricted to -128 to -1
since the pixels at locations 0 to +127 have not yet been
decoded). If a template refers to a pixel location that reside
outside of the image boundaries its value is assumed to be 0.
UNOPTIMIZED DECODER
The unoptimized decoders first check the contents of GBAT. If
GBAT specifies that any of the adaptive pixels reside outside the
allowed field the decoding is aborted. Next, each row is
processed top to bottom, left to right, one pixel at a time. For
each pixel a context is created containing the bit values of the
pixels that fall inside the template.
The order these bits are stored in the context is implementation
dependent (6.2.5.3). We store the bit values in the CONTEXT
variable from LSB to MSB, starting with the value of the pixel to
the left of the current pixel, continuing right to left, bottom
to top following the template. Using the CONTEXT created from
these pixel values, the arithmetic integer decoder retrieves the
pixel value, which is then written into the output image.
Example when GBTEMPLATE is 2:
The figure below represents a pixel grid of the output image.
Each pixel is a single bit in the image. The pixel "OO" in the
figure below is about to be decoded. The pixels "??" have not
been decoded yet. The CONTEXT variable is constructed by
combining the bit values from the pixels referred to by the
template, shifted to their corresponding bit position.
. . . . . . . .
. . . . . . . .
...+----+----+----+----+----+----+----+...
| | | X9 | X8 | X7 | | |
...+----+----+----+----+----+----+----+...
| | X6 | X5 | X4 | X3 | A1 | |
...+----+----+----+----+----+----+----+...
| | X2 | X1 | OO | ?? | ?? | ?? |
...+----+----+----+----+----+----+----+...
. . . . . . . .
. . . . . . . .
In the table below pixel OO is assumed to be at coordinate (x, y).
Bit 9: Pixel at location (x-1, y-2) (This is fixed pixel X9)
Bit 8: Pixel at location (x , y-2) (This is fixed pixel X8)
Bit 7: Pixel at location (x+1, y-2) (This is fixed pixel X7)
Bit 6: Pixel at location (x-2, y-1) (This is fixed pixel X6)
Bit 5: Pixel at location (x-1, y-1) (This is fixed pixel X5)
Bit 4: Pixel at location (x , y-1) (This is fixed pixel X4)
Bit 3: Pixel at location (x+1, y-1) (This is fixed pixel X3)
Bit 2: Pixel at location (x+2, y-1) (This is adaptive pixel A1)
Bit 1: Pixel at location (x-2, y ) (This is fixed pixel X2)
Bit 0: Pixel at location (x-1, y ) (This is fixed pixel X1)
The location of adaptive pixel A1 may not always be at the
nominal location (x+2, y-1). It could be at any pixel location to
the left or above OO as specified by GBAT, e.g. at the location
(x-128, y+127).
OPTIMIZED DECODER
The optimized decoders work differently. They strive to avoid
recreating the arithmetic integer decoder context from scratch
for every pixel decoded. Instead they reuse part of the CONTEXT
used to compute the previous pixel (the pixel to left of the one
now being decoded). They also keep two sliding windows of pixel
bit values from the two rows of pixels immediately above the
pixel to be decoded. These are stored in the 32-bit variables
line_m1 (row above the pixel to be decoded) and line_m2 (row
above that of line_m1). These optimized decoders ONLY work for
the nominal adaptive pixel locations since these locations are
hard-coded into the implementation.
The bit ordering in the CONTEXT variable is identical to the
unoptimized case described above.
The optimized decoders decode the output pixels one row at a
time, top to bottom. Within each row the pixels are decoded in
batches of up to eight pixels at a time (except possibly the
right most batch which may be less than eight pixels). The
batches in a row are decoded in sequence from left to right.
Within each such batch the pixels are decoded in sequence from
left to right.
Before decoding the pixels in a row the two sliding windows of
pixel values are reset. The first eight pixels of the row above
the pixel to be decoded is stored in line_m1, while line_m2
stores the first eight pixels of the row above that of line_m1.
The figure below illustrates the situation where the template has
been placed so that the decoded pixel OO is the very first pixel
of a row. It also gives labels to various pixels that we will
refer to below.
. . . . . . . . . . .
| . . . . . . . . . .
+ + +----+----+----+----+----+----+----+----+----+----+...
X9 | X8 | X7 | m1 | m2 | m3 | m4 | m5 | m6 | m7 | |
+ + +----+----+----+----+----+----+----+----+----+----+...
X6 X5 | X4 | X3 | A1 | n1 | n2 | n3 | n4 | n5 | n6 | n7 |
+ + +----+----+----+----+----+----+----+----+----+----+...
X2 X1 | OO | | | | | | | | | |
+ + +----+----+----+----+----+----+----+----+----+----+...
| . . . . . . . . . .
. . . . . . . . . . .
The pixels X1, X2, X5, X6 and X9 all reside outside the left edge
of the image. These pixels (like all others outside the image)
can according to 6.2.5.2 be assumed to be 0. line_m1 stores n5
through n1 as well as A1, and X3 through X6. line_m2 stores m6
through m1 as well as X7 through X9. The bits in line_m2 are also
shifted left four bits as seen below.
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | bit position
------------------------------------------------+------------------
0 0 0 0 0 0 X6 X5 X4 X3 A1 n1 n2 n3 n4 n5 | line_m1
0 0 0 X9 X8 X7 m1 m2 m3 m4 m5 m6 0 0 0 0 | line_m2
The way line_m1 and line_m2 are stored means we can simply shift
them by the same amount to move the sliding window.
The bit order in line_m1 and line_m2 matches the ordering in the
CONTEXT variable. Each bit for the 'A' and 'X' pixels in line_m1
and line_m2 correspond to the equivalent bits in CONTEXT, only
shifted right by 3 bits. Thus X3 is bit 3 in CONTEXT and bit 6 in
line_m1, etc.
The initial arithmetic integer decoder context is created and
stored in the CONTEXT variable by masking, shifting, and bitwise
ORing the contents of line_m1 and line_m2. The "CONTEXT contents"
row is only shown for clarity, it is not present in the code.
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | bit position
------------------------------------------------+---------------------------
0 0 0 0 0 0 0 0 0 X6 X5 X4 X3 A1 n1 n2 | line_m1 >> 3
0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 | mask for line_m1 (0x7c)
0 0 0 0 0 0 0 0 0 X6 X5 X4 X3 A1 0 0 | line_m1 AND mask
------------------------------------------------+---------------------------
0 0 0 0 0 0 X9 X8 X7 m1 m2 m3 m4 m5 m6 0 | line_m2 >> 3
0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 | mask for line_m2 (0x380)
0 0 0 0 0 0 X9 X8 X7 0 0 0 0 0 0 0 | line_m2 AND mask
------------------------------------------------+---------------------------
0 0 0 0 0 0 X9 X8 X7 X6 X5 X4 X3 A1 0 0 | CONTEXT = line_m1 OR line_m2
------------------------------------------------+---------------------------
0 0 0 0 0 0 X9 X8 X7 X6 X5 X4 X3 A1 X2 X1 | CONTEXT contents
Each batch is normally 8 bits, but at the right edge of the image
we may have fewer pixels to decode. The minor_width is how many
pixels the current batch should decode, with a counter variable
x_minor to keep track of the current pixel being decoded.
In order to process a new batch of pixels, unless we're at the
rightmost batch of pixels, we need to refill the sliding window
variables with eight new bits. Looking at the diagram above we
can see that in order to decode eight pixels starting with O0
we'll need to have bits up to pixel 'n7' for line_m1 and 'm7' for
line_m2 available (A1 and X7 moved right 7 times). To do this
simply and quickly, we shift line_m1 left by 8 bits, and OR in
the next byte from corresponding row. Likewise for line_m2, but
the next byte from the image is also shifted left by 4 bits to
compensate for line_m2 having the four least significant bits
unused.
These new eight bits contain the bit values of the eight pixels
to the right of those already present in line_m1 and line_m2. We
call these new bits m7 through mE, and n6 through nD, as
illustrated below.
23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | bit position
------------------------------------------------------------------------+-------------
0 0 0 0 0 0 0 0 0 0 0 0 0 0 X6 X5 X4 X3 A1 n1 n2 n3 n4 n5 | original line_m1
0 0 0 0 0 0 X6 X5 X4 X3 A1 n1 n2 n3 n4 n5 0 0 0 0 0 0 0 0 | line_m1 shifted left by 8
0 0 0 0 0 0 X6 X5 X4 X3 A1 n1 n2 n3 n4 n5 n6 n7 n8 n9 nA nB nC nD | line_m1 with new bits ORed in
------------------------------------------------------------------------+-------------
0 0 0 0 0 0 0 0 0 0 0 X9 X8 X7 m1 m2 m3 m4 m5 m6 0 0 0 0 | original line_m2
0 0 0 X9 X8 X7 m1 m2 m3 m4 m5 m6 0 0 0 0 0 0 0 0 0 0 0 0 | line_m2 shifted left by 8
0 0 0 X9 X8 X7 m1 m2 m3 m4 m5 m6 m7 m8 m9 mA mB mC mD mE 0 0 0 0 | line_m2 with new bits ORed in
. . . . . . . . . . . . . . . . . . . .
| . . . . . . . . . . . . . . . . . . .
+ + +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+...
X9 | X8 | X7 | m1 | m2 | m3 | m4 | m5 | m6 | m7 | m8 | m9 | mA | mB | mC | mD | mE | | | |
+ + +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+...
X6 X5 | X4 | X3 | A1 | n1 | n2 | n3 | n4 | n5 | n6 | n7 | n8 | n9 | nA | nB | nC | nD | | | |
+ + +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+...
X2 X1 | OO | | | | | | | | | | | | | | | | | | |
+ + +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+...
| . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
CONTEXT, line_m1 and line_m2 now contain all necessary bits to
decode a full batch of eight pixels.
The first pixel in the batch is decoded using this CONTEXT. After
that, for each following pixel we need to update the CONTEXT
using both the last decoded pixel value and new bits from line_m1
and line_m2.
. . . . . . . . . . . . . . . . . . . .
| . . . . . . . . . . . . . . . . . . .
+ + +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+...
(X9)|_X8_|_X7_|>m1<| m2 | m3 | m4 | m5 | m6 | m7 | m8 | m9 | mA | mB | mC | mD | mE | | | |
+ + +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+...
(X6) _X5_|_X4_|_X3_|_A1_|>n1<| n2 | n3 | n4 | n5 | n6 | n7 | n8 | n9 | nA | nB | nC | nD | | | |
+ + +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+...
(X2) _X1_|>OO<| oo | | | | | | | | | | | | | | | | | |
+ + +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+...
| . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
This figure illustrates what happens when the same template is
overlaid on itself shifted one pixel to the right in order to
decode the next pixel. Pixels marked with _ _ are pixels that
are present in both templates' CONTEXTs and can be reused. Pixels
marked with ( ) are pixels from the first template that are no
longer necessary and can be removed from CONTEXT. Pixels marked
with > < are new pixels that were not part of the original
CONTEXT, and so need to be moved into the CONTEXT at the
appropriate locations. In general the leftmost pixels of each
template row can be forgotten, while new pixels are needed at the
right most location of each row.
The CONTEXT corresponding to the current pixel OO and how it is
masked is shown below. Note how the left most pixel of each row
of the template is NOT propagated to the CONTEXT, these pixels
are X2, X6 and X9. This is done by having the mask being 0 at the
corresponding locations.
9 8 7 6 5 4 3 2 1 0 | bit position
------------------------------+-------------
X9 X8 X7 X6 X5 X4 X3 A1 X2 X1 | pixel values from CONTEXT
0 1 1 0 1 1 1 1 0 1 | reused pixel bit value mask (0x1bd)
0 X8 X7 0 X5 X4 X3 A1 0 X1 | reused pixel values from CONTEXT
Next the CONTEXT is shifted left by one bit to make it reference
the next pixel to be decoded. The pixel bit value we just decoded
is then written into the bit corresponding to X1. The sliding
windows in line_m1 and line_m2 are both shifted (10 - x_minor)
bits to the right to make the needed pixels' bit values appear at
the correct positions to be ORed into CONTEXT. Note that this
shift amount depends on which bit in the batch is currently being
computed, as is given by the x_minor counter. In the example
below we assume that x_minor is 0.
9 8 7 6 5 4 3 2 1 0 | bit position
------------------------------+--------------
0 X8 X7 0 X5 X4 X3 A1 0 0 | reused pixels from CONTEXT
X8 X7 0 X5 X4 X3 A1 0 0 0 | reused pixels shifted left 1 bit
------------------------------+--------------
X8 X7 0 X5 X4 X3 A1 0 X1 OO | new CONTEXT with current pixel at LSB
------------------------------+--------------
0 0 X6 X5 X4 X3 A1 n1 n2 n3 | line_m1 shifted (10 - x_minor) bits to the right
0 0 0 0 0 0 0 1 0 0 | mask for new adaptive pixel one row above (0x4)
X8 X7 0 X5 X4 X3 A1 n1 X1 OO | new CONTEXT with new adaptive pixel
------------------------------+--------------
X8 X7 m1 m2 m3 m4 m5 m6 m7 m8 | line_m2 with new bits ORed in
0 0 1 0 0 0 0 0 0 0 | mask for new pixel two rows above (0x80)
X8 X7 m1 X5 X4 X3 A1 n1 X1 OO | new CONTEXT with new pixel
This makes the computation of the new CONTEXT be:
NEWCONTEXT = (CONTEXT & 0x1bd) << 1
NEWCONTEXT |= newbit;
NEWCONTEXT |= (line_m1 >> (10-x_minor)) & 0x4;
NEWCONTEXT |= (line_m2 >> (10-x_minor)) & 0x80;
The optimized decoding functions for GBTEMPLATE 0, 1 and 3 all
work similarly. */
/* return the appropriate context size for the given template */
int
jbig2_generic_stats_size(Jbig2Ctx *ctx, int template)
{
int stats_size = template == 0 ? 1 << 16 : template == 1 ? 1 << 13 : 1 << 10;
return stats_size;
}
static int
jbig2_decode_generic_template0(Jbig2Ctx *ctx,
Jbig2Segment *segment,
const Jbig2GenericRegionParams *params, Jbig2ArithState *as,
Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
const uint32_t GBW = image->width;
const uint32_t GBH = image->height;
const uint32_t rowstride = image->stride;
uint32_t x, y;
byte *line2 = NULL;
byte *line1 = NULL;
byte *gbreg_line = (byte *) image->data;
#ifdef OUTPUT_PBM
printf("P4\n%d %d\n", GBW, GBH);
#endif
if (GBW <= 0)
return 0;
for (y = 0; y < GBH; y++) {
uint32_t CONTEXT;
uint32_t line_m1;
uint32_t line_m2;
uint32_t padded_width = (GBW + 7) & -8;
int code = 0;
line_m1 = line1 ? line1[0] : 0;
line_m2 = line2 ? line2[0] << 6 : 0;
CONTEXT = (line_m1 & 0x7f0) | (line_m2 & 0xf800);
/* 6.2.5.7 3d */
for (x = 0; x < padded_width; x += 8) {
byte result = 0;
int x_minor;
int minor_width = GBW - x > 8 ? 8 : GBW - x;
if (line1)
line_m1 = (line_m1 << 8) | (x + 8 < GBW ? line1[(x >> 3) + 1] : 0);
if (line2)
line_m2 = (line_m2 << 8) | (x + 8 < GBW ? line2[(x >> 3) + 1] << 6 : 0);
/* This is the speed-critical inner loop. */
for (x_minor = 0; x_minor < minor_width; x_minor++) {
bool bit;
bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code);
if (code)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template0 optimized");
result |= bit << (7 - x_minor);
CONTEXT = ((CONTEXT & 0x7bf7) << 1) | bit | ((line_m1 >> (7 - x_minor)) & 0x10) | ((line_m2 >> (7 - x_minor)) & 0x800);
}
gbreg_line[x >> 3] = result;
}
#ifdef OUTPUT_PBM
fwrite(gbreg_line, 1, rowstride, stdout);
#endif
line2 = line1;
line1 = gbreg_line;
gbreg_line += rowstride;
}
return 0;
}
#define pixel_outside_field(x, y) \
((y) < -128 || (y) > 0 || (x) < -128 || ((y) < 0 && (x) > 127) || ((y) == 0 && (x) >= 0))
static int
jbig2_decode_generic_template0_unopt(Jbig2Ctx *ctx,
Jbig2Segment *segment,
const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
const uint32_t GBW = image->width;
const uint32_t GBH = image->height;
uint32_t CONTEXT;
uint32_t x, y;
bool bit;
int code = 0;
if (pixel_outside_field(params->gbat[0], params->gbat[1]) ||
pixel_outside_field(params->gbat[2], params->gbat[3]) ||
pixel_outside_field(params->gbat[4], params->gbat[5]) ||
pixel_outside_field(params->gbat[6], params->gbat[7]))
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
"adaptive template pixel is out of field");
/* this version is generic and easy to understand, but very slow */
for (y = 0; y < GBH; y++) {
for (x = 0; x < GBW; x++) {
if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) {
jbig2_image_set_pixel(image, x, y, 0);
continue;
}
CONTEXT = 0;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y) << 0;
CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1;
CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2;
CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3;
CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4;
CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 1) << 5;
CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 6;
CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 7;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 8;
CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 9;
CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[2], y + params->gbat[3]) << 10;
CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[4], y + params->gbat[5]) << 11;
CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 12;
CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 2) << 13;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 14;
CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[6], y + params->gbat[7]) << 15;
bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code);
if (code)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template0 unoptimized");
jbig2_image_set_pixel(image, x, y, bit);
}
}
return 0;
}
static int
jbig2_decode_generic_template1_unopt(Jbig2Ctx *ctx,
Jbig2Segment *segment,
const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
const uint32_t GBW = image->width;
const uint32_t GBH = image->height;
uint32_t CONTEXT;
uint32_t x, y;
bool bit;
int code = 0;
if (pixel_outside_field(params->gbat[0], params->gbat[1]))
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
"adaptive template pixel is out of field");
/* this version is generic and easy to understand, but very slow */
for (y = 0; y < GBH; y++) {
for (x = 0; x < GBW; x++) {
if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) {
jbig2_image_set_pixel(image, x, y, 0);
continue;
}
CONTEXT = 0;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y) << 0;
CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1;
CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2;
CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 3;
CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 1) << 4;
CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 5;
CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 6;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 7;
CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 8;
CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 2) << 9;
CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 10;
CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 2) << 11;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 12;
bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code);
if (code)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template1 unoptimized");
jbig2_image_set_pixel(image, x, y, bit);
}
}
return 0;
}
static int
jbig2_decode_generic_template1(Jbig2Ctx *ctx,
Jbig2Segment *segment,
const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
const uint32_t GBW = image->width;
const uint32_t GBH = image->height;
const uint32_t rowstride = image->stride;
uint32_t x, y;
byte *line2 = NULL;
byte *line1 = NULL;
byte *gbreg_line = (byte *) image->data;
int code = 0;
#ifdef OUTPUT_PBM
printf("P4\n%d %d\n", GBW, GBH);
#endif
if (GBW <= 0)
return 0;
for (y = 0; y < GBH; y++) {
uint32_t CONTEXT;
uint32_t line_m1;
uint32_t line_m2;
uint32_t padded_width = (GBW + 7) & -8;
line_m1 = line1 ? line1[0] : 0;
line_m2 = line2 ? line2[0] << 5 : 0;
CONTEXT = ((line_m1 >> 1) & 0x1f8) | ((line_m2 >> 1) & 0x1e00);
/* 6.2.5.7 3d */
for (x = 0; x < padded_width; x += 8) {
byte result = 0;
int x_minor;
int minor_width = GBW - x > 8 ? 8 : GBW - x;
if (line1)
line_m1 = (line_m1 << 8) | (x + 8 < GBW ? line1[(x >> 3) + 1] : 0);
if (line2)
line_m2 = (line_m2 << 8) | (x + 8 < GBW ? line2[(x >> 3) + 1] << 5 : 0);
/* This is the speed-critical inner loop. */
for (x_minor = 0; x_minor < minor_width; x_minor++) {
bool bit;
bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code);
if (code)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template1 optimized");
result |= bit << (7 - x_minor);
CONTEXT = ((CONTEXT & 0xefb) << 1) | bit | ((line_m1 >> (8 - x_minor)) & 0x8) | ((line_m2 >> (8 - x_minor)) & 0x200);
}
gbreg_line[x >> 3] = result;
}
#ifdef OUTPUT_PBM
fwrite(gbreg_line, 1, rowstride, stdout);
#endif
line2 = line1;
line1 = gbreg_line;
gbreg_line += rowstride;
}
return 0;
}
static int
jbig2_decode_generic_template2_unopt(Jbig2Ctx *ctx,
Jbig2Segment *segment,
const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
const uint32_t GBW = image->width;
const uint32_t GBH = image->height;
uint32_t CONTEXT;
uint32_t x, y;
bool bit;
int code = 0;
if (pixel_outside_field(params->gbat[0], params->gbat[1]))
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
"adaptive template pixel is out of field");
/* this version is generic and easy to understand, but very slow */
for (y = 0; y < GBH; y++) {
for (x = 0; x < GBW; x++) {
if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) {
jbig2_image_set_pixel(image, x, y, 0);
continue;
}
CONTEXT = 0;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y) << 0;
CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1;
CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 2;
CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 3;
CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 4;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 5;
CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 6;
CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 7;
CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 2) << 8;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 9;
bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code);
if (code)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template2 unoptimized");
jbig2_image_set_pixel(image, x, y, bit);
}
}
return 0;
}
static int
jbig2_decode_generic_template2(Jbig2Ctx *ctx,
Jbig2Segment *segment,
const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
const uint32_t GBW = image->width;
const uint32_t GBH = image->height;
const uint32_t rowstride = image->stride;
uint32_t x, y;
byte *line2 = NULL;
byte *line1 = NULL;
byte *gbreg_line = (byte *) image->data;
int code = 0;
#ifdef OUTPUT_PBM
printf("P4\n%d %d\n", GBW, GBH);
#endif
if (GBW <= 0)
return 0;
for (y = 0; y < GBH; y++) {
uint32_t CONTEXT;
uint32_t line_m1;
uint32_t line_m2;
uint32_t padded_width = (GBW + 7) & -8;
line_m1 = line1 ? line1[0] : 0;
line_m2 = line2 ? line2[0] << 4 : 0;
CONTEXT = ((line_m1 >> 3) & 0x7c) | ((line_m2 >> 3) & 0x380);
/* 6.2.5.7 3d */
for (x = 0; x < padded_width; x += 8) {
byte result = 0;
int x_minor;
int minor_width = GBW - x > 8 ? 8 : GBW - x;
if (line1)
line_m1 = (line_m1 << 8) | (x + 8 < GBW ? line1[(x >> 3) + 1] : 0);
if (line2)
line_m2 = (line_m2 << 8) | (x + 8 < GBW ? line2[(x >> 3) + 1] << 4 : 0);
/* This is the speed-critical inner loop. */
for (x_minor = 0; x_minor < minor_width; x_minor++) {
bool bit;
bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code);
if (code)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template2 optimized");
result |= bit << (7 - x_minor);
CONTEXT = ((CONTEXT & 0x1bd) << 1) | bit | ((line_m1 >> (10 - x_minor)) & 0x4) | ((line_m2 >> (10 - x_minor)) & 0x80);
}
gbreg_line[x >> 3] = result;
}
#ifdef OUTPUT_PBM
fwrite(gbreg_line, 1, rowstride, stdout);
#endif
line2 = line1;
line1 = gbreg_line;
gbreg_line += rowstride;
}
return 0;
}
static int
jbig2_decode_generic_template3(Jbig2Ctx *ctx,
Jbig2Segment *segment,
const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
const uint32_t GBW = image->width;
const uint32_t GBH = image->height;
const uint32_t rowstride = image->stride;
byte *line1 = NULL;
byte *gbreg_line = (byte *) image->data;
uint32_t x, y;
int code;
#ifdef OUTPUT_PBM
printf("P4\n%d %d\n", GBW, GBH);
#endif
if (GBW <= 0)
return 0;
for (y = 0; y < GBH; y++) {
uint32_t CONTEXT;
uint32_t line_m1;
uint32_t padded_width = (GBW + 7) & -8;
line_m1 = line1 ? line1[0] : 0;
CONTEXT = (line_m1 >> 1) & 0x3f0;
/* 6.2.5.7 3d */
for (x = 0; x < padded_width; x += 8) {
byte result = 0;
int x_minor;
int minor_width = GBW - x > 8 ? 8 : GBW - x;
if (line1)
line_m1 = (line_m1 << 8) | (x + 8 < GBW ? line1[(x >> 3) + 1] : 0);
/* This is the speed-critical inner loop. */
for (x_minor = 0; x_minor < minor_width; x_minor++) {
bool bit;
bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code);
if (code)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template3 optimized");
result |= bit << (7 - x_minor);
CONTEXT = ((CONTEXT & 0x1f7) << 1) | bit | ((line_m1 >> (8 - x_minor)) & 0x10);
}
gbreg_line[x >> 3] = result;
}
#ifdef OUTPUT_PBM
fwrite(gbreg_line, 1, rowstride, stdout);
#endif
line1 = gbreg_line;
gbreg_line += rowstride;
}
return 0;
}
static int
jbig2_decode_generic_template3_unopt(Jbig2Ctx *ctx,
Jbig2Segment *segment,
const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
const uint32_t GBW = image->width;
const uint32_t GBH = image->height;
uint32_t CONTEXT;
uint32_t x, y;
bool bit;
int code = 0;
if (pixel_outside_field(params->gbat[0], params->gbat[1]))
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
"adaptive template pixel is out of field");
/* this version is generic and easy to understand, but very slow */
for (y = 0; y < GBH; y++) {
for (x = 0; x < GBW; x++) {
if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) {
jbig2_image_set_pixel(image, x, y, 0);
continue;
}
CONTEXT = 0;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y) << 0;
CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1;
CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2;
CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3;
CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4;
CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 5;
CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 6;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 7;
CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 8;
CONTEXT |= jbig2_image_get_pixel(image, x - 3, y - 1) << 9;
bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code);
if (code)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template3 unoptimized");
jbig2_image_set_pixel(image, x, y, bit);
}
}
return 0;
}
static void
copy_prev_row(Jbig2Image *image, int row)
{
if (!row) {
/* no previous row */
memset(image->data, 0, image->stride);
} else {
/* duplicate data from the previous row */
uint8_t *src = image->data + (row - 1) * image->stride;
memcpy(src + image->stride, src, image->stride);
}
}
static int
jbig2_decode_generic_template0_TPGDON(Jbig2Ctx *ctx,
Jbig2Segment *segment,
const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
const uint32_t GBW = image->width;
const uint32_t GBH = image->height;
uint32_t CONTEXT;
uint32_t x, y;
bool bit;
int LTP = 0;
int code = 0;
if (pixel_outside_field(params->gbat[0], params->gbat[1]) ||
pixel_outside_field(params->gbat[2], params->gbat[3]) ||
pixel_outside_field(params->gbat[4], params->gbat[5]) ||
pixel_outside_field(params->gbat[6], params->gbat[7]))
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
"adaptive template pixel is out of field");
for (y = 0; y < GBH; y++) {
LTP ^= jbig2_arith_decode(as, &GB_stats[0x9B25], &code);
if (code)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template0 TPGDON1");
if (!LTP) {
for (x = 0; x < GBW; x++) {
if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) {
jbig2_image_set_pixel(image, x, y, 0);
continue;
}
CONTEXT = jbig2_image_get_pixel(image, x - 1, y);
CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1;
CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2;
CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3;
CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4;
CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 1) << 5;
CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 6;
CONTEXT |= jbig2_image_get_pixel(image, x, y - 1) << 7;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 8;
CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 9;
CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[2], y + params->gbat[3]) << 10;
CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[4], y + params->gbat[5]) << 11;
CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 12;
CONTEXT |= jbig2_image_get_pixel(image, x, y - 2) << 13;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 14;
CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[6], y + params->gbat[7]) << 15;
bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code);
if (code)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template0 TPGDON2");
jbig2_image_set_pixel(image, x, y, bit);
}
} else {
copy_prev_row(image, y);
}
}
return 0;
}
static int
jbig2_decode_generic_template1_TPGDON(Jbig2Ctx *ctx,
Jbig2Segment *segment,
const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
const uint32_t GBW = image->width;
const uint32_t GBH = image->height;
uint32_t CONTEXT;
uint32_t x, y;
bool bit;
int LTP = 0;
int code = 0;
if (pixel_outside_field(params->gbat[0], params->gbat[1]))
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
"adaptive template pixel is out of field");
for (y = 0; y < GBH; y++) {
LTP ^= jbig2_arith_decode(as, &GB_stats[0x0795], &code);
if (code)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template1 TPGDON1");
if (!LTP) {
for (x = 0; x < GBW; x++) {
if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) {
jbig2_image_set_pixel(image, x, y, 0);
continue;
}
CONTEXT = jbig2_image_get_pixel(image, x - 1, y);
CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1;
CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2;
CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 3;
CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 1) << 4;
CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 5;
CONTEXT |= jbig2_image_get_pixel(image, x, y - 1) << 6;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 7;
CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 8;
CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 2) << 9;
CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 10;
CONTEXT |= jbig2_image_get_pixel(image, x, y - 2) << 11;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 12;
bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code);
if (code)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template1 TPGDON2");
jbig2_image_set_pixel(image, x, y, bit);
}
} else {
copy_prev_row(image, y);
}
}
return 0;
}
static int
jbig2_decode_generic_template2_TPGDON(Jbig2Ctx *ctx,
Jbig2Segment *segment,
const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
const uint32_t GBW = image->width;
const uint32_t GBH = image->height;
uint32_t CONTEXT;
uint32_t x, y;
bool bit;
int LTP = 0;
int code = 0;
if (pixel_outside_field(params->gbat[0], params->gbat[1]))
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
"adaptive template pixel is out of field");
for (y = 0; y < GBH; y++) {
LTP ^= jbig2_arith_decode(as, &GB_stats[0xE5], &code);
if (code)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template2 TPGDON1");
if (!LTP) {
for (x = 0; x < GBW; x++) {
if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) {
jbig2_image_set_pixel(image, x, y, 0);
continue;
}
CONTEXT = jbig2_image_get_pixel(image, x - 1, y);
CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1;
CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 2;
CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 3;
CONTEXT |= jbig2_image_get_pixel(image, x, y - 1) << 4;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 5;
CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 6;
CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 7;
CONTEXT |= jbig2_image_get_pixel(image, x, y - 2) << 8;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 9;
bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code);
if (code)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template2 TPGDON2");
jbig2_image_set_pixel(image, x, y, bit);
}
} else {
copy_prev_row(image, y);
}
}
return 0;
}
static int
jbig2_decode_generic_template3_TPGDON(Jbig2Ctx *ctx,
Jbig2Segment *segment,
const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
const uint32_t GBW = image->width;
const uint32_t GBH = image->height;
uint32_t CONTEXT;
uint32_t x, y;
bool bit;
int LTP = 0;
int code = 0;
if (pixel_outside_field(params->gbat[0], params->gbat[1]))
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
"adaptive template pixel is out of field");
for (y = 0; y < GBH; y++) {
LTP ^= jbig2_arith_decode(as, &GB_stats[0x0195], &code);
if (code)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template3 TPGDON1");
if (!LTP) {
for (x = 0; x < GBW; x++) {
if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) {
jbig2_image_set_pixel(image, x, y, 0);
continue;
}
CONTEXT = jbig2_image_get_pixel(image, x - 1, y);
CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1;
CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2;
CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3;
CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4;
CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 5;
CONTEXT |= jbig2_image_get_pixel(image, x, y - 1) << 6;
CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 7;
CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 8;
CONTEXT |= jbig2_image_get_pixel(image, x - 3, y - 1) << 9;
bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code);
if (code)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template3 TPGDON2");
jbig2_image_set_pixel(image, x, y, bit);
}
} else {
copy_prev_row(image, y);
}
}
return 0;
}
static int
jbig2_decode_generic_region_TPGDON(Jbig2Ctx *ctx,
Jbig2Segment *segment,
const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
switch (params->GBTEMPLATE) {
case 0:
return jbig2_decode_generic_template0_TPGDON(ctx, segment, params, as, image, GB_stats);
case 1:
return jbig2_decode_generic_template1_TPGDON(ctx, segment, params, as, image, GB_stats);
case 2:
return jbig2_decode_generic_template2_TPGDON(ctx, segment, params, as, image, GB_stats);
case 3:
return jbig2_decode_generic_template3_TPGDON(ctx, segment, params, as, image, GB_stats);
}
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unsupported GBTEMPLATE (%d)", params->GBTEMPLATE);
}
/**
* jbig2_decode_generic_region: Decode a generic region.
* @ctx: The context for allocation and error reporting.
* @segment: A segment reference for error reporting.
* @params: Decoding parameter set.
* @as: Arithmetic decoder state.
* @image: Where to store the decoded data.
* @GB_stats: Arithmetic stats.
*
* Decodes a generic region, according to section 6.2. The caller should
* pass an already allocated Jbig2Image object for @image
*
* Because this API is based on an arithmetic decoding state, it is
* not suitable for MMR decoding.
*
* Return code: 0 on success.
**/
int
jbig2_decode_generic_region(Jbig2Ctx *ctx,
Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
const int8_t *gbat = params->gbat;
if (image->stride * image->height > (1 << 26) && segment->data_length < image->stride * image->height / (1 << 16)) {
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
"region is far larger than data provided (%d << %d), aborting to prevent DOS", segment->data_length, image->stride * image->height);
}
if (!params->MMR && params->TPGDON)
return jbig2_decode_generic_region_TPGDON(ctx, segment, params, as, image, GB_stats);
if (!params->MMR && params->GBTEMPLATE == 0) {
if (!params->USESKIP && gbat[0] == +3 && gbat[1] == -1 && gbat[2] == -3 && gbat[3] == -1 && gbat[4] == +2 && gbat[5] == -2 && gbat[6] == -2 && gbat[7] == -2)
return jbig2_decode_generic_template0(ctx, segment, params, as, image, GB_stats);
else
return jbig2_decode_generic_template0_unopt(ctx, segment, params, as, image, GB_stats);
} else if (!params->MMR && params->GBTEMPLATE == 1) {
if (!params->USESKIP && gbat[0] == +3 && gbat[1] == -1)
return jbig2_decode_generic_template1(ctx, segment, params, as, image, GB_stats);
else
return jbig2_decode_generic_template1_unopt(ctx, segment, params, as, image, GB_stats);
}
else if (!params->MMR && params->GBTEMPLATE == 2) {
if (!params->USESKIP && gbat[0] == 2 && gbat[1] == -1)
return jbig2_decode_generic_template2(ctx, segment, params, as, image, GB_stats);
else
return jbig2_decode_generic_template2_unopt(ctx, segment, params, as, image, GB_stats);
} else if (!params->MMR && params->GBTEMPLATE == 3) {
if (!params->USESKIP && gbat[0] == 2 && gbat[1] == -1)
return jbig2_decode_generic_template3(ctx, segment, params, as, image, GB_stats);
else
return jbig2_decode_generic_template3_unopt(ctx, segment, params, as, image, GB_stats);
}
{
int i;
for (i = 0; i < 8; i++)
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "gbat[%d] = %d", i, params->gbat[i]);
}
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unsupported generic region (MMR=%d, GBTEMPLATE=%d)", params->MMR, params->GBTEMPLATE);
}
/**
* Handler for immediate generic region segments
*/
int
jbig2_immediate_generic_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data)
{
Jbig2RegionSegmentInfo rsi;
byte seg_flags;
int8_t gbat[8];
int offset;
uint32_t gbat_bytes = 0;
Jbig2GenericRegionParams params;
int code = 0;
Jbig2Image *image = NULL;
Jbig2WordStream *ws = NULL;
Jbig2ArithState *as = NULL;
Jbig2ArithCx *GB_stats = NULL;
uint32_t height;
Jbig2Page *page = &ctx->pages[ctx->current_page];
/* 7.4.6 */
if (segment->data_length < 18)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
jbig2_get_region_segment_info(&rsi, segment_data);
jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "generic region: %u x %u @ (%u, %u), flags = %02x", rsi.width, rsi.height, rsi.x, rsi.y, rsi.flags);
/* 7.4.6.4 */
height = rsi.height;
if (segment->rows != UINT32_MAX) {
if (segment->rows > rsi.height)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment contains more rows than stated in header");
height = segment->rows;
}
/* 7.4.6.2 */
seg_flags = segment_data[17];
jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "segment flags = %02x", seg_flags);
if ((seg_flags & 1) && (seg_flags & 6))
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "MMR is 1, but GBTEMPLATE is not 0");
/* 7.4.6.3 */
if (!(seg_flags & 1)) {
gbat_bytes = (seg_flags & 6) ? 2 : 8;
if (18 + gbat_bytes > segment->data_length)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
memcpy(gbat, segment_data + 18, gbat_bytes);
jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "gbat: %d, %d", gbat[0], gbat[1]);
}
offset = 18 + gbat_bytes;
/* Check for T.88 amendment 2 */
if ((seg_flags >> 5) & 1)
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment uses 12 adaptive template pixels (NYI)");
/* Table 34 */
params.MMR = seg_flags & 1;
params.GBTEMPLATE = (seg_flags & 6) >> 1;
params.TPGDON = (seg_flags & 8) >> 3;
params.USESKIP = 0;
memcpy(params.gbat, gbat, gbat_bytes);
if (page->height == 0xffffffff && page->striped && page->stripe_size > 0) {
if (rsi.y >= page->end_row + page->stripe_size) {
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "ignoring %u x %u region at (%u, %u) outside of stripe at row %u covering %u rows, on page of height %u", rsi.width, rsi.height, rsi.x, rsi.y, page->end_row, page->stripe_size, page->image->height);
return 0;
}
if (height > page->end_row + page->stripe_size) {
height = page->end_row + page->stripe_size;
}
} else {
if (rsi.y >= page->height) {
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "ignoring %u x %u region at (%u, %u) outside of page of height %u", rsi.width, rsi.height, rsi.x, rsi.y, page->height);
return 0;
}
if (height > page->height - rsi .y) {
height = page->height - rsi.y;
}
}
if (height == 0) {
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "nothing remains of region, ignoring");
return 0;
}
image = jbig2_image_new(ctx, rsi.width, height);
if (image == NULL)
return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate generic image");
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "allocated %d x %d image buffer for region decode results", rsi.width, height);
if (params.MMR) {
code = jbig2_decode_generic_mmr(ctx, segment, ¶ms, segment_data + offset, segment->data_length - offset, image);
if (code < 0) {
code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode MMR-coded generic region");
goto cleanup;
}
} else {
int stats_size = jbig2_generic_stats_size(ctx, params.GBTEMPLATE);
GB_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
if (GB_stats == NULL) {
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate arithmetic decoder states when handling immediate generic region");
goto cleanup;
}
memset(GB_stats, 0, stats_size);
ws = jbig2_word_stream_buf_new(ctx, segment_data + offset, segment->data_length - offset);
if (ws == NULL) {
code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocated word stream when handling immediate generic region");
goto cleanup;
}
as = jbig2_arith_new(ctx, ws);
if (as == NULL) {
code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate arithmetic coding state when handling immediate generic region");
goto cleanup;
}
code = jbig2_decode_generic_region(ctx, segment, ¶ms, as, image, GB_stats);
if (code < 0) {
code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode immediate generic region");
goto cleanup;
}
}
code = jbig2_page_add_result(ctx, &ctx->pages[ctx->current_page], image, rsi.x, rsi.y, rsi.op);
if (code < 0)
code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to add result to page");
cleanup:
jbig2_free(ctx->allocator, as);
jbig2_word_stream_buf_free(ctx, ws);
jbig2_free(ctx->allocator, GB_stats);
jbig2_image_release(ctx, image);
return code;
}
|