From fbaaced9e95a65d29a1772175ff909b36f9af9dd Mon Sep 17 00:00:00 2001 From: Packit Date: Sep 14 2020 09:58:54 +0000 Subject: jbigkit-2.1 base --- diff --git a/ANNOUNCE b/ANNOUNCE new file mode 100644 index 0000000..15ce550 --- /dev/null +++ b/ANNOUNCE @@ -0,0 +1,172 @@ + +JBIG-KIT lossless image compression library +------------------------------------------- + +by Markus Kuhn + + +The latest release of JBIG-KIT can be downloaded from + + http://www.cl.cam.ac.uk/~mgk25/jbigkit/ + +JBIG-KIT implements a highly effective data compression algorithm for +bi-level high-resolution images such as fax pages or scanned +documents. + +JBIG-KIT provides two variants of a portable library of compression +and decompression functions with a documented interface. You can very +easily include into your image or document processing software. In +addition, JBIG-KIT provides ready-to-use compression and decompression +programs with a simple command line interface (similar to the +converters found in Jef Poskanzer's PBM graphics file conversion +package). + +JBIG-KIT implements the specification + + International Standard ISO/IEC 11544:1993 and ITU-T Recommendation + T.82(1993), "Information technology - Coded representation of picture + and audio information - progressive bi-level image compression", + , + +which is commonly referred to as the "JBIG1 standard". JBIG (Joint +Bi-level Image experts Group) is the committee which developed this +international standard for the lossless compression of images using +arithmetic coding. Like the well-known compression algorithms JPEG and +MPEG, JBIG has also been developed and published by the International +Organization for Standardization (ISO) and the International +Telecommunication Union (ITU). See also + + http://www.jpeg.org/jbig/ + http://www.iso.ch/ + http://www.itu.int/ + +The JBIG compression algorithm offers the following features: + + - Close to state-of-the-art lossless compression ratio for high + resolution bi-level images. + + - About 1.1 to 1.5 times better compression ratio on typical + scanned documents compared to G4 fax compression (ITU-T T.6), + which has been the best compression algorithm for scanned + documents available prior to JBIG. + + - Up to 30 times better compression of scanned images with dithered + images compared to G4 fax compression. + + - About 2 times better compression on typical 300 dpi documents + compared to 'gzip -9' on raw bitmaps. + + - About 3-4 times better compression than GIF on typical 300 dpi + documents. + + - Even much better competitive compression results on computer + generated images which are free of scanning distortions. + + - JBIG supports hierarchical "progressive" encoding, that means it is + possible to encode a low resolution image first, followed by + resolution enhancement data. This allows, for instance, a document + browser to display already a good 75 dpi low resolution version of + an image, while the data necessary to reconstruct the full 300 dpi + version for laser printer reproduction is still arriving (say + over a slow network link or mass storage medium). + + - The various resolution layers of a JBIG image in progressive + encoding mode together require not much more space than a + normal non-progressive mode encoded image (which JBIG also + supports). + + - The progressive encoding mode utilizes a quite sophisticated + resolution reduction algorithm which offers high quality low + resolution versions that preserve the shape of characters as well + as the integrity of thin lines and dithered images. + + - JBIG supports multiple bit planes and can this way also be used + for grayscale and color images, although the main field of + application is compression of bi-level images, i.e. images with + only two different pixel values. For grayscale images with up to + 6 bit per pixel, JBIG performs superior to JPEG's lossless + mode. + +JBIG-KIT can be used as free software under the GNU General Public +License. Other license arrangements more suitable for commercial +applications are available as well, please contact the author for +details. JBIG-KIT provides two portable libraries implemented in +ANSI/ISO C for encoding and decoding JBIG data streams, along with +documentation. The first library, jbig.c, implements nearly all of the +options that the JBIG standard provides, but keeps the entire +uncompressed image in memory. The second library, jbig85.c, implements +only the ITU-R T.85 subset of the standard that black/white fax +machines use (single bit per pixel, no "progressive" encoding), and +keeps only three lines of the uncompressed image in memory, making it +particularly attractive for low-memory embedded applications. + +The libraries are not intended for 8-bit or 16-bit machine +architectures (e.g., old MS-DOS C compilers). For maximum performance, +a 32-bit processor is required (64-bit systems work too, of course). +On architectures with 16-bit pointer arithmetic, the full-featured +jbig.c library can process only very small images. + +Special features of the full-featured jbig.c variant: + + - Fully reentrant multithread-capable design (no global or static + variables, isolated malloc()/free() calls, etc.) + + - Capable of handling incomplete and growing JBIG data streams in + order to allow earliest display of low resolution versions + + - Capable of handling several incoming data streams simultaneously + in one single process and thread + + - Especially designed with applications in mind that want to display + incoming data as early as possible (e.g., similar to the way in + which Netscape Navigator handles incoming GIF images) + + - Implements all JBIG features and options including progressive and + sequential encoding, multiple bit planes, user specified + resolution reduction and deterministic prediction tables, adaptive + template changes for optimal performance on half-tone images, + deterministic prediction, typical prediction in lowest and + differential layers, various stripe orderings, etc; only the SEQ + and HITOLO options are currently not supported by the decoder + (they are normally never required, but could be added later in + case of user requirements) + + - Suitable for fax applications, satisfies ITU-T T.85 profile + + - Efficient code, optimized utilization of 32-bit processor + registers + + - Very easy to use documented C library interface + + - Included Gray code conversion routines for efficient encoding + of grayscale images + + - Ready-to-use pbmtojbg and jbgtopbm converters. + +Special features of the light-weight jbig85.c variant: + + - Suitable for low-memory embedded applications + + - Implements only the JBIG1 subset defined in the ITU-T T.85 + profile (single bit plane, no differential layers) + + - Requires only three pixel rows of the uncompressed image to be + kept in memory + + - Handles all NEWLEN modes of operation required by ITU-T T.85 with + just a single pass over the data, automatically performing the + necessary lookahead after the last stripe + + - Codec buffers only a few bytes of arithmetic-codec data and outputs + resulting bytes or lines as soon as they are available. + +I will try to provide free support and maintenance for this software +for the foreseeable future, depending on my available time. + +Happy compressing ... + +Markus Kuhn + +-- +Markus Kuhn, Computer Laboratory, University of Cambridge +http://www.cl.cam.ac.uk/~mgk25/ || CB3 0FD, Great Britain diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..2b766c8 --- /dev/null +++ b/CHANGES @@ -0,0 +1,237 @@ + +JBIG-KIT revision history +------------------------- + +Changes in version 2.1 (2014-04-08) + +This is a security-critical bug-fix release that remains API and ABI +backwards compatible to version 2.0. Users who process BIE data from +untrusted sources should upgrade. + + - fixed a buffer-overflow vulnerability in the jbig.c decoder, + reported by Florian Weimer (Red Hat): CVE-2013-6369 + + - fixed ability of corrupted input data to force jbig85.c decoder + into an end-less loop + + - fixed a bug in the processing of private deterministic-prediction + tables (DPPRIV=1) in jbig.c decoder + + - fixed integer-type mismatches in printf arguments on 64-bit systems + + - fuzz-testing script added + +Changes in version 2.0 (2008-08-30) + +Main new features of release 2.0: + + - This release adds a separate lightweight "T.85" version of the + encoder and decoder library (jbig85.c, jbig85.h). This new T.85 + library is optimized for embedded low-memory applications, such as + printers and fax machines. It implements only the subset of the + JBIG standard that is required by the ITU-T T.85 fax profile, + namely only a single bit plane (P = 1) and no differential layers + (DL = D = HITOLO = SEQ = ILEAVE = SMID = TPDON = DPON = DPON = + DPLAST = 0) and some other restrictions (MY = 0, MX < 128). + + The T.85 library requires only three pixel rows of the + uncompressed image to reside in memory at any time. This 3-line + buffer has to be allocated by the calling application, therefore + the T.85 library will not call any heap management functions such + as malloc() or free() itself. + + - There are also two new example applications pbmtojbg85 and + jbgtopbm85 included that provide command-line access to the new + T.85 library. (Note to distribution maintainers: there is probably + little point in adding pbmtojbg85 and jbgtopbm85 to precompiled + JBIG-KIT packages for workstation operating systems, as these two + programs do not really provide the end user much additional + functionality beyond what pbmtojbg and jbgtopbm already do, which + use the full library instead.) + +Changes to the original full jbig.c library from version 1.6: + + - the arithmetic codec routines are now located in a separate source + file (they are now used by both the full library jbig.c and the new + T.85 library jbig85.c, and might also be of use to other applications) + + - arithmetic decoder behaviour slightly changed to enable the + lookahead needed to handle T.85-style NEWLEN after the final + stripe + + - added encoder support for adding comment marker segment + + - added encoder option for using SDRST marker instead of SDNORM + (only useful to make encoder able to generate a wider range + of test data) + + - added pbmtojbg options -C and -r, which provide command-line + access to the previous two extensions + + - slightly improved diagnostic output of jbgtopbm option -d + + - non-English translations of error messages are now provided + in a separate PO file (e.g., for use with GNU gettext), + jbg_strerror() no longer has a language attribute and the + JBG_EN, JBG_DE_8859_1, JBG_DE_UTF_8 constants no longer exist + + - jbg_dec_in() return values changed; the least significant bits of + the error codes now provide more information about what caused the + error, beyond what the more general error text messages returned by + jbg_strerror() reveal + + - pbmtojbg has a new option -f as a shortcut for all the options + needed to make the output comply to the basic ITU-T T.85 fax + profile + + - jbg_dec_getwidth(), jbg_dec_getheight(), jbg_dec_getsize(), and + jbg_dec_getsize_merged() return now an unsigned long value + (was: long), and return 0 (was: -1) if no image is available yet + + - jbgtopbm now outputs image dimensions in header padded to 10 + digits fixed width, for consistency with jbgtopbm85 + to allow for later in-place update of height due to NEWLEN + + - macro JBG_LICENCE can be changed from the default value "GPL" to a + licence agreement reference code to if the library is used under a + commercial licence, to clarify under which exact licence the + library is used in a particular application + +Changes in version 1.6 (2004-06-11) + + - various small changes to reduce the risk of 32-bit unsigned + integer overflows when dealing with extremely large images + + - robuster treatment of L0 = 0xffffffff + + - minor API modification in jbg_enc_options(): parameter l0 changed + from type long to unsigned long; previous value now remains + unchanged when l0 == 0 (was: l0 < 0) + + - lots of type casts added such that the C source code is now + also compilable as C++ + +Changes in version 1.5 (2003-06-11) + + - fixed two minor memory leaks (special thanks to Davide Pizzolato + for locating one of these) + + - jbgtopbm does not attempt any more to parse multiple concatenated + BIEs (options -m must be used now to enable this feature explicitly), + in order to handle BIEs with data after the last expected SDE gracefully + + - various extensions to improve support of JBIG fax applications + (ITU-T T.85 profile): + + o support for maximum adaptive template pixel offset increased + to MX=127 in both encoder and decoder + + o encoder now has a hook for producing BIEs with a NEWLEN marker + segment and VLENGTH=1, in order to assist in testing decoders + for T.85 conformance (see also new pbmtojbg option -Y) + + o a new function jbg_newlen() can be used to scan an + entire in-memory BIE for NEWLEN marker segments and update the + YD value in the BIE header, which can be applied to BIE data + before passing it to the decoder for T.85 compliance + (Background: the incremental design of the JBIG-KIT decoder + makes it infeasible to look ahead for NEWLEN marker segments + that occur after the SDE with the last image line, therefore + this second pass is necessary to handle the old-style fax + applications permitted by T.85 in which the low-RAM encoder + doesn't know the height of the image at the start of + transmission) + +Changes in version 1.4 (2002-04-09) + + - typo fixed in stripe number calculation, which caused encoder and + decoder to fail on certain image sizes (special thanks to Koen Denecker + for locating this one) + +Changes in version 1.3 (2002-03-23): + + - bugs fixed in jbg_split_planes(), jbg_dec_merge_planes() that + caused a failure for more than eight planes per pixel + + - example converters now can handle PGM files with up to 32 bits + per pixel + +Changes in version 1.2 (2000-04-08): + + - bug in the decoder fixed, which caused the rest of the input file + to be skipped whenever a comment marker was encountered (special + thanks to Ben Rudiak-Gould for + reporting this one) + +Changes in version 1.1 (1999-11-16): + + - serious bug in the encoder fixed, which for a very small + percentage of images has caused an unterminated linked list to be + created internally that could have been responsible for + segmentation violations or non-terminating encoders + (special thanks to Hisashi Saiga for + tracking that one down) + + - minor bug in the "jbgtopbm -d" diagnostic output fixed + +Changes in version 1.0 (1998-04-11): + + - two bugs fixed that caused the encoder and decoder to fail + under certain modes of operation with several bit planes + + - added new functions jbg_split_planes(), jbg_dec_merge_planes(), + and jbg_dec_getsize_merged() for easy handling of grayscale + images + + - added support for compressing grayscale PGM files to pbmtojbg + and jbgtopbm + + - more changes to avoid paranoid compiler warnings + +Changes in version 0.9 (1996-01-09): + + - encoder won't break any more on input bitmap data with incorrect + zero padding + + - pbmtojbg displays a warning if input file has incorrect zero + padding + + - various minor improvements suggested by Stefan Willer + + + - many minor changes in order to avoid warnings from paranoid + compilers + +Changes in version 0.8 (1995-09-20): + + - namespace cleared up, all names externally visible from the library + start now with jbg_ or JBG_ + + - minor non-critical bug fixed which caused library to fail compatibility + test and showed up especially on DEC Alpha systems + + - jbg_dec_gethight() is now called jbg_dec_getheight() + + - filenames conform now to MS-DOS limits + + - Bug in pbmtojbg fixed (handling of ASCII PBM files) + +Changes in version 0.7 (1995-06-10): + + - more problems on 16-bit int systems and on Macintosh systems fixed + (special thanks to Jean-Pierre Gachen ) + + - global Makefile + +Changes in version 0.6 (1995-06-08): + + - memory leak fixed + + - should now also work on systems where int is only 16-bit large + + - changes of the JBIG "Technical Corrigendum 1" included (special + thanks to Dr. Sebestyen from Siemens AG for sending me a copy + of the draft) + +First release: version 0.5 (1995-05-28) + diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..45d68f5 --- /dev/null +++ b/INSTALL @@ -0,0 +1,163 @@ + +Getting started with JBIG-KIT +----------------------------- + +Markus Kuhn -- 2014-03-27 + + +JBIG-KIT is a portable C library that should work on any platform with +an ANSI/ISO C compiler, such as GNU gcc. + +To get started, compile the demonstration software in pbmtools/ and +test it with some of the provided example files. + +On a Unix system, check Makefile to suit your compiler, then start +"make". If libjbig.a and/or libjbig85.a have been produced correctly, +then activate the automatic library test suite with "make test", or +just start libjbig/tstcodec and libjbig/tstcodec85. If these tests +fail, please do let me know. + +On other operating systems, just link libjbig/jbig.c and +libjbig/jbig_ar.c together with any application in which you want to +use the full JBIG-KIT library. Likewise, just link libjbig/jbig85.c +and libjbig/jbig_ar.c together with any application in which you want +to use the simpler variant optimized for fax applications. + +In subdirectory pbmtools/, you will find the programs pbmtojbg and +jbgtopbm. These are two file converters, serving as examples for +applications that use the full JBIG-KIT library (jbig.c). After +testing them on some of the example JBIG files, you can move these +executable files together with their respective man pages (in a UNIX +style environment) to the appropriate directories. Options -h and +--help will give you short command-line usage summaries. The programs +pbmtojbg85 and jbgtopbm85 are very similar, but demonstrate use of the +simpler jbig85.c library instead. + +The subdirectory examples/ contains a few files as raw JBIG data +streams (called bi-level image entities (BIE) in the standard). + +Try + + jbgtopbm ccitt1.jbg ccitt1.pbm + +to decompress CCITT test letter #1 into a portable bitmap file, which +you can then further convert using Jef Poskanzer's PBM tools +, or view with many popular +image file viewers, such as the "display" command from ImageMagick. + +The ccitt1.jbg image is 1728 x 2376 pixels large and may not fit onto +your display screen. However, fortunately, I have stored it in JBIG's +"progressive mode" with the following resolution layers: + + layer 0: 216 x 297 pixel + layer 1: 432 x 594 pixel + layer 2: 864 x 1188 pixel + layer 3: 1728 x 2376 pixel + +In progressive mode, each layer has twice the resolution of the +previous one. Resolution layer 0 encodes all its pixels independent +from any other data; all other resolution layers encode only the +difference between the previous and the new resolution layer, which +requires much less space than encoding resolution layers without +referring to the lower layer. By default, the BIE files produced by +pbmtojbg will all start with a lowest resolution layer 0 that fits +onto a 640 x 480 screen. + +In order to tell jbgtopbm that you do not want to decode higher +resolution layers if they will not fit onto your (say) 1024 x 768 +pixel display, simply use + + jbgtopbm -x 1024 -y 768 ccitt1.jbg ccitt1.pbm + +You will get a 4 times smaller image, the highest resolution layer +that still fits onto your screen. You can also directly pipe the image +to another application using standard output, by removing the second +file name, e.g. + + jbgtopbm -x 1024 -y 768 ccitt1.jbg | display + +In fact, the data in the first quarter of the input file is sufficient +to decode the requested resolution: + + head --bytes=4000 ccitt1.jbg | ../pbmtools/jbgtopbm -x 1024 -y 768 | display + +Now let's do some compression. With + + jbgtopbm ccitt1.jbg ccitt1.pbm + +followed by + + pbmtojbg ccitt1.pbm test.jbg + +you produce again the same data stream as ccitt1.jbg. However if you +want that the lowest resolution layer is not larger than 70 x 100 +pixels ("thumb nail" image), then use + + pbmtojbg -v -x 100 -y 150 ccitt1.pbm test.jbg + +Option -v will output some technical data, and will tell you that five +incremental resolution layers have been created, in addition to the +lowest 54 x 75 pixel large layer 0. Look at the lowest resolution +layer in test.jbg with + + jbgtopbm -x 100 test.jbg | display + +and you will still be able to clearly recognize the layout and line +structure of the page, which the implemented bi-level +resolution-reduction algorithm tried to preserve. With + + pbmtojbg -q ccitt1.pbm test.jbg + +you can enforce a single resolution layer, which usually requires a +slightly less space than progressive encoding. + + +OK, another small exercise. Assume you want to build a document +database in which you want to store scanned images in two resolution +layers, one for screen previewing and one for laser-printer output. +However, you do not want your decision to store images in two +resolutions to cause too much additional storage requirement. You +decide that 3 resolution layers in JBIG fit your requirement and you +want to store + + layer 0: 432 x 594 pixels + +in the first file test-low.jbg and the two layers + + layer 1: 864 x 1188 pixels + layer 2: 1728 x 2376 pixels + +in the second file test-high.jbg. No problem, just call + + pbmtojbg -d 2 -l 0 -h 0 ccitt1.pbm test-low.jbg + pbmtojbg -d 2 -l 1 -h 2 ccitt1.pbm test-high.jbg + +where option -d specifies the total number of layers and -l/-h select +the range of layers written to the output file. You will see that the +low and high resolution file together are only 1.6 kB larger than if +you had stored only the high-res version directly without progressive +mode (option -q). Progressive mode has reduced the additional storage +requirement by 50% compared to storing the 3.2 kB low-resolution +version independently of the high resolution image. + +In order to view only the screen version, use + + jbgtopbm test-low.jbg | display + +and in order to send the full version to the printer, just concatenate +both BIE files like in + + cat test-low.jbg test-high.jbg | jbgtopbm -m | .... + + +All this functionality, and more, are available as functions in the +libjbig C library, which you can link into your application. Just copy +the relevant files from libjbig/ into your own source-code directory +and adapt your Makefile. In libjbig/jbig.txt, you will find +documentation about how to use the full library, while +libjbig/jbig85.txt documents the fax variant of the library. The +latter lacks progressive encoding, but can instead deal better with +images where the height is not yet known at the start of a +transmission. + +Markus diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9f7e3ba --- /dev/null +++ b/Makefile @@ -0,0 +1,44 @@ +# Unix makefile for JBIG-KIT + +# Select an ANSI/ISO C compiler here, GNU gcc is recommended +CC = gcc + +# Options for the compiler: A high optimization level is suggested +CFLAGS = -O2 -W -Wno-unused-result +# CFLAGS = -O -g -W -Wall -Wno-unused-result -ansi -pedantic # -DDEBUG + +export CC CFLAGS + +VERSION=2.1 + +all: lib pbm + @echo "Enter 'make test' in order to start some automatic tests." + +lib: + cd libjbig && $(MAKE) -e + +pbm: lib + cd pbmtools && $(MAKE) -e + +test: lib pbm + cd libjbig && $(MAKE) test + cd pbmtools && $(MAKE) test + +analyze: + cd libjbig && $(MAKE) analyze + cd pbmtools && $(MAKE) analyze + +clean: + rm -f *~ core + cd libjbig && $(MAKE) clean + cd pbmtools && $(MAKE) clean + +distribution: + rm -rf jbigkit-$(VERSION) + git archive v$(VERSION) --prefix jbigkit-$(VERSION)/ | tar xvf - + make -C jbigkit-$(VERSION)/pbmtools txt + tar cvaf jbigkit-$(VERSION).tar.gz jbigkit-$(VERSION) + +release: + rsync -t jbigkit-$(VERSION).tar.gz $(HOME)/public_html/download/ + rsync -t jbigkit-$(VERSION)/CHANGES $(HOME)/public_html/jbigkit/ diff --git a/TODO b/TODO new file mode 100644 index 0000000..c0b01a3 --- /dev/null +++ b/TODO @@ -0,0 +1,51 @@ +Features that may appear in some future release regarding jbig.c: + + - function to prepare incompletely decoded images for display by Xlib + + - use a more efficient resolution-reduction method suggested by + Dr. Klaus Bartz + + - investigate whether there is a standard way of embedding JBIG + into TIFF and implement it (see also RFC 2301) + + - test for and eliminate warning messages from compilers + other than GCC + + - multichannel (e.g., RGB) support, PPM support + + - add dynamic library target to Makefile (patch by David Woodhouse), + for the benefit of Linux packagers + +The NEWLEN handling in jbig.c remains less than ideal. There is no +easy fix as NEWLEN is inherently incompatible with many of the other +options that jbig.c supports. The whole point of the VLENGTH bit may +have been to allow recipients to choose between a jbig.c (VLENGTH=0) +and jbig85.c (VLENGTH=1) style of decoder implementation. The cleanest +option would really be to remove NEWLEN support entirely from jbig.c +and to urge users who need it to use jbig85.c instead. Short of that, +the new NEWLEN look-ahead architecture from jbig85.c could be +backported to jbig.c, but this would only only slightly increase the +number of cases where the jbig.c decoder could deal with a NEWLEN +marker without a prior invocation of the jbg_newlen() pre-processing +pass. + +The following past feature requests for jbig.c probably have become +less important since the release of jbig85.c: + + - compile-time option to remove progressive encoding and + resolution-reduction support (in the interest of reducing code size) + + - investigate how to best deal with broken BIEs that contain + multiple NEWLEN marker segments, which are not permitted by ITU-T + T.85, but which have been observed coming from some fax machines; + possible options for jbg_newlen(): use first, last, or minimum + value + + - version of jbg_newlen() for dealing with BIEs that are split + into several blocks + + - call-back function for progress meter + +Features that may appear in some future release regarding jbig85.c: + + - man pages for pbmtojbg85 and jbgtopbm85 diff --git a/contrib/INDEX b/contrib/INDEX new file mode 100644 index 0000000..3e8542a --- /dev/null +++ b/contrib/INDEX @@ -0,0 +1,16 @@ +Here are some files which users of JBIG-KIT have contributed and which +I have included into the package in the hope that you might find them +useful. If you have questions with regard to these files, better +contact the respective contributors directly. + +--------------------------------------------------------------------------- + +atariprj.tar + + From: Stefan Willer + + These are four hierarchical project files for use with the Atari ST + Pure-C development environment. With these files, installing + JBIG-KIT should be child's play for Atari ST users (except the + necessary line end changes in all text files). + diff --git a/contrib/atariprj.tar b/contrib/atariprj.tar new file mode 100644 index 0000000..db12563 Binary files /dev/null and b/contrib/atariprj.tar differ diff --git a/examples/README b/examples/README new file mode 100644 index 0000000..c43b4f8 --- /dev/null +++ b/examples/README @@ -0,0 +1,8 @@ +The files in this directory are a few sample images and documents +stored as raw bi-level image entities (BIE) (the data stream specified +by the JBIG standard). + +The source data for the test examples ccitt* and lena.bie is available from + + ftp://ftp.funet.fi/pub/graphics/misc/test-images/ + diff --git a/examples/ccitt1.jbg b/examples/ccitt1.jbg new file mode 100644 index 0000000..cb7b9a4 Binary files /dev/null and b/examples/ccitt1.jbg differ diff --git a/examples/ccitt2.jbg b/examples/ccitt2.jbg new file mode 100644 index 0000000..c82699b Binary files /dev/null and b/examples/ccitt2.jbg differ diff --git a/examples/ccitt3.jbg b/examples/ccitt3.jbg new file mode 100644 index 0000000..c017204 Binary files /dev/null and b/examples/ccitt3.jbg differ diff --git a/examples/ccitt4.jbg b/examples/ccitt4.jbg new file mode 100644 index 0000000..65ead50 Binary files /dev/null and b/examples/ccitt4.jbg differ diff --git a/examples/ccitt5.jbg b/examples/ccitt5.jbg new file mode 100644 index 0000000..82b02c5 Binary files /dev/null and b/examples/ccitt5.jbg differ diff --git a/examples/ccitt6.jbg b/examples/ccitt6.jbg new file mode 100644 index 0000000..98468bc Binary files /dev/null and b/examples/ccitt6.jbg differ diff --git a/examples/ccitt7.jbg b/examples/ccitt7.jbg new file mode 100644 index 0000000..aca9d2b Binary files /dev/null and b/examples/ccitt7.jbg differ diff --git a/examples/ccitt8.jbg b/examples/ccitt8.jbg new file mode 100644 index 0000000..7eeebac Binary files /dev/null and b/examples/ccitt8.jbg differ diff --git a/examples/jbgtests.m b/examples/jbgtests.m new file mode 100644 index 0000000..2ebc77b --- /dev/null +++ b/examples/jbgtests.m @@ -0,0 +1,10 @@ +% MATLAB code to generate test files that exercise a JBIG codec + +width = 1200; +img = []; +for y=1:650; + mx = ceil(y / 5); + line = uint8(repmat(round(rand(1,mx)),1,ceil(width/mx))) == 1; + img = [img ; line(1:width)]; +end +imwrite(img, 'mx.png', 'PNG'); diff --git a/examples/multi.pgm b/examples/multi.pgm new file mode 100644 index 0000000..77fc0b2 --- /dev/null +++ b/examples/multi.pgm @@ -0,0 +1,5 @@ +P5 + 2 + 2 +4294967295 +abcdABCD9876WXYZ \ No newline at end of file diff --git a/examples/mx.jbg b/examples/mx.jbg new file mode 100644 index 0000000..9adedad Binary files /dev/null and b/examples/mx.jbg differ diff --git a/examples/sandra.pgm b/examples/sandra.pgm new file mode 100644 index 0000000..c65e5c8 Binary files /dev/null and b/examples/sandra.pgm differ diff --git a/examples/xvlogo.jbg b/examples/xvlogo.jbg new file mode 100644 index 0000000..d321685 Binary files /dev/null and b/examples/xvlogo.jbg differ diff --git a/libjbig/Makefile b/libjbig/Makefile new file mode 100644 index 0000000..f2898f5 --- /dev/null +++ b/libjbig/Makefile @@ -0,0 +1,55 @@ +# Unix makefile for the JBIG-KIT library + +# Select an ANSI/ISO C compiler here, GNU gcc is recommended +CC = gcc + +# Options for the compiler: A high optimization level is suggested +CFLAGS = -g -O -W -Wall -ansi -pedantic # --coverage + +all: libjbig.a libjbig85.a tstcodec tstcodec85 + +tstcodec: tstcodec.o jbig.o jbig_ar.o + $(CC) $(CFLAGS) -o tstcodec tstcodec.o jbig.o jbig_ar.o + +tstcodec85: tstcodec85.o jbig85.o jbig_ar.o + $(CC) $(CFLAGS) -o tstcodec85 tstcodec85.o jbig85.o jbig_ar.o + +libjbig.a: jbig.o jbig_ar.o + rm -f libjbig.a + ar rc libjbig.a jbig.o jbig_ar.o + -ranlib libjbig.a + +libjbig85.a: jbig85.o jbig_ar.o + rm -f libjbig85.a + ar rc libjbig85.a jbig85.o jbig_ar.o + -ranlib libjbig85.a + +jbig.o: jbig.c jbig.h jbig_ar.h +jbig85.o: jbig85.c jbig85.h jbig_ar.h +jbig_ar.o: jbig_ar.c jbig_ar.h +tstcodec.o: tstcodec.c jbig.h +tstcodec85.o: tstcodec85.c jbig85.h + +update-po: jbig.c jbig85.c Makefile + xgettext -ojbig.pot -k_ \ + --copyright-holder='Markus Kuhn' \ + --msgid-bugs-address='http://www.cl.cam.ac.uk/~mgk25/jbigkit/' \ + --package-name jbigkit \ + jbig.c jbig85.c + cd po && for po in *.po ; do \ + msgmerge --update $$po ../jbig.pot ; done + +analyze: + clang --analyze *.c + +test: tstcodec tstcodec85 + ./tstcodec + ./tstcodec85 + +t82test.pbm: tstcodec + ./tstcodec $@ + +clean: + rm -f *.o *.gcda *.gcno *.gcov *.plist *~ core gmon.out dbg_d\=??.pbm + rm -f t82test.pbm + rm -f tstcodec tstcodec85 diff --git a/libjbig/jbig.c b/libjbig/jbig.c new file mode 100644 index 0000000..751ceff --- /dev/null +++ b/libjbig/jbig.c @@ -0,0 +1,3285 @@ +/* + * Portable JBIG image compression library + * + * Copyright 1995-2014 -- Markus Kuhn -- http://www.cl.cam.ac.uk/~mgk25/ + * + * This module implements a portable standard C encoder and decoder + * using the JBIG1 lossless bi-level image compression algorithm + * specified in International Standard ISO 11544:1993 and + * ITU-T Recommendation T.82. See the file jbig.txt for usage + * instructions and application examples. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * If you want to use this program under different license conditions, + * then contact the author for an arrangement. + */ + +#ifdef DEBUG +#include +#else +#define NDEBUG +#endif + +#include +#include +#include + +#include "jbig.h" + +#define MX_MAX 127 /* maximal supported mx offset for + * adaptive template in the encoder */ + +#define TPB2CX 0x195 /* contexts for TP special pixels */ +#define TPB3CX 0x0e5 +#define TPDCX 0xc3f + +/* marker codes */ +#define MARKER_STUFF 0x00 +#define MARKER_RESERVE 0x01 +#define MARKER_SDNORM 0x02 +#define MARKER_SDRST 0x03 +#define MARKER_ABORT 0x04 +#define MARKER_NEWLEN 0x05 +#define MARKER_ATMOVE 0x06 +#define MARKER_COMMENT 0x07 +#define MARKER_ESC 0xff + +/* loop array indices */ +#define STRIPE 0 +#define LAYER 1 +#define PLANE 2 + +/* special jbg_buf pointers (instead of NULL) */ +#define SDE_DONE ((struct jbg_buf *) -1) +#define SDE_TODO ((struct jbg_buf *) 0) + +/* object code version id */ + +const char jbg_version[] = + "JBIG-KIT " JBG_VERSION " -- (c) 1995-2014 Markus Kuhn -- " + "Licence: " JBG_LICENCE "\n"; + +/* + * The following array specifies for each combination of the 3 + * ordering bits, which ii[] variable represents which dimension + * of s->sde. + */ +static const int iindex[8][3] = { + { 2, 1, 0 }, /* no ordering bit set */ + { -1, -1, -1}, /* SMID -> illegal combination */ + { 2, 0, 1 }, /* ILEAVE */ + { 1, 0, 2 }, /* SMID + ILEAVE */ + { 0, 2, 1 }, /* SEQ */ + { 1, 2, 0 }, /* SEQ + SMID */ + { 0, 1, 2 }, /* SEQ + ILEAVE */ + { -1, -1, -1 } /* SEQ + SMID + ILEAVE -> illegal combination */ +}; + +#define _(String) String /* to mark translatable string for GNU gettext */ + +/* + * Array with English ASCII error messages that correspond + * to return values from public functions in this library. + */ +static const char *errmsg[] = { + _("All OK"), /* JBG_EOK */ + _("Reached specified image size"), /* JBG_EOK_INTR */ + _("Unexpected end of input data stream"), /* JBG_EAGAIN */ + _("Not enough memory available"), /* JBG_ENOMEM */ + _("ABORT marker segment encountered"), /* JBG_EABORT */ + _("Unknown marker segment encountered"), /* JBG_EMARKER */ + _("Input data stream contains invalid data"), /* JBG_EINVAL */ + _("Input data stream uses unimplemented JBIG features"), /* JBG_EIMPL */ + _("Incremental BIE does not continue previous one") /* JBG_ENOCONT */ +}; + + +/* + * The following three functions are the only places in this code, were + * C library memory management functions are called. The whole JBIG + * library has been designed in order to allow multi-threaded + * execution. No static or global variables are used, so all fuctions + * are fully reentrant. However if you want to use this multi-thread + * capability and your malloc, realloc and free are not reentrant, + * then simply add the necessary semaphores or mutex primitives below. + * In contrast to C's malloc() and realloc(), but like C's calloc(), + * these functions take two parameters nmemb and size that are multiplied + * before being passed on to the corresponding C function. + * This we can catch all overflows during a size_t multiplication a + * a single place. + */ + +#ifndef SIZE_MAX +#define SIZE_MAX ((size_t) -1) /* largest value of size_t */ +#endif + +static void *checked_malloc(size_t nmemb, size_t size) +{ + void *p; + + /* Full manual exception handling is ugly here for performance + * reasons. If an adequate handling of lack of memory is required, + * then use C++ and throw a C++ exception instead of abort(). */ + + /* assert that nmemb * size <= SIZE_MAX */ + if (size > SIZE_MAX / nmemb) + abort(); + + p = malloc(nmemb * size); + + if (!p) + abort(); + +#if 0 + fprintf(stderr, "%p = malloc(%lu * %lu)\n", p, + (unsigned long) nmemb, (unsigned long) size); +#endif + + return p; +} + + +static void *checked_realloc(void *ptr, size_t nmemb, size_t size) +{ + void *p; + + /* Full manual exception handling is ugly here for performance + * reasons. If an adequate handling of lack of memory is required, + * then use C++ and throw a C++ exception here instead of abort(). */ + + /* assert that nmemb * size <= SIZE_MAX */ + if (size > SIZE_MAX / nmemb) + abort(); + + p = realloc(ptr, nmemb * size); + + if (!p) + abort(); + +#if 0 + fprintf(stderr, "%p = realloc(%p, %lu * %lu)\n", p, ptr, + (unsigned long) nmemb, (unsigned long) size); +#endif + + return p; +} + + +static void checked_free(void *ptr) +{ + free(ptr); + +#if 0 + fprintf(stderr, "free(%p)\n", ptr); +#endif + +} + + + + +/* + * Memory management for buffers which are used for temporarily + * storing SDEs by the encoder. + * + * The following functions manage a set of struct jbg_buf storage + * containers were each can keep JBG_BUFSIZE bytes. The jbg_buf + * containers can be linked to form linear double-chained lists for + * which a number of operations are provided. Blocks which are + * tempoarily not used any more are returned to a freelist which each + * encoder keeps. Only the destructor of the encoder actually returns + * the block via checked_free() to the stdlib memory management. + */ + + +/* + * Allocate a new buffer block and initialize it. Try to get it from + * the free_list, and if it is empty, call checked_malloc(). + */ +static struct jbg_buf *jbg_buf_init(struct jbg_buf **free_list) +{ + struct jbg_buf *new_block; + + /* Test whether a block from the free list is available */ + if (*free_list) { + new_block = *free_list; + *free_list = new_block->next; + } else { + /* request a new memory block */ + new_block = (struct jbg_buf *) checked_malloc(1, sizeof(struct jbg_buf)); + } + new_block->len = 0; + new_block->next = NULL; + new_block->previous = NULL; + new_block->last = new_block; + new_block->free_list = free_list; + + return new_block; +} + + +/* + * Return an entire free_list to the memory management of stdlib. + * This is only done by jbg_enc_free(). + */ +static void jbg_buf_free(struct jbg_buf **free_list) +{ + struct jbg_buf *tmp; + + while (*free_list) { + tmp = (*free_list)->next; + checked_free(*free_list); + *free_list = tmp; + } + + return; +} + + +/* + * Append a single byte to a single list that starts with the block + * *(struct jbg_buf *) head. The type of *head is void here in order to + * keep the interface of the arithmetic encoder gereric, which uses this + * function as a call-back function in order to deliver single bytes + * for a PSCD. + */ +static void jbg_buf_write(int b, void *head) +{ + struct jbg_buf *now; + + now = ((struct jbg_buf *) head)->last; + if (now->len < JBG_BUFSIZE - 1) { + now->d[now->len++] = b; + return; + } + now->next = jbg_buf_init(((struct jbg_buf *) head)->free_list); + now->next->previous = now; + now->next->d[now->next->len++] = b; + ((struct jbg_buf *) head)->last = now->next; + + return; +} + + +/* + * Remove any trailing zero bytes from the end of a linked jbg_buf list, + * however make sure that no zero byte is removed which directly + * follows a 0xff byte (i.e., keep MARKER_ESC MARKER_STUFF sequences + * intact). This function is used to remove any redundant final zero + * bytes from a PSCD. + */ +static void jbg_buf_remove_zeros(struct jbg_buf *head) +{ + struct jbg_buf *last; + + while (1) { + /* remove trailing 0x00 in last block of list until this block is empty */ + last = head->last; + while (last->len && last->d[last->len - 1] == 0) + last->len--; + /* if block became really empty, remove it in case it is not the + * only remaining block and then loop to next block */ + if (last->previous && !last->len) { + head->last->next = *head->free_list; + *head->free_list = head->last; + head->last = last->previous; + head->last->next = NULL; + } else + break; + } + + /* + * If the final non-zero byte is 0xff (MARKER_ESC), then we just have + * removed a MARKER_STUFF and we will append it again now in order + * to preserve PSCD status of byte stream. + */ + if (head->last->len && head->last->d[head->last->len - 1] == MARKER_ESC) + jbg_buf_write(MARKER_STUFF, head); + + return; +} + + +/* + * The jbg_buf list which starts with block *new_prefix is concatenated + * with the list which starts with block **start and *start will then point + * to the first block of the new list. + */ +static void jbg_buf_prefix(struct jbg_buf *new_prefix, struct jbg_buf **start) +{ + new_prefix->last->next = *start; + new_prefix->last->next->previous = new_prefix->last; + new_prefix->last = new_prefix->last->next->last; + *start = new_prefix; + + return; +} + + +/* + * Send the contents of a jbg_buf list that starts with block **head to + * the call back function data_out and return the blocks of the jbg_buf + * list to the freelist from which these jbg_buf blocks have been taken. + * After the call, *head == NULL. + */ +static void jbg_buf_output(struct jbg_buf **head, + void (*data_out)(unsigned char *start, + size_t len, void *file), + void *file) +{ + struct jbg_buf *tmp; + + while (*head) { + data_out((*head)->d, (*head)->len, file); + tmp = (*head)->next; + (*head)->next = *(*head)->free_list; + *(*head)->free_list = *head; + *head = tmp; + } + + return; +} + + +/* + * Calculate y = ceil(x/2) applied n times, which is equivalent to + * y = ceil(x/(2^n)). This function is used to + * determine the number of pixels per row or column after n resolution + * reductions. E.g. X[d-1] = jbg_ceil_half(X[d], 1) and X[0] = + * jbg_ceil_half(X[d], d) as defined in clause 6.2.3 of T.82. + */ +unsigned long jbg_ceil_half(unsigned long x, int n) +{ + unsigned long mask; + + assert(n >= 0 && n < 32); + mask = (1UL << n) - 1; /* the lowest n bits are 1 here */ + return (x >> n) + ((mask & x) != 0); +} + + +/* + * Set L0 (the number of lines in a stripe at lowest resolution) + * to a default value, such that there are about 35 stripes, as + * suggested in Annex C of ITU-T T.82, without exceeding the + * limit 128/2^D suggested in Annex A. + */ +static void jbg_set_default_l0(struct jbg_enc_state *s) +{ + s->l0 = jbg_ceil_half(s->yd, s->d) / 35; /* 35 stripes/image */ + while ((s->l0 << s->d) > 128) /* but <= 128 lines/stripe */ + --s->l0; + if (s->l0 < 2) s->l0 = 2; +} + + +/* + * Calculate the number of stripes, as defined in clause 6.2.3 of T.82. + */ +unsigned long jbg_stripes(unsigned long l0, unsigned long yd, + unsigned long d) +{ + unsigned long y0 = jbg_ceil_half(yd, d); + + return y0 / l0 + (y0 % l0 != 0); +} + + +/* + * Resolution reduction table given by ITU-T T.82 Table 17 + */ + +static char jbg_resred[4096] = { + 0,0,0,1,0,0,0,1,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, + 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1, + 0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1, + 1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,1,0,0,1,1,1,0,1,1, + 0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1, + 1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,0,1,1,1,0, + 0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, + 0,0,0,1,0,0,0,1,0,1,1,0,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, + 1,1,1,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1, + 1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1, + 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,1,1,0,1,0,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,0,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1, + 1,0,0,1,0,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0, + 0,0,1,0,1,1,1,1,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0, + 0,0,0,0,1,0,0,1,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1, + 0,0,1,0,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1, + 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,1,0,0,1,0,0,1,1, + 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,1,0,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1, + 0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,1,0,1,0,1,1,0,0,0,1,0,0,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,1,1,0,0,1,1, + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1, + 0,0,1,0,0,1,1,1,0,0,0,0,1,0,0,1,0,0,0,1,1,1,1,0,1,0,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1,1,0, + 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,1,1,0,1,1,1, + 0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,1,1,0,1,0,0,0,1,1,0,1,0,0,0,0,1,1,1,1,0,0,1,1,1,0,1,1,0,0,1,1, + 0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,1,0,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, + 0,0,0,1,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, + 0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1, + 0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,1, + 0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,1,0,1,1,0,1,1,1,0,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,1,0,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,1,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1, + 1,0,1,0,1,0,0,1,1,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,0,1,1,0,1,1,1, + 0,0,1,0,0,0,0,1,0,0,0,0,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,0,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,1,0,1,0,1,0,1,1,0,1,0,1,0,0,0,1,1,1,1,1,1,1,1,1, + 1,1,1,0,1,0,0,0,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1, + 1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,1, + 0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,1,0,1,0,0,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1, + 1,0,0,0,1,0,0,0,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,1,0,1,1,0, + 0,0,1,1,1,1,1,1,0,0,0,0,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,0,1,0,1,1,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1, + 0,0,1,0,1,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1, + 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1, + 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,1,0,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1, + 0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,1, + 0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1, + 1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0, + 0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1, + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1, + 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,1, + 0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,1,1,0,0,0,1,0,1,1,1,0,1,1,1 +}; + +/* + * Deterministic prediction tables given by ITU-T T.82 tables + * 19 to 22. The table below is organized differently, the + * index bits are permutated for higher efficiency. + */ + +static char jbg_dptable[256 + 512 + 2048 + 4096] = { + /* phase 0: offset=0 */ + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,2,2,2,2,2,2,2, + 0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,2,0,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + /* phase 1: offset=256 */ + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,0,2,0,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,2,2,2,2,1,2,1,2,2,2,2,1,1,1,1,2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,2, + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,0,2,2,2,2,2,2,2, + 0,2,0,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,0,0,2,2,2,2,2,0,0,2,2,2,2,2, + 0,2,2,2,2,1,2,1,2,2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1, + 1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,1,1,2,2,2,2,2,0,2,2,2,2,2,2, + 2,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,0,2,0,2,2,2,2,2,0,2,2,2,2,2,2,2, + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,2, + 2,2,2,2,2,1,1,1,2,2,2,2,1,1,1,1,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,0,1,2,0,2,0,2,2,2,2,2,0,2,0,2,2,2,2,1, + 0,2,0,2,2,1,2,1,2,2,2,2,1,1,1,1,0,0,0,0,2,2,2,2,0,2,0,2,2,2,2,1, + 2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,0,0,0,2,2,2,2,2, + 2,2,2,2,2,1,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,1,2,1,2,2,2,2,1, + 2,2,2,2,2,2,2,2,0,2,0,2,2,1,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2, + /* phase 2: offset=768 */ + 2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,1,1,1,1, + 0,2,2,2,2,1,2,1,2,2,2,2,1,2,1,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, + 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,1,2,1,2,2,2,2,2,1,1,1, + 2,0,2,2,2,1,2,1,0,2,2,2,1,2,1,2,2,2,2,0,2,2,2,2,0,2,0,2,2,2,2,2, + 0,2,0,0,1,1,1,1,2,2,2,2,1,1,1,1,0,2,0,2,1,1,1,1,2,2,2,2,1,1,1,1, + 2,2,0,2,2,2,1,2,2,2,2,2,1,2,1,2,2,2,0,2,2,1,2,1,0,2,0,2,1,1,1,1, + 2,0,0,2,2,2,2,2,0,2,0,2,2,0,2,0,2,0,2,0,2,2,2,1,2,2,0,2,1,1,2,1, + 2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,1,1,1,1, + 0,0,0,0,2,2,2,2,0,0,0,0,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,0,2,2,2,2,1,0,2,2,2,1,1,1,1,2,0,2,2,2,2,2,2,0,2,0,2,2,1,2,1, + 2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2, + 0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2, + 2,2,0,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,2,2,1,2,1,0,2,2,2,1,1,1,1, + 2,2,2,0,2,2,2,2,2,2,0,2,2,0,2,0,2,1,2,2,2,2,2,2,1,2,1,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,1, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,1,1,1,2,2,2,2,1,1,1,1, + 2,2,2,1,2,2,2,2,2,2,1,2,0,0,0,0,2,2,0,2,2,1,2,2,2,2,2,2,1,1,1,1, + 2,0,0,0,2,2,2,2,0,2,2,2,2,2,2,0,2,2,2,0,2,2,2,2,2,0,0,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,0,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,1, + 0,2,0,2,2,1,1,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2, + 2,0,2,0,2,1,2,1,0,2,0,2,2,2,1,2,2,0,2,0,2,2,2,2,0,2,0,2,2,2,1,2, + 2,2,2,0,2,2,2,2,2,2,0,2,2,2,2,2,2,2,1,2,2,2,2,2,2,0,1,2,2,2,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2, + 2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,1,2,1,0,2,2,2,1,1,1,1, + 2,0,2,0,2,1,2,2,0,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,1,2,2, + 2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,2,1,2,1, + 2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,0,0,2,2,2,1,2,2,2, + 0,0,2,0,2,2,2,2,0,2,0,2,2,0,2,0,1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1, + 2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,1, + 2,2,0,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,1,1,1,1, + 0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2, + 2,0,0,2,2,2,2,2,0,2,0,2,2,2,2,2,1,0,1,2,2,2,2,1,0,2,2,2,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,0,2,2,0,2,0,2,1,2,2,2,2,2,2,2,2,0,2,2,1,2,2, + 0,2,0,0,1,1,1,1,0,2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,0,2,2,1,2,1,1, + 2,2,0,2,2,1,2,2,2,2,2,2,1,2,2,2,2,0,2,2,2,2,2,2,0,2,0,2,1,2,1,1, + 2,0,2,0,2,2,2,2,0,2,0,2,2,1,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,1, + 2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,2,2,2,2,2,1,1,2,2,2,2,2,1,2,2,2, + 2,0,2,2,2,1,2,1,0,2,2,2,2,2,1,2,2,0,2,0,2,2,2,2,0,2,0,2,2,1,2,2, + 0,2,0,0,2,2,2,2,1,2,2,2,2,2,2,0,2,1,2,2,2,2,2,2,1,2,2,2,2,2,2,2, + 0,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,1,0,2,2, + 0,0,0,2,2,1,1,1,2,2,2,2,1,2,2,2,2,0,2,0,2,2,2,1,2,2,2,2,1,2,1,2, + 0,0,0,0,2,2,2,2,2,2,0,2,2,1,2,2,2,1,2,1,2,2,2,2,1,2,1,2,0,2,2,2, + 2,0,2,0,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,1,2,2,2,2,2,0,2,2,1,2,2,0,0,0,2,2,2,2,2,1,2,2,0,2,2,2,1,2,1,2, + 2,0,2,0,2,2,2,2,0,2,0,2,2,1,2,2,0,2,0,0,2,2,2,2,2,2,2,2,2,1,2,2, + 2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,1, + 1,2,0,2,2,1,2,1,2,2,2,2,1,2,2,2,2,0,2,0,2,2,2,2,2,0,2,2,1,1,1,1, + 0,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,1,2,1, + 2,2,0,0,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1, + 2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2, + 2,0,2,0,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,0,2,0,2,2,2,1,2, + 2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, + 2,0,2,0,2,2,2,2,2,0,2,0,2,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,2,1,2,1, + 2,2,2,2,2,1,2,1,0,2,0,2,2,2,2,2,2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,1, + 2,0,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,0, + 2,0,2,0,2,2,2,1,2,2,2,0,2,2,2,1,2,0,2,0,2,2,2,2,0,0,0,2,2,2,2,1, + 2,0,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2, + /* phase 3: offset=2816 */ + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,0,2,2,2,1,2,0,2,2,2,1,2,2,2,2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2, + 2,2,2,1,2,2,2,0,1,1,1,1,0,0,0,0,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,0,0,0,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2, + 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,2,0,2,0,2,1,2,1, + 2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2, + 2,0,2,2,2,1,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,0,2,0,1,1,2,1, + 2,2,2,0,2,2,2,1,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, + 0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1, + 2,0,0,2,2,1,1,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,1,1,1,2,0,0,0, + 2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2,2,2,2,0,2,2,2,1,2,0,2,0,2,1,2,1, + 2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1, + 2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2, + 2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,0,2,0,2,1,2,1,0,0,2,0,1,1,2,1, + 2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,0,0,0,2,1,1,1, + 2,2,2,1,2,2,2,0,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2, + 2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1, + 2,0,2,2,2,1,2,2,0,0,2,0,1,1,2,1,2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2, + 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,0,0,0,1,1,1,1, + 2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,2,1,0,2,2,0,1,2, + 2,2,2,1,2,2,2,0,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2, + 2,1,2,1,2,0,2,0,1,2,1,1,0,2,0,0,0,0,2,1,1,1,2,0,0,0,0,0,1,1,1,1, + 2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,0,2,1,2,1,2,0,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,0,2,2,2,1,2,2,2,0,0,2,2,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2, + 2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1, + 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,0,0,0,2,1,1,1, + 2,2,2,0,2,2,2,1,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, + 2,0,2,2,2,1,2,2,2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,1,2,1,2,0,2,0,1,2,1,1,0,2,0,0,2,0,2,2,2,1,2,2,0,2,1,2,1,2,0,2, + 2,2,2,1,2,2,2,0,2,2,1,2,2,2,0,2,2,1,2,2,2,0,2,2,2,2,0,2,2,2,1,2, + 0,0,2,0,1,1,2,1,0,0,1,0,1,1,0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,0,2,2,2,1,1,2,2,2,0,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, + 2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,0,0,2,2,1,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2, + 2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,2,2,1,2,2,2,0,2,1,2,1,2,0,2,0, + 2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1,2,0,0,0,2,1,1,1, + 2,2,2,2,2,2,2,2,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,1,2,1,2,0,2,0,2,0,2,2,2,1,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,1,1,1,2,0,0,0, + 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1, + 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2, + 2,1,2,1,2,0,2,0,2,1,2,2,2,0,2,2,2,2,2,0,2,2,2,1,2,0,2,0,2,1,2,1, + 2,0,2,0,2,1,2,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, + 2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,0,1,0,0,1,0,1,1, + 2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,1,2,2,1,0,2,0,2,2,2,1,2,2,2, + 2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2, + 2,0,2,0,2,1,2,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, + 0,2,0,0,1,2,1,1,2,0,0,0,2,1,1,1,2,2,2,2,2,2,2,2,1,0,1,2,0,1,0,2, + 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,1,2,2,2,0,2,2,1,1,2,2,0,0,2,2, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,1,2,1,2,0,2,0,2,1,2,2,2,0,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,1,2,2,2,0,2,2,2, + 2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,2, + 0,0,0,0,1,1,1,1,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,2,0,2,2,2,1,2, + 2,0,2,0,2,1,2,1,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,1,2,2,2,0,1,1,2,1,0,0,2,0,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,0,2,2,2,1,2, + 2,0,2,0,2,1,2,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2, + 0,2,0,0,1,2,1,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1,2, + 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,0,2,1,1,1,2,0,0,2,2,2,1,2,2,2, + 2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1, + 0,0,2,2,1,1,2,2,0,2,1,2,1,2,0,2,2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2, + 2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1, + 2,2,0,0,2,2,1,1,2,2,0,0,2,2,1,1,2,2,2,2,2,2,2,2,2,2,0,0,2,2,1,1, + 2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1, + 2,2,2,0,2,2,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,1,1,1,2,0,0,0,2, + 2,2,2,2,2,2,2,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2, + 2,0,2,0,2,1,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1, + 2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2,2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2, + 2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,0,2,0,2,1,2,1,2,1,2,0,2,0,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,0,2,0,2,1,2,1,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2, + 2,0,2,1,2,1,2,0,0,2,1,2,1,2,0,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,0,2,0,2,1,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1, + 2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,1,2,1,2,0,2,0,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,0,2,0,2,1,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +}; + + +/* + * Initialize the status struct for the encoder. + */ +void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y, + int planes, unsigned char **p, + void (*data_out)(unsigned char *start, size_t len, + void *file), + void *file) +{ + unsigned long l, lx; + int i; + + assert(x > 0 && y > 0 && planes > 0 && planes < 256); + s->xd = x; + s->yd = y; + s->yd1 = y; /* This is the hight initially announced in BIH. To provoke + generation of NEWLEN for T.85 compatibility tests, + overwrite with new value s->yd1 > s->yd */ + s->planes = planes; + s->data_out = data_out; + s->file = file; + + s->d = 0; + s->dl = 0; + s->dh = s->d; + jbg_set_default_l0(s); + s->mx = 8; + s->my = 0; + s->order = JBG_ILEAVE | JBG_SMID; + s->options = JBG_TPBON | JBG_TPDON | JBG_DPON; + s->comment = NULL; + s->dppriv = jbg_dptable; + s->res_tab = jbg_resred; + + s->highres = (int *) checked_malloc(planes, sizeof(int)); + s->lhp[0] = p; + s->lhp[1] = (unsigned char **) + checked_malloc(planes, sizeof(unsigned char *)); + for (i = 0; i < planes; i++) { + s->highres[i] = 0; + s->lhp[1][i] = (unsigned char *) + checked_malloc(jbg_ceil_half(y, 1), jbg_ceil_half(x, 1+3)); + } + + s->free_list = NULL; + s->s = (struct jbg_arenc_state *) + checked_malloc(s->planes, sizeof(struct jbg_arenc_state)); + s->tx = (int *) checked_malloc(s->planes, sizeof(int)); + lx = jbg_ceil_half(x, 1); + s->tp = (char *) checked_malloc(lx, sizeof(char)); + for (l = 0; l < lx; s->tp[l++] = 2) ; + s->sde = NULL; + + return; +} + + +/* + * This function selects the number of differential layers based on + * the maximum size requested for the lowest resolution layer. If + * possible, a number of differential layers is selected, which will + * keep the size of the lowest resolution layer below or equal to the + * given width x and height y. However not more than 6 differential + * resolution layers will be used. In addition, a reasonable value for + * l0 (height of one stripe in the lowest resolution layer) is + * selected, which obeys the recommended limitations for l0 in annex A + * and C of the JBIG standard. The selected number of resolution layers + * is returned. + */ +int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long x, + unsigned long y) +{ + for (s->d = 0; s->d < 6; s->d++) + if (jbg_ceil_half(s->xd, s->d) <= x && jbg_ceil_half(s->yd, s->d) <= y) + break; + s->dl = 0; + s->dh = s->d; + jbg_set_default_l0(s); + return s->d; +} + + +/* + * As an alternative to jbg_enc_lrlmax(), the following function allows + * to specify the number of layers directly. The stripe height and layer + * range is also adjusted automatically here. + */ +void jbg_enc_layers(struct jbg_enc_state *s, int d) +{ + if (d < 0 || d > 31) + return; + s->d = d; + s->dl = 0; + s->dh = s->d; + jbg_set_default_l0(s); + return; +} + + +/* + * Specify the highest and lowest resolution layers which will be + * written to the output file. Call this function not before + * jbg_enc_layers() or jbg_enc_lrlmax(), because these two functions + * reset the lowest and highest resolution layer to default values. + * Negative values are ignored. The total number of layers is returned. + */ +int jbg_enc_lrange(struct jbg_enc_state *s, int dl, int dh) +{ + if (dl >= 0 && dl <= s->d) s->dl = dl; + if (dh >= s->dl && dh <= s->d) s->dh = dh; + + return s->d; +} + + +/* + * The following function allows to specify the bits describing the + * options of the format as well as the maximum AT movement window and + * the number of layer 0 lines per stripes. + */ +void jbg_enc_options(struct jbg_enc_state *s, int order, int options, + unsigned long l0, int mx, int my) +{ + if (order >= 0 && order <= 0x0f) s->order = order; + if (options >= 0) s->options = options; + if (l0 > 0) s->l0 = l0; + if (mx >= 0 && my < 128) s->mx = mx; + if (my >= 0 && my < 256) s->my = my; + + return; +} + + +/* + * This function actually does all the tricky work involved in producing + * a SDE, which is stored in the appropriate s->sde[][][] element + * for later output in the correct order. + */ +static void encode_sde(struct jbg_enc_state *s, + long stripe, int layer, int plane) +{ + unsigned char *hp, *lp1, *lp2, *p0, *p1, *q1, *q2; + unsigned long hl, ll, hx, hy, lx, ly, hbpl, lbpl; + unsigned long line_h0 = 0, line_h1 = 0; + unsigned long line_h2, line_h3, line_l1, line_l2, line_l3; + struct jbg_arenc_state *se; + unsigned long y; /* current line number in highres image */ + unsigned long i; /* current line number within highres stripe */ + unsigned long j; /* current column number in highres image */ + long o; + unsigned a, p, t; + int ltp, ltp_old, cx; + unsigned long c_all, c[MX_MAX + 1], cmin, cmax, clmin, clmax; + int tmax, at_determined; + int new_tx; + long new_tx_line = -1; + int reset; + struct jbg_buf *new_jbg_buf; + +#ifdef DEBUG + static long tp_lines, tp_exceptions, tp_pixels, dp_pixels; + static long encoded_pixels; +#endif + + /* return immediately if this stripe has already been encoded */ + if (s->sde[stripe][layer][plane] != SDE_TODO) + return; + +#ifdef DEBUG + if (stripe == 0) + tp_lines = tp_exceptions = tp_pixels = dp_pixels = encoded_pixels = 0; + fprintf(stderr, "encode_sde: s/d/p = %2ld/%2d/%2d\n", + stripe, layer, plane); +#endif + + /* number of lines per stripe in highres image */ + hl = s->l0 << layer; + /* number of lines per stripe in lowres image */ + ll = hl >> 1; + /* current line number in highres image */ + y = stripe * hl; + /* number of pixels in highres image */ + hx = jbg_ceil_half(s->xd, s->d - layer); + hy = jbg_ceil_half(s->yd, s->d - layer); + /* number of pixels in lowres image */ + lx = jbg_ceil_half(hx, 1); + ly = jbg_ceil_half(hy, 1); + /* bytes per line in highres and lowres image */ + hbpl = jbg_ceil_half(hx, 3); + lbpl = jbg_ceil_half(lx, 3); + /* pointer to first image byte of highres stripe */ + hp = s->lhp[s->highres[plane]][plane] + stripe * hl * hbpl; + lp2 = s->lhp[1 - s->highres[plane]][plane] + stripe * ll * lbpl; + lp1 = lp2 + lbpl; + + /* check whether we can refer to any state of a previous stripe */ + reset = (stripe == 0) || (s->options & JBG_SDRST); + + /* initialize arithmetic encoder */ + se = s->s + plane; + arith_encode_init(se, !reset); + s->sde[stripe][layer][plane] = jbg_buf_init(&s->free_list); + se->byte_out = jbg_buf_write; + se->file = s->sde[stripe][layer][plane]; + + /* initialize adaptive template movement algorithm */ + c_all = 0; + for (t = 0; t <= s->mx; t++) + c[t] = 0; + if (stripe == 0) /* the SDRST case is handled at the end */ + s->tx[plane] = 0; + new_tx = -1; + at_determined = 0; /* we haven't yet decided the template move */ + if (s->mx == 0) + at_determined = 1; + + /* initialize typical prediction */ + ltp = 0; + if (reset) + ltp_old = 0; + else { + ltp_old = 1; + p1 = hp - hbpl; + if (y > 1) { + q1 = p1 - hbpl; + while (p1 < hp && (ltp_old = (*p1++ == *q1++)) != 0) ; + } else + while (p1 < hp && (ltp_old = (*p1++ == 0)) != 0) ; + } + + if (layer == 0) { + + /* + * Encode lowest resolution layer + */ + + for (i = 0; i < hl && y < hy; i++, y++) { + + /* check whether it is worth to perform an ATMOVE */ + if (!at_determined && c_all > 2048) { + cmin = clmin = 0xffffffffL; + cmax = clmax = 0; + tmax = 0; + for (t = (s->options & JBG_LRLTWO) ? 5 : 3; t <= s->mx; t++) { + if (c[t] > cmax) cmax = c[t]; + if (c[t] < cmin) cmin = c[t]; + if (c[t] > c[tmax]) tmax = t; + } + clmin = (c[0] < cmin) ? c[0] : cmin; + clmax = (c[0] > cmax) ? c[0] : cmax; + if (c_all - cmax < (c_all >> 3) && + cmax - c[s->tx[plane]] > c_all - cmax && + cmax - c[s->tx[plane]] > (c_all >> 4) && + /* ^ T.82 said < here, fixed in Cor.1/25 */ + cmax - (c_all - c[s->tx[plane]]) > c_all - cmax && + cmax - (c_all - c[s->tx[plane]]) > (c_all >> 4) && + cmax - cmin > (c_all >> 2) && + (s->tx[plane] || clmax - clmin > (c_all >> 3))) { + /* we have decided to perform an ATMOVE */ + new_tx = tmax; + if (!(s->options & JBG_DELAY_AT)) { + new_tx_line = i; + s->tx[plane] = new_tx; + } +#ifdef DEBUG + fprintf(stderr, "ATMOVE: line=%ld, tx=%d, c_all=%ld\n", + i, new_tx, c_all); +#endif + } + at_determined = 1; + } + assert(s->tx[plane] >= 0); /* i.e., tx can safely be cast to unsigned */ + + /* typical prediction */ + if (s->options & JBG_TPBON) { + ltp = 1; + p1 = hp; + if (i > 0 || !reset) { + q1 = hp - hbpl; + while (q1 < hp && (ltp = (*p1++ == *q1++)) != 0) ; + } else + while (p1 < hp + hbpl && (ltp = (*p1++ == 0)) != 0) ; + arith_encode(se, (s->options & JBG_LRLTWO) ? TPB2CX : TPB3CX, + ltp == ltp_old); +#ifdef DEBUG + tp_lines += ltp; +#endif + ltp_old = ltp; + if (ltp) { + /* skip next line */ + hp += hbpl; + continue; + } + } + + /* + * Layout of the variables line_h1, line_h2, line_h3, which contain + * as bits the neighbour pixels of the currently coded pixel X: + * + * 76543210765432107654321076543210 line_h3 + * 76543210765432107654321076543210 line_h2 + * 76543210765432107654321X76543210 line_h1 + */ + + line_h1 = line_h2 = line_h3 = 0; + if (i > 0 || !reset) line_h2 = (long)*(hp - hbpl) << 8; + if (i > 1 || !reset) line_h3 = (long)*(hp - hbpl - hbpl) << 8; + + /* encode line */ + for (j = 0; j < hx; hp++) { + line_h1 |= *hp; + if (j < hbpl * 8 - 8 && (i > 0 || !reset)) { + line_h2 |= *(hp - hbpl + 1); + if (i > 1 || !reset) + line_h3 |= *(hp - hbpl - hbpl + 1); + } + if (s->options & JBG_LRLTWO) { + /* two line template */ + do { + line_h1 <<= 1; line_h2 <<= 1; line_h3 <<= 1; + if (s->tx[plane]) { + if ((unsigned) s->tx[plane] > j) + a = 0; + else { + o = (j - s->tx[plane]) - (j & ~7L); + a = (hp[o >> 3] >> (7 - (o & 7))) & 1; + a <<= 4; + } + assert(s->tx[plane] > 23 || + a == ((line_h1 >> (4 + s->tx[plane])) & 0x010)); + arith_encode(se, (((line_h2 >> 10) & 0x3e0) | a | + ((line_h1 >> 9) & 0x00f)), + (line_h1 >> 8) & 1); + } + else + arith_encode(se, (((line_h2 >> 10) & 0x3f0) | + ((line_h1 >> 9) & 0x00f)), + (line_h1 >> 8) & 1); +#ifdef DEBUG + encoded_pixels++; +#endif + /* statistics for adaptive template changes */ + if (!at_determined && j >= s->mx && j < hx-2) { + p = (line_h1 & 0x100) != 0; /* current pixel value */ + c[0] += ((line_h2 & 0x4000) != 0) == p; /* default position */ + assert(!(((line_h2 >> 6) ^ line_h1) & 0x100) == + (((line_h2 & 0x4000) != 0) == p)); + for (t = 5; t <= s->mx && t <= j; t++) { + o = (j - t) - (j & ~7L); + a = (hp[o >> 3] >> (7 - (o & 7))) & 1; + assert(t > 23 || + (a == p) == !(((line_h1 >> t) ^ line_h1) & 0x100)); + c[t] += a == p; + } + for (; t <= s->mx; t++) { + c[t] += 0 == p; + } + ++c_all; + } + } while (++j & 7 && j < hx); + } else { + /* three line template */ + do { + line_h1 <<= 1; line_h2 <<= 1; line_h3 <<= 1; + if (s->tx[plane]) { + if ((unsigned) s->tx[plane] > j) + a = 0; + else { + o = (j - s->tx[plane]) - (j & ~7L); + a = (hp[o >> 3] >> (7 - (o & 7))) & 1; + a <<= 2; + } + assert(s->tx[plane] > 23 || + a == ((line_h1 >> (6 + s->tx[plane])) & 0x004)); + arith_encode(se, (((line_h3 >> 8) & 0x380) | + ((line_h2 >> 12) & 0x078) | a | + ((line_h1 >> 9) & 0x003)), + (line_h1 >> 8) & 1); + } else + arith_encode(se, (((line_h3 >> 8) & 0x380) | + ((line_h2 >> 12) & 0x07c) | + ((line_h1 >> 9) & 0x003)), + (line_h1 >> 8) & 1); +#ifdef DEBUG + encoded_pixels++; +#endif + /* statistics for adaptive template changes */ + if (!at_determined && j >= s->mx && j < hx-2) { + p = (line_h1 & 0x100) != 0; /* current pixel value */ + c[0] += ((line_h2 & 0x4000) != 0) == p; /* default position */ + assert(!(((line_h2 >> 6) ^ line_h1) & 0x100) == + (((line_h2 & 0x4000) != 0) == p)); + for (t = 3; t <= s->mx && t <= j; t++) { + o = (j - t) - (j & ~7L); + a = (hp[o >> 3] >> (7 - (o & 7))) & 1; + assert(t > 23 || + (a == p) == !(((line_h1 >> t) ^ line_h1) & 0x100)); + c[t] += a == p; + } + for (; t <= s->mx; t++) { + c[t] += 0 == p; + } + ++c_all; + } + } while (++j & 7 && j < hx); + } /* if (s->options & JBG_LRLTWO) */ + } /* for (j = ...) */ + } /* for (i = ...) */ + + } else { + + /* + * Encode differential layer + */ + + for (i = 0; i < hl && y < hy; i++, y++) { + + /* check whether it is worth to perform an ATMOVE */ + if (!at_determined && c_all > 2048) { + cmin = clmin = 0xffffffffL; + cmax = clmax = 0; + tmax = 0; + for (t = 3; t <= s->mx; t++) { + if (c[t] > cmax) cmax = c[t]; + if (c[t] < cmin) cmin = c[t]; + if (c[t] > c[tmax]) tmax = t; + } + clmin = (c[0] < cmin) ? c[0] : cmin; + clmax = (c[0] > cmax) ? c[0] : cmax; + if (c_all - cmax < (c_all >> 3) && + cmax - c[s->tx[plane]] > c_all - cmax && + cmax - c[s->tx[plane]] > (c_all >> 4) && + /* ^ T.82 said < here, fixed in Cor.1/25 */ + cmax - (c_all - c[s->tx[plane]]) > c_all - cmax && + cmax - (c_all - c[s->tx[plane]]) > (c_all >> 4) && + cmax - cmin > (c_all >> 2) && + (s->tx[plane] || clmax - clmin > (c_all >> 3))) { + /* we have decided to perform an ATMOVE */ + new_tx = tmax; + if (!(s->options & JBG_DELAY_AT)) { + new_tx_line = i; + s->tx[plane] = new_tx; + } +#ifdef DEBUG + fprintf(stderr, "ATMOVE: line=%ld, tx=%d, c_all=%ld\n", + i, new_tx, c_all); +#endif + } + at_determined = 1; + } + + if ((i >> 1) >= ll - 1 || (y >> 1) >= ly - 1) + lp1 = lp2; + + /* typical prediction */ + if (s->options & JBG_TPDON && (i & 1) == 0) { + q1 = lp1; q2 = lp2; + p0 = p1 = hp; + if (i < hl - 1 && y < hy - 1) + p0 = hp + hbpl; + if (i > 1 || !reset) + line_l3 = (long)*(q2 - lbpl) << 8; + else + line_l3 = 0; + line_l2 = (long)*q2 << 8; + line_l1 = (long)*q1 << 8; + ltp = 1; + for (j = 0; j < lx && ltp; q1++, q2++) { + if (j < lbpl * 8 - 8) { + if (i > 1 || !reset) + line_l3 |= *(q2 - lbpl + 1); + line_l2 |= *(q2 + 1); + line_l1 |= *(q1 + 1); + } + do { + if ((j >> 2) < hbpl) { + line_h1 = *(p1++); + line_h0 = *(p0++); + } + do { + line_l3 <<= 1; + line_l2 <<= 1; + line_l1 <<= 1; + line_h1 <<= 2; + line_h0 <<= 2; + cx = (((line_l3 >> 15) & 0x007) | + ((line_l2 >> 12) & 0x038) | + ((line_l1 >> 9) & 0x1c0)); + if (cx == 0x000) + if ((line_h1 & 0x300) == 0 && (line_h0 & 0x300) == 0) + s->tp[j] = 0; + else { + ltp = 0; +#ifdef DEBUG + tp_exceptions++; +#endif + } + else if (cx == 0x1ff) + if ((line_h1 & 0x300) == 0x300 && (line_h0 & 0x300) == 0x300) + s->tp[j] = 1; + else { + ltp = 0; +#ifdef DEBUG + tp_exceptions++; +#endif + } + else + s->tp[j] = 2; + } while (++j & 3 && j < lx); + } while (j & 7 && j < lx); + } /* for (j = ...) */ + arith_encode(se, TPDCX, !ltp); +#ifdef DEBUG + tp_lines += ltp; +#endif + } + + + /* + * Layout of the variables line_h1, line_h2, line_h3, which contain + * as bits the high resolution neighbour pixels of the currently coded + * highres pixel X: + * + * 76543210 76543210 76543210 76543210 line_h3 + * 76543210 76543210 76543210 76543210 line_h2 + * 76543210 76543210 7654321X 76543210 line_h1 + * + * Layout of the variables line_l1, line_l2, line_l3, which contain + * the low resolution pixels near the currently coded pixel as bits. + * The lowres pixel in which the currently coded highres pixel is + * located is marked as Y: + * + * 76543210 76543210 76543210 76543210 line_l3 + * 76543210 7654321Y 76543210 76543210 line_l2 + * 76543210 76543210 76543210 76543210 line_l1 + */ + + + line_h1 = line_h2 = line_h3 = line_l1 = line_l2 = line_l3 = 0; + if (i > 0 || !reset) line_h2 = (long)*(hp - hbpl) << 8; + if (i > 1 || !reset) { + line_h3 = (long)*(hp - hbpl - hbpl) << 8; + line_l3 = (long)*(lp2 - lbpl) << 8; + } + line_l2 = (long)*lp2 << 8; + line_l1 = (long)*lp1 << 8; + + /* encode line */ + for (j = 0; j < hx; lp1++, lp2++) { + if ((j >> 1) < lbpl * 8 - 8) { + if (i > 1 || !reset) + line_l3 |= *(lp2 - lbpl + 1); + line_l2 |= *(lp2 + 1); + line_l1 |= *(lp1 + 1); + } + do { /* ... while (j & 15 && j < hx) */ + + assert(hp - (s->lhp[s->highres[plane]][plane] + + (stripe * hl + i) * hbpl) + == (ptrdiff_t) j >> 3); + + assert(lp2 - (s->lhp[1-s->highres[plane]][plane] + + (stripe * ll + (i>>1)) * lbpl) + == (ptrdiff_t) j >> 4); + + line_h1 |= *hp; + if (j < hbpl * 8 - 8) { + if (i > 0 || !reset) { + line_h2 |= *(hp - hbpl + 1); + if (i > 1 || !reset) + line_h3 |= *(hp - hbpl - hbpl + 1); + } + } + do { /* ... while (j & 7 && j < hx) */ + line_l1 <<= 1; line_l2 <<= 1; line_l3 <<= 1; + if (ltp && s->tp[j >> 1] < 2) { + /* pixel are typical and have not to be encoded */ + line_h1 <<= 2; line_h2 <<= 2; line_h3 <<= 2; +#ifdef DEBUG + do { + ++tp_pixels; + } while (++j & 1 && j < hx); +#else + j += 2; +#endif + } else + do { /* ... while (++j & 1 && j < hx) */ + line_h1 <<= 1; line_h2 <<= 1; line_h3 <<= 1; + + /* deterministic prediction */ + if (s->options & JBG_DPON) { + if ((y & 1) == 0) { + if ((j & 1) == 0) { + /* phase 0 */ + if (s->dppriv[((line_l3 >> 16) & 0x003) | + ((line_l2 >> 14) & 0x00c) | + ((line_h1 >> 5) & 0x010) | + ((line_h2 >> 10) & 0x0e0)] < 2) { +#ifdef DEBUG + ++dp_pixels; +#endif + continue; + } + } else { + /* phase 1 */ + if (s->dppriv[(((line_l3 >> 16) & 0x003) | + ((line_l2 >> 14) & 0x00c) | + ((line_h1 >> 5) & 0x030) | + ((line_h2 >> 10) & 0x1c0)) + 256] < 2) { +#ifdef DEBUG + ++dp_pixels; +#endif + continue; + } + } + } else { + if ((j & 1) == 0) { + /* phase 2 */ + if (s->dppriv[(((line_l3 >> 16) & 0x003) | + ((line_l2 >> 14) & 0x00c) | + ((line_h1 >> 5) & 0x010) | + ((line_h2 >> 10) & 0x0e0) | + ((line_h3 >> 7) & 0x700)) + 768] < 2) { +#ifdef DEBUG + ++dp_pixels; +#endif + continue; + } + } else { + /* phase 3 */ + if (s->dppriv[(((line_l3 >> 16) & 0x003) | + ((line_l2 >> 14) & 0x00c) | + ((line_h1 >> 5) & 0x030) | + ((line_h2 >> 10) & 0x1c0) | + ((line_h3 >> 7) & 0xe00)) + 2816] < 2) { +#ifdef DEBUG + ++dp_pixels; +#endif + continue; + } + } + } + } + + /* determine context */ + if (s->tx[plane]) { + if ((unsigned) s->tx[plane] > j) + a = 0; + else { + o = (j - s->tx[plane]) - (j & ~7L); + a = (hp[o >> 3] >> (7 - (o & 7))) & 1; + a <<= 4; + } + assert(s->tx[plane] > 23 || + a == ((line_h1 >> (4 + s->tx[plane])) & 0x010)); + cx = (((line_h1 >> 9) & 0x003) | a | + ((line_h2 >> 13) & 0x00c) | + ((line_h3 >> 11) & 0x020)); + } else + cx = (((line_h1 >> 9) & 0x003) | + ((line_h2 >> 13) & 0x01c) | + ((line_h3 >> 11) & 0x020)); + if (j & 1) + cx |= (((line_l2 >> 9) & 0x0c0) | + ((line_l1 >> 7) & 0x300)) | (1UL << 10); + else + cx |= (((line_l2 >> 10) & 0x0c0) | + ((line_l1 >> 8) & 0x300)); + cx |= (y & 1) << 11; + + arith_encode(se, cx, (line_h1 >> 8) & 1); +#ifdef DEBUG + encoded_pixels++; +#endif + + /* statistics for adaptive template changes */ + if (!at_determined && j >= s->mx) { + c[0] += !(((line_h2 >> 6) ^ line_h1) & 0x100); + for (t = 3; t <= s->mx; t++) + c[t] += !(((line_h1 >> t) ^ line_h1) & 0x100); + ++c_all; + } + + } while (++j & 1 && j < hx); + } while (j & 7 && j < hx); + hp++; + } while (j & 15 && j < hx); + } /* for (j = ...) */ + + /* low resolution pixels are used twice */ + if ((i & 1) == 0) { + lp1 -= lbpl; + lp2 -= lbpl; + } + + } /* for (i = ...) */ + } + + arith_encode_flush(se); + jbg_buf_remove_zeros(s->sde[stripe][layer][plane]); + jbg_buf_write(MARKER_ESC, s->sde[stripe][layer][plane]); + jbg_buf_write((s->options & JBG_SDRST) ? MARKER_SDRST : MARKER_SDNORM, + s->sde[stripe][layer][plane]); + if (s->options & JBG_SDRST) + s->tx[plane] = 0; + + /* add ATMOVE */ + if (new_tx != -1) { + if (s->options & JBG_DELAY_AT) { + /* ATMOVE will become active at the first line of the next stripe */ + s->tx[plane] = new_tx; + jbg_buf_write(MARKER_ESC, s->sde[stripe][layer][plane]); + jbg_buf_write(MARKER_ATMOVE, s->sde[stripe][layer][plane]); + jbg_buf_write(0, s->sde[stripe][layer][plane]); + jbg_buf_write(0, s->sde[stripe][layer][plane]); + jbg_buf_write(0, s->sde[stripe][layer][plane]); + jbg_buf_write(0, s->sde[stripe][layer][plane]); + jbg_buf_write(s->tx[plane], s->sde[stripe][layer][plane]); + jbg_buf_write(0, s->sde[stripe][layer][plane]); + } else { + /* ATMOVE has already become active during this stripe + * => we have to prefix the SDE data with an ATMOVE marker */ + new_jbg_buf = jbg_buf_init(&s->free_list); + jbg_buf_write(MARKER_ESC, new_jbg_buf); + jbg_buf_write(MARKER_ATMOVE, new_jbg_buf); + jbg_buf_write((new_tx_line >> 24) & 0xff, new_jbg_buf); + jbg_buf_write((new_tx_line >> 16) & 0xff, new_jbg_buf); + jbg_buf_write((new_tx_line >> 8) & 0xff, new_jbg_buf); + jbg_buf_write(new_tx_line & 0xff, new_jbg_buf); + jbg_buf_write(new_tx, new_jbg_buf); + jbg_buf_write(0, new_jbg_buf); + jbg_buf_prefix(new_jbg_buf, &s->sde[stripe][layer][plane]); + } + } + +#if 0 + if (stripe == s->stripes - 1) + fprintf(stderr, "tp_lines = %ld, tp_exceptions = %ld, tp_pixels = %ld, " + "dp_pixels = %ld, encoded_pixels = %ld\n", + tp_lines, tp_exceptions, tp_pixels, dp_pixels, encoded_pixels); +#endif + + return; +} + + +/* + * Create the next lower resolution version of an image + */ +static void resolution_reduction(struct jbg_enc_state *s, int plane, + int higher_layer) +{ + unsigned long hl, ll, hx, hy, lx, ly, hbpl, lbpl; + unsigned char *hp1, *hp2, *hp3, *lp; + unsigned long line_h1, line_h2, line_h3, line_l2; + unsigned long y; /* current line number in lowres image */ + unsigned long i; /* current line number within lowres stripe */ + unsigned long j; /* current column number in lowres image */ + int pix, k, l; + + /* number of lines per stripe in highres image */ + hl = s->l0 << higher_layer; + /* number of lines per stripe in lowres image */ + ll = hl >> 1; + /* number of pixels in highres image */ + hx = jbg_ceil_half(s->xd, s->d - higher_layer); + hy = jbg_ceil_half(s->yd, s->d - higher_layer); + /* number of pixels in lowres image */ + lx = jbg_ceil_half(hx, 1); + ly = jbg_ceil_half(hy, 1); + /* bytes per line in highres and lowres image */ + hbpl = jbg_ceil_half(hx, 3); + lbpl = jbg_ceil_half(lx, 3); + /* pointers to first image bytes */ + hp2 = s->lhp[s->highres[plane]][plane]; + hp1 = hp2 + hbpl; + hp3 = hp2 - hbpl; + lp = s->lhp[1 - s->highres[plane]][plane]; + +#ifdef DEBUG + fprintf(stderr, "resolution_reduction: plane = %d, higher_layer = %d\n", + plane, higher_layer); +#endif + + /* + * Layout of the variables line_h1, line_h2, line_h3, which contain + * as bits the high resolution neighbour pixels of the currently coded + * lowres pixel /\: + * \/ + * + * 76543210 76543210 76543210 76543210 line_h3 + * 76543210 76543210 765432/\ 76543210 line_h2 + * 76543210 76543210 765432\/ 76543210 line_h1 + * + * Layout of the variable line_l2, which contains the low resolution + * pixels near the currently coded pixel as bits. The lowres pixel + * which is currently coded is marked as X: + * + * 76543210 76543210 76543210 76543210 line_l2 + * X + */ + + for (y = 0; y < ly;) { + for (i = 0; i < ll && y < ly; i++, y++) { + if (2*y + 1 >= hy) + hp1 = hp2; + pix = 0; + line_h1 = line_h2 = line_h3 = line_l2 = 0; + for (j = 0; j < lbpl * 8; j += 8) { + *lp = 0; + if (i > 0 || (y > 0 && !(s->options & JBG_SDRST))) + line_l2 |= *(lp-lbpl); + for (k = 0; k < 8 && j + k < lx; k += 4) { + if (((j + k) >> 2) < hbpl) { + if (i > 0 || (y > 0 && !(s->options & JBG_SDRST))) + line_h3 |= *hp3; + ++hp3; + line_h2 |= *(hp2++); + line_h1 |= *(hp1++); + } + for (l = 0; l < 4 && j + k + l < lx; l++) { + line_h3 <<= 2; + line_h2 <<= 2; + line_h1 <<= 2; + line_l2 <<= 1; + pix = s->res_tab[((line_h1 >> 8) & 0x007) | + ((line_h2 >> 5) & 0x038) | + ((line_h3 >> 2) & 0x1c0) | + (pix << 9) | ((line_l2 << 2) & 0xc00)]; + *lp = (*lp << 1) | pix; + } + } + ++lp; + } + *(lp - 1) <<= lbpl * 8 - lx; + hp1 += hbpl; + hp2 += hbpl; + hp3 += hbpl; + } + } + +#ifdef DEBUG + { + FILE *f; + char fn[50]; + + sprintf(fn, "dbg_d=%02d.pbm", higher_layer - 1); + f = fopen(fn, "wb"); + fprintf(f, "P4\n%lu %lu\n", lx, ly); + fwrite(s->lhp[1 - s->highres[plane]][plane], 1, lbpl * ly, f); + fclose(f); + } +#endif + + return; +} + + +/* + * This function is called inside the three loops of jbg_enc_out() in + * order to write the next SDE. It has first to generate the required + * SDE and all SDEs which have to be encoded before this SDE can be + * created. The problem here is that if we want to output a lower + * resolution layer, we have to apply the resolution reduction + * algorithm first to get it. As we try to safe as much memory as + * possible, the resolution reduction will overwrite previous higher + * resolution bitmaps. Consequently, we have to encode and buffer SDEs + * which depend on higher resolution layers before we can start the + * resolution reduction. All the logic about which SDE has to be + * encoded before resolution reduction is allowed is handled + * here. This approach may be a bit more complex than alternative ways + * of doing it, but it minimizes the amount of temporary memory used. + */ +static void output_sde(struct jbg_enc_state *s, + unsigned long stripe, int layer, int plane) +{ + int lfcl; /* lowest fully coded layer */ + long i; + unsigned long u; + + assert(s->sde[stripe][layer][plane] != SDE_DONE); + + if (s->sde[stripe][layer][plane] != SDE_TODO) { +#ifdef DEBUG + fprintf(stderr, "writing SDE: s/d/p = %2lu/%2d/%2d\n", + stripe, layer, plane); +#endif + jbg_buf_output(&s->sde[stripe][layer][plane], s->data_out, s->file); + s->sde[stripe][layer][plane] = SDE_DONE; + return; + } + + /* Determine the smallest resolution layer in this plane for which + * not yet all stripes have been encoded into SDEs. This layer will + * have to be completely coded, before we can apply the next + * resolution reduction step. */ + lfcl = 0; + for (i = s->d; i >= 0; i--) + if (s->sde[s->stripes - 1][i][plane] == SDE_TODO) { + lfcl = i + 1; + break; + } + if (lfcl > s->d && s->d > 0 && stripe == 0) { + /* perform the first resolution reduction */ + resolution_reduction(s, plane, s->d); + } + /* In case HITOLO is not used, we have to encode and store the higher + * resolution layers first, although we do not need them right now. */ + while (lfcl - 1 > layer) { + for (u = 0; u < s->stripes; u++) + encode_sde(s, u, lfcl - 1, plane); + --lfcl; + s->highres[plane] ^= 1; + if (lfcl > 1) + resolution_reduction(s, plane, lfcl - 1); + } + + encode_sde(s, stripe, layer, plane); + +#ifdef DEBUG + fprintf(stderr, "writing SDE: s/d/p = %2lu/%2d/%2d\n", stripe, layer, plane); +#endif + jbg_buf_output(&s->sde[stripe][layer][plane], s->data_out, s->file); + s->sde[stripe][layer][plane] = SDE_DONE; + + if (stripe == s->stripes - 1 && layer > 0 && + s->sde[0][layer-1][plane] == SDE_TODO) { + s->highres[plane] ^= 1; + if (layer > 1) + resolution_reduction(s, plane, layer - 1); + } + + return; +} + + +/* + * Convert the table which controls the deterministic prediction + * process from the internal format into the representation required + * for the 1728 byte long DPTABLE element of a BIH. + * + * The bit order of the DPTABLE format (see also ITU-T T.82 figure 13) is + * + * high res: 4 5 6 low res: 0 1 + * 7 8 9 2 3 + * 10 11 12 + * + * were 4 table entries are packed into one byte, while we here use + * internally an unpacked 6912 byte long table indexed by the following + * bit order: + * + * high res: 7 6 5 high res: 8 7 6 low res: 1 0 + * (phase 0) 4 . . (phase 1) 5 4 . 3 2 + * . . . . . . + * + * high res: 10 9 8 high res: 11 10 9 + * (phase 2) 7 6 5 (phase 3) 8 7 6 + * 4 . . 5 4 . + */ +void jbg_int2dppriv(unsigned char *dptable, const char *internal) +{ + int i, j, k; + int trans0[ 8] = { 1, 0, 3, 2, 7, 6, 5, 4 }; + int trans1[ 9] = { 1, 0, 3, 2, 8, 7, 6, 5, 4 }; + int trans2[11] = { 1, 0, 3, 2, 10, 9, 8, 7, 6, 5, 4 }; + int trans3[12] = { 1, 0, 3, 2, 11, 10, 9, 8, 7, 6, 5, 4 }; + + for (i = 0; i < 1728; dptable[i++] = 0) ; + +#define FILL_TABLE1(offset, len, trans) \ + for (i = 0; i < len; i++) { \ + k = 0; \ + for (j = 0; i >> j; j++) \ + k |= ((i >> j) & 1) << trans[j]; \ + dptable[(i + offset) >> 2] |= \ + (internal[k + offset] & 3) << ((3 - (i&3)) << 1); \ + } + + FILL_TABLE1( 0, 256, trans0); + FILL_TABLE1( 256, 512, trans1); + FILL_TABLE1( 768, 2048, trans2); + FILL_TABLE1(2816, 4096, trans3); + + return; +} + + +/* + * Convert the table which controls the deterministic prediction + * process from the 1728 byte long DPTABLE format into the 6912 byte long + * internal format. + */ +void jbg_dppriv2int(char *internal, const unsigned char *dptable) +{ + int i, j, k; + int trans0[ 8] = { 1, 0, 3, 2, 7, 6, 5, 4 }; + int trans1[ 9] = { 1, 0, 3, 2, 8, 7, 6, 5, 4 }; + int trans2[11] = { 1, 0, 3, 2, 10, 9, 8, 7, 6, 5, 4 }; + int trans3[12] = { 1, 0, 3, 2, 11, 10, 9, 8, 7, 6, 5, 4 }; + +#define FILL_TABLE2(offset, len, trans) \ + for (i = 0; i < len; i++) { \ + k = 0; \ + for (j = 0; i >> j; j++) \ + k |= ((i >> j) & 1) << trans[j]; \ + internal[k + offset] = \ + (dptable[(i + offset) >> 2] >> ((3 - (i & 3)) << 1)) & 3; \ + } + + FILL_TABLE2( 0, 256, trans0); + FILL_TABLE2( 256, 512, trans1); + FILL_TABLE2( 768, 2048, trans2); + FILL_TABLE2(2816, 4096, trans3); + + return; +} + + +/* + * Encode one full BIE and pass the generated data to the specified + * call-back function + */ +void jbg_enc_out(struct jbg_enc_state *s) +{ + unsigned long bpl; + unsigned char buf[20]; + unsigned long xd, yd, y; + long ii[3], is[3], ie[3]; /* generic variables for the 3 nested loops */ + unsigned long stripe; + int layer, plane; + int order; + unsigned char dpbuf[1728]; + + /* some sanity checks */ + s->order &= JBG_HITOLO | JBG_SEQ | JBG_ILEAVE | JBG_SMID; + order = s->order & (JBG_SEQ | JBG_ILEAVE | JBG_SMID); + if (iindex[order][0] < 0) + s->order = order = JBG_SMID | JBG_ILEAVE; + if (s->options & JBG_DPON && s->dppriv != jbg_dptable) + s->options |= JBG_DPPRIV; + if (s->mx > MX_MAX) + s->mx = MX_MAX; + s->my = 0; + if (s->mx && s->mx < ((s->options & JBG_LRLTWO) ? 5U : 3U)) + s->mx = 0; + if (s->d > 255 || s->d < 0 || s->dh > s->d || s->dh < 0 || + s->dl < 0 || s->dl > s->dh || s->planes < 0 || s->planes > 255) + return; + /* prevent uint32 overflow: s->l0 * 2 ^ s->d < 2 ^ 32 */ + if (s->d > 31 || (s->d != 0 && s->l0 >= (1UL << (32 - s->d)))) + return; + if (s->yd1 < s->yd) + s->yd1 = s->yd; + if (s->yd1 > s->yd) + s->options |= JBG_VLENGTH; + + /* ensure correct zero padding of bitmap at the final byte of each line */ + if (s->xd & 7) { + bpl = jbg_ceil_half(s->xd, 3); /* bytes per line */ + for (plane = 0; plane < s->planes; plane++) + for (y = 0; y < s->yd; y++) + s->lhp[0][plane][y * bpl + bpl - 1] &= ~((1 << (8 - (s->xd & 7))) - 1); + } + + /* prepare BIH */ + buf[0] = s->dl; + buf[1] = s->dh; + buf[2] = s->planes; + buf[3] = 0; + xd = jbg_ceil_half(s->xd, s->d - s->dh); + yd = jbg_ceil_half(s->yd1, s->d - s->dh); + buf[4] = xd >> 24; + buf[5] = (xd >> 16) & 0xff; + buf[6] = (xd >> 8) & 0xff; + buf[7] = xd & 0xff; + buf[8] = yd >> 24; + buf[9] = (yd >> 16) & 0xff; + buf[10] = (yd >> 8) & 0xff; + buf[11] = yd & 0xff; + buf[12] = s->l0 >> 24; + buf[13] = (s->l0 >> 16) & 0xff; + buf[14] = (s->l0 >> 8) & 0xff; + buf[15] = s->l0 & 0xff; + buf[16] = s->mx; + buf[17] = s->my; + buf[18] = s->order; + buf[19] = s->options & 0x7f; + +#if 0 + /* sanitize L0 (if it was set to 0xffffffff for T.85-style NEWLEN tests) */ + if (s->l0 > (s->yd >> s->d)) + s->l0 = s->yd >> s->d; +#endif + + /* calculate number of stripes that will be required */ + s->stripes = jbg_stripes(s->l0, s->yd, s->d); + + /* allocate buffers for SDE pointers */ + if (s->sde == NULL) { + s->sde = (struct jbg_buf ****) + checked_malloc(s->stripes, sizeof(struct jbg_buf ***)); + for (stripe = 0; stripe < s->stripes; stripe++) { + s->sde[stripe] = (struct jbg_buf ***) + checked_malloc(s->d + 1, sizeof(struct jbg_buf **)); + for (layer = 0; layer < s->d + 1; layer++) { + s->sde[stripe][layer] = (struct jbg_buf **) + checked_malloc(s->planes, sizeof(struct jbg_buf *)); + for (plane = 0; plane < s->planes; plane++) + s->sde[stripe][layer][plane] = SDE_TODO; + } + } + } + + /* output BIH */ + s->data_out(buf, 20, s->file); + if ((s->options & (JBG_DPON | JBG_DPPRIV | JBG_DPLAST)) == + (JBG_DPON | JBG_DPPRIV)) { + /* write private table */ + jbg_int2dppriv(dpbuf, s->dppriv); + s->data_out(dpbuf, 1728, s->file); + } + +#if 0 + /* + * Encode everything first. This is a simple-minded alternative to + * all the tricky on-demand encoding logic in output_sde() for + * debugging purposes. + */ + for (layer = s->dh; layer >= s->dl; layer--) { + for (plane = 0; plane < s->planes; plane++) { + if (layer > 0) + resolution_reduction(s, plane, layer); + for (stripe = 0; stripe < s->stripes; stripe++) + encode_sde(s, stripe, layer, plane); + s->highres[plane] ^= 1; + } + } +#endif + + /* + * Generic loops over all SDEs. Which loop represents layer, plane and + * stripe depends on the option flags. + */ + + /* start and end value for each loop */ + is[iindex[order][STRIPE]] = 0; + ie[iindex[order][STRIPE]] = s->stripes - 1; + is[iindex[order][LAYER]] = s->dl; + ie[iindex[order][LAYER]] = s->dh; + is[iindex[order][PLANE]] = 0; + ie[iindex[order][PLANE]] = s->planes - 1; + + for (ii[0] = is[0]; ii[0] <= ie[0]; ii[0]++) + for (ii[1] = is[1]; ii[1] <= ie[1]; ii[1]++) + for (ii[2] = is[2]; ii[2] <= ie[2]; ii[2]++) { + + stripe = ii[iindex[order][STRIPE]]; + if (s->order & JBG_HITOLO) + layer = s->dh - (ii[iindex[order][LAYER]] - s->dl); + else + layer = ii[iindex[order][LAYER]]; + plane = ii[iindex[order][PLANE]]; + + /* output comment marker segment if there is any pending */ + if (s->comment) { + buf[0] = MARKER_ESC; + buf[1] = MARKER_COMMENT; + buf[2] = s->comment_len >> 24; + buf[3] = (s->comment_len >> 16) & 0xff; + buf[4] = (s->comment_len >> 8) & 0xff; + buf[5] = s->comment_len & 0xff; + s->data_out(buf, 6, s->file); + s->data_out(s->comment, s->comment_len, s->file); + s->comment = NULL; + } + + output_sde(s, stripe, layer, plane); + + /* + * When we generate a NEWLEN test case (s->yd1 > s->yd), output + * NEWLEN after last stripe if we have only a single + * resolution layer or plane (see ITU-T T.85 profile), otherwise + * output NEWLEN before last stripe. + */ + if (s->yd1 > s->yd && + (stripe == s->stripes - 1 || + (stripe == s->stripes - 2 && + (s->dl != s->dh || s->planes > 1)))) { + s->yd1 = s->yd; + yd = jbg_ceil_half(s->yd, s->d - s->dh); + buf[0] = MARKER_ESC; + buf[1] = MARKER_NEWLEN; + buf[2] = yd >> 24; + buf[3] = (yd >> 16) & 0xff; + buf[4] = (yd >> 8) & 0xff; + buf[5] = yd & 0xff; + s->data_out(buf, 6, s->file); +#ifdef DEBUG + fprintf(stderr, "NEWLEN: yd=%lu\n", yd); +#endif + if (stripe == s->stripes - 1) { + buf[1] = MARKER_SDNORM; + s->data_out(buf, 2, s->file); + } + } + + } + + return; +} + + +void jbg_enc_free(struct jbg_enc_state *s) +{ + unsigned long stripe; + int layer, plane; + +#ifdef DEBUG + fprintf(stderr, "jbg_enc_free(%p)\n", (void *) s); +#endif + + /* clear buffers for SDEs */ + if (s->sde) { + for (stripe = 0; stripe < s->stripes; stripe++) { + for (layer = 0; layer < s->d + 1; layer++) { + for (plane = 0; plane < s->planes; plane++) + if (s->sde[stripe][layer][plane] != SDE_DONE && + s->sde[stripe][layer][plane] != SDE_TODO) + jbg_buf_free(&s->sde[stripe][layer][plane]); + checked_free(s->sde[stripe][layer]); + } + checked_free(s->sde[stripe]); + } + checked_free(s->sde); + } + + /* clear free_list */ + jbg_buf_free(&s->free_list); + + /* clear memory for arithmetic encoder states */ + checked_free(s->s); + + /* clear memory for differential-layer typical prediction buffer */ + checked_free(s->tp); + + /* clear memory for adaptive template pixel offsets */ + checked_free(s->tx); + + /* clear lowres image buffers */ + if (s->lhp[1]) { + for (plane = 0; plane < s->planes; plane++) + checked_free(s->lhp[1][plane]); + checked_free(s->lhp[1]); + } + + /* clear buffer for index of highres image in lhp */ + checked_free(s->highres); + + return; +} + + +/* + * Convert the error codes used by jbg_dec_in() into an English ASCII string + */ +const char *jbg_strerror(int errnum) +{ + errnum >>= 4; + if (errnum < 0 || (unsigned) errnum >= sizeof(errmsg)/sizeof(errmsg[0])) + return "Unknown error code passed to jbg_strerror()"; + + return errmsg[errnum]; +} + + +/* + * The constructor for a decoder + */ +void jbg_dec_init(struct jbg_dec_state *s) +{ + s->order = 0; + s->d = -1; + s->bie_len = 0; + s->buf_len = 0; + s->dppriv = NULL; + s->xmax = 4294967295UL; + s->ymax = 4294967295UL; + s->dmax = 256; + s->s = NULL; + + return; +} + + +/* + * Specify a maximum image size for the decoder. If the JBIG file has + * the order bit ILEAVE, but not the bit SEQ set, then the decoder + * will abort to decode after the image has reached the maximal + * resolution layer which is still not wider than xmax or higher than + * ymax. + */ +void jbg_dec_maxsize(struct jbg_dec_state *s, unsigned long xmax, + unsigned long ymax) +{ + if (xmax > 0) s->xmax = xmax; + if (ymax > 0) s->ymax = ymax; + + return; +} + + +/* + * Decode the new len PSDC bytes to which data points and add them to + * the current stripe. Return the number of bytes which have actually + * been read (this will be less than len if a marker segment was + * part of the data or if the final byte was 0xff, in which case + * this code cannot determine whether we have a marker segment). + */ +static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data, + size_t len) +{ + unsigned long stripe; + unsigned int layer, plane; + unsigned long hl, ll, y, hx, hy, lx, ly, hbpl, lbpl; + unsigned char *hp, *lp1, *lp2, *p1, *q1; + register unsigned long line_h1, line_h2, line_h3; + register unsigned long line_l1, line_l2, line_l3; + struct jbg_ardec_state *se; + unsigned long x; + long o; + unsigned a; + int n; + int pix, cx = 0, slntp, tx; + + /* SDE loop variables */ + stripe = s->ii[iindex[s->order & 7][STRIPE]]; + layer = s->ii[iindex[s->order & 7][LAYER]]; + plane = s->ii[iindex[s->order & 7][PLANE]]; + + /* forward data to arithmetic decoder */ + se = s->s[plane] + layer - s->dl; + se->pscd_ptr = data; + se->pscd_end = data + len; + + /* number of lines per stripe in highres image */ + hl = s->l0 << layer; + /* number of lines per stripe in lowres image */ + ll = hl >> 1; + /* current line number in highres image */ + y = stripe * hl + s->i; + /* number of pixels in highres image */ + hx = jbg_ceil_half(s->xd, s->d - layer); + hy = jbg_ceil_half(s->yd, s->d - layer); + /* number of pixels in lowres image */ + lx = jbg_ceil_half(hx, 1); + ly = jbg_ceil_half(hy, 1); + /* bytes per line in highres and lowres image */ + hbpl = jbg_ceil_half(hx, 3); + lbpl = jbg_ceil_half(lx, 3); + /* pointer to highres and lowres image bytes */ + hp = s->lhp[ layer & 1][plane] + (stripe * hl + s->i) * hbpl + + (s->x >> 3); + lp2 = s->lhp[(layer-1) & 1][plane] + (stripe * ll + (s->i >> 1)) * lbpl + + (s->x >> 4); + lp1 = lp2 + lbpl; + + /* restore a few local variables */ + line_h1 = s->line_h1; + line_h2 = s->line_h2; + line_h3 = s->line_h3; + line_l1 = s->line_l1; + line_l2 = s->line_l2; + line_l3 = s->line_l3; + x = s->x; + +#ifdef DEBUG + if (s->x == 0 && s->i == 0 && s->pseudo) + fprintf(stderr, "decode_pscd(%p, %p, %ld): s/d/p = %2lu/%2u/%2u\n", + (void *) s, (void *) data, (long) len, stripe, layer, plane); +#endif + + if (s->x == 0 && s->i == 0 && + (stripe == 0 || s->reset[plane][layer - s->dl]) && s->pseudo) { + s->tx[plane][layer - s->dl] = s->ty[plane][layer - s->dl] = 0; + s->lntp[plane][layer - s->dl] = 1; + } + + if (layer == 0) { + + /* + * Decode lowest resolution layer + */ + + for (; s->i < hl && y < hy; s->i++, y++) { + + /* adaptive template changes */ + if (x == 0 && s->pseudo) + for (n = 0; n < s->at_moves; n++) + if (s->at_line[n] == s->i) { + s->tx[plane][layer - s->dl] = s->at_tx[n]; + s->ty[plane][layer - s->dl] = s->at_ty[n]; +#ifdef DEBUG + fprintf(stderr, "ATMOVE: line=%lu, tx=%d, ty=%d.\n", s->i, + s->tx[plane][layer - s->dl], s->ty[plane][layer - s->dl]); +#endif + } + tx = s->tx[plane][layer - s->dl]; + assert(tx >= 0); /* i.e., tx can safely be cast to unsigned */ + + /* typical prediction */ + if (s->options & JBG_TPBON && s->pseudo) { + slntp = arith_decode(se, (s->options & JBG_LRLTWO) ? TPB2CX : TPB3CX); + if (slntp < 0) + goto leave; + s->lntp[plane][layer - s->dl] = + !(slntp ^ s->lntp[plane][layer - s->dl]); + if (!s->lntp[plane][layer - s->dl]) { + /* this line is 'typical' (i.e. identical to the previous one) */ + p1 = hp; + if (s->i == 0 && (stripe == 0 || s->reset[plane][layer - s->dl])) + while (p1 < hp + hbpl) *p1++ = 0; + else { + q1 = hp - hbpl; + while (q1 < hp) *p1++ = *q1++; + } + hp += hbpl; + continue; + } + /* this line is 'not typical' and has to be coded completely */ + } + s->pseudo = 0; + + /* + * Layout of the variables line_h1, line_h2, line_h3, which contain + * as bits the neighbour pixels of the currently decoded pixel X: + * + * 76543210 76543210 76543210 76543210 line_h3 + * 76543210 76543210 76543210 76543210 line_h2 + * 76543210 76543210 76543210 76543210 X line_h1 + */ + + if (x == 0) { + line_h1 = line_h2 = line_h3 = 0; + if (s->i > 0 || (y > 0 && !s->reset[plane][layer - s->dl])) + line_h2 = (long)*(hp - hbpl) << 8; + if (s->i > 1 || (y > 1 && !s->reset[plane][layer - s->dl])) + line_h3 = (long)*(hp - hbpl - hbpl) << 8; + } + + /* + * Another tiny JBIG standard bug: + * + * While implementing the line_h3 handling here, I discovered + * another problem with the ITU-T T.82(1993 E) specification. + * This might be a somewhat pathological case, however. The + * standard is unclear about how a decoder should behave in the + * following situation: + * + * Assume we are in layer 0 and all stripes are single lines + * (L0=1 allowed by table 9). We are now decoding the first (and + * only) line of the third stripe. Assume, the first stripe was + * terminated by SDRST and the second stripe was terminated by + * SDNORM. While decoding the only line of the third stripe with + * the three-line template, we need access to pixels from the + * previous two stripes. We know that the previous stripe + * terminated with SDNROM, so we access the pixel from the + * second stripe. But do we have to replace the pixels from the + * first stripe by background pixels, because this stripe ended + * with SDRST? The standard, especially clause 6.2.5 does never + * mention this case, so the behaviour is undefined here. My + * current implementation remembers only the marker used to + * terminate the previous stripe. In the above example, the + * pixels of the first stripe are accessed despite the fact that + * this stripe ended with SDRST. An alternative (only slightly + * more complicated) implementation would be to remember the end + * marker (SDNORM or SDRST) of the previous two stripes in a + * plane/layer and to act accordingly when accessing the two + * previous lines. What am I supposed to do here? + * + * As the standard is unclear about the correct behaviour in the + * situation of the above example, I strongly suggest to avoid + * the following situation while encoding data with JBIG: + * + * LRLTWO = 0, L0=1 and both SDNORM and SDRST appear in layer 0. + * + * I guess that only a very few if any encoders will switch + * between SDNORM and SDRST, so let us hope that this ambiguity + * in the standard will never cause any interoperability + * problems. + * + * Markus Kuhn -- 1995-04-30 + */ + + /* decode line */ + while (x < hx) { + if ((x & 7) == 0) { + if (x < hbpl * 8 - 8 && + (s->i > 0 || (y > 0 && !s->reset[plane][layer - s->dl]))) { + line_h2 |= *(hp - hbpl + 1); + if (s->i > 1 || (y > 1 && !s->reset[plane][layer - s->dl])) + line_h3 |= *(hp - hbpl - hbpl + 1); + } + } + if (s->options & JBG_LRLTWO) { + /* two line template */ + do { + if (tx) { + if ((unsigned) tx > x) + a = 0; + else if (tx < 8) + a = ((line_h1 >> (tx - 5)) & 0x010); + else { + o = (x - tx) - (x & ~7L); + a = (hp[o >> 3] >> (7 - (o & 7))) & 1; + a <<= 4; + } + assert(tx > 31 || + a == ((line_h1 >> (tx - 5)) & 0x010)); + pix = arith_decode(se, (((line_h2 >> 9) & 0x3e0) | a | + (line_h1 & 0x00f))); + } else + pix = arith_decode(se, (((line_h2 >> 9) & 0x3f0) | + (line_h1 & 0x00f))); + if (pix < 0) + goto leave; + line_h1 = (line_h1 << 1) | pix; + line_h2 <<= 1; + } while ((++x & 7) && x < hx); + } else { + /* three line template */ + do { + if (tx) { + if ((unsigned) tx > x) + a = 0; + else if (tx < 8) + a = ((line_h1 >> (tx - 3)) & 0x004); + else { + o = (x - tx) - (x & ~7L); + a = (hp[o >> 3] >> (7 - (o & 7))) & 1; + a <<= 2; + } + assert(tx > 31 || + a == ((line_h1 >> (tx - 3)) & 0x004)); + pix = arith_decode(se, (((line_h3 >> 7) & 0x380) | + ((line_h2 >> 11) & 0x078) | a | + (line_h1 & 0x003))); + } else + pix = arith_decode(se, (((line_h3 >> 7) & 0x380) | + ((line_h2 >> 11) & 0x07c) | + (line_h1 & 0x003))); + if (pix < 0) + goto leave; + + line_h1 = (line_h1 << 1) | pix; + line_h2 <<= 1; + line_h3 <<= 1; + } while ((++x & 7) && x < hx); + } /* if (s->options & JBG_LRLTWO) */ + *hp++ = line_h1; + } /* while */ + *(hp - 1) <<= hbpl * 8 - hx; + x = 0; + s->pseudo = 1; + } /* for (i = ...) */ + + } else { + + /* + * Decode differential layer + */ + + for (; s->i < hl && y < hy; s->i++, y++) { + + /* adaptive template changes */ + if (x == 0) + for (n = 0; n < s->at_moves; n++) + if (s->at_line[n] == s->i) { + s->tx[plane][layer - s->dl] = s->at_tx[n]; + s->ty[plane][layer - s->dl] = s->at_ty[n]; +#ifdef DEBUG + fprintf(stderr, "ATMOVE: line=%lu, tx=%d, ty=%d.\n", s->i, + s->tx[plane][layer - s->dl], s->ty[plane][layer - s->dl]); +#endif + } + tx = s->tx[plane][layer - s->dl]; + + /* handle lower border of low-resolution image */ + if ((s->i >> 1) >= ll - 1 || (y >> 1) >= ly - 1) + lp1 = lp2; + + /* typical prediction */ + if ((s->options & JBG_TPDON) && s->pseudo) { + if ((s->lntp[plane][layer - s->dl] = arith_decode(se, TPDCX)) < 0) + goto leave; + } + s->pseudo = 0; + + /* + * Layout of the variables line_h1, line_h2, line_h3, which contain + * as bits the high resolution neighbour pixels of the currently + * decoded highres pixel X: + * + * 76543210 76543210 76543210 76543210 line_h3 + * 76543210 76543210 76543210 76543210 line_h2 + * 76543210 76543210 76543210 76543210 X line_h1 + * + * Layout of the variables line_l1, line_l2, line_l3, which contain + * the low resolution pixels near the currently decoded pixel as bits. + * The lowres pixel in which the currently coded highres pixel is + * located is marked as Y: + * + * 76543210 76543210 76543210 76543210 line_l3 + * 76543210 76543210 Y6543210 76543210 line_l2 + * 76543210 76543210 76543210 76543210 line_l1 + */ + + + if (x == 0) { + line_h1 = line_h2 = line_h3 = line_l1 = line_l2 = line_l3 = 0; + if (s->i > 0 || (y > 0 && !s->reset[plane][layer - s->dl])) { + line_h2 = (long)*(hp - hbpl) << 8; + if (s->i > 1 || (y > 1 && !s->reset[plane][layer - s->dl])) + line_h3 = (long)*(hp - hbpl - hbpl) << 8; + } + if (s->i > 1 || (y > 1 && !s->reset[plane][layer-s->dl])) + line_l3 = (long)*(lp2 - lbpl) << 8; + line_l2 = (long)*lp2 << 8; + line_l1 = (long)*lp1 << 8; + } + + /* decode line */ + while (x < hx) { + if ((x & 15) == 0) + if ((x >> 1) < lbpl * 8 - 8) { + line_l1 |= *(lp1 + 1); + line_l2 |= *(lp2 + 1); + if (s->i > 1 || + (y > 1 && !s->reset[plane][layer - s->dl])) + line_l3 |= *(lp2 - lbpl + 1); + } + do { + + assert(hp - (s->lhp[ layer &1][plane] + (stripe * hl + s->i) + * hbpl) == (ptrdiff_t) x >> 3); + assert(lp2 - (s->lhp[(layer-1) &1][plane] + (stripe * ll + (s->i>>1)) + * lbpl) == (ptrdiff_t) x >> 4); + + if ((x & 7) == 0) + if (x < hbpl * 8 - 8) { + if (s->i > 0 || (y > 0 && !s->reset[plane][layer - s->dl])) { + line_h2 |= *(hp + 1 - hbpl); + if (s->i > 1 || (y > 1 && !s->reset[plane][layer - s->dl])) + line_h3 |= *(hp + 1 - hbpl - hbpl); + } + } + do { + if (!s->lntp[plane][layer - s->dl]) + cx = (((line_l3 >> 14) & 0x007) | + ((line_l2 >> 11) & 0x038) | + ((line_l1 >> 8) & 0x1c0)); + if (!s->lntp[plane][layer - s->dl] && + (cx == 0x000 || cx == 0x1ff)) { + /* pixels are typical and have not to be decoded */ + do { + line_h1 = (line_h1 << 1) | (cx & 1); + } while ((++x & 1) && x < hx); + line_h2 <<= 2; line_h3 <<= 2; + } else + do { + + /* deterministic prediction */ + if (s->options & JBG_DPON) + if ((y & 1) == 0) + if ((x & 1) == 0) + /* phase 0 */ + pix = s->dppriv[((line_l3 >> 15) & 0x003) | + ((line_l2 >> 13) & 0x00c) | + ((line_h1 << 4) & 0x010) | + ((line_h2 >> 9) & 0x0e0)]; + else + /* phase 1 */ + pix = s->dppriv[(((line_l3 >> 15) & 0x003) | + ((line_l2 >> 13) & 0x00c) | + ((line_h1 << 4) & 0x030) | + ((line_h2 >> 9) & 0x1c0)) + 256]; + else + if ((x & 1) == 0) + /* phase 2 */ + pix = s->dppriv[(((line_l3 >> 15) & 0x003) | + ((line_l2 >> 13) & 0x00c) | + ((line_h1 << 4) & 0x010) | + ((line_h2 >> 9) & 0x0e0) | + ((line_h3 >> 6) & 0x700)) + 768]; + else + /* phase 3 */ + pix = s->dppriv[(((line_l3 >> 15) & 0x003) | + ((line_l2 >> 13) & 0x00c) | + ((line_h1 << 4) & 0x030) | + ((line_h2 >> 9) & 0x1c0) | + ((line_h3 >> 6) & 0xe00)) + 2816]; + else + pix = 2; + + if (pix & 2) { + if (tx) + cx = ((line_h1 & 0x003) | + (((line_h1 << 2) >> (tx - 3)) & 0x010) | + ((line_h2 >> 12) & 0x00c) | + ((line_h3 >> 10) & 0x020)); + else + cx = ((line_h1 & 0x003) | + ((line_h2 >> 12) & 0x01c) | + ((line_h3 >> 10) & 0x020)); + if (x & 1) + cx |= (((line_l2 >> 8) & 0x0c0) | + ((line_l1 >> 6) & 0x300)) | (1UL << 10); + else + cx |= (((line_l2 >> 9) & 0x0c0) | + ((line_l1 >> 7) & 0x300)); + cx |= (y & 1) << 11; + + pix = arith_decode(se, cx); + if (pix < 0) + goto leave; + } + + line_h1 = (line_h1 << 1) | pix; + line_h2 <<= 1; + line_h3 <<= 1; + + } while ((++x & 1) && x < hx); + line_l1 <<= 1; line_l2 <<= 1; line_l3 <<= 1; + } while ((x & 7) && x < hx); + *hp++ = line_h1; + } while ((x & 15) && x < hx); + ++lp1; + ++lp2; + } /* while */ + x = 0; + + *(hp - 1) <<= hbpl * 8 - hx; + if ((s->i & 1) == 0) { + /* low resolution pixels are used twice */ + lp1 -= lbpl; + lp2 -= lbpl; + } else + s->pseudo = 1; + + } /* for (i = ...) */ + + } + + leave: + + /* save a few local variables */ + s->line_h1 = line_h1; + s->line_h2 = line_h2; + s->line_h3 = line_h3; + s->line_l1 = line_l1; + s->line_l2 = line_l2; + s->line_l3 = line_l3; + s->x = x; + + return se->pscd_ptr - data; +} + + +/* + * Provide to the decoder a new BIE fragment of len bytes starting at data. + * + * Unless cnt is NULL, *cnt will contain the number of actually read bytes + * on return. + * + * Normal return values: + * + * JBG_EAGAIN All data bytes provided so far have been processed + * (*cnt == len) but the end of the data stream has + * not yet been recognized. Call the function again + * with additional BIE bytes. + * JBG_EOK The function has reached the end of a and + * a full image has been decoded. The function can + * be called again with data from the next BIE, if + * there exists one, in order to get to a higher + * resolution layer. The remaining len - *cnt bytes + * of the previous data block will then have to passed + * to this function again if len > *cnt. + * JBG_EOK_INTR Parsing the BIE has been interrupted as had been + * requested by a jbg_dec_maxsize() specification. + * This function can be called again with the + * rest of the BIE to continue the decoding process. + * The remaining len - *cnt bytes of the previous + * data block will then have to be passed to this + * function again if len > *cnt. + * + * Any other return value indicates that the decoding process was + * aborted by a serious problem and the only function you can then + * still call is jbg_dec_free() in order to remove the mess, and + * jbg85_strerror() to find out what to tell the user. (Looking at the + * least significant bits of the return value will provide additional + * information by identifying which test exactly has failed.) + */ +int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len, + size_t *cnt) +{ + int i, j, required_length; + unsigned long x, y; + unsigned long is[3], ie[3]; + size_t dummy_cnt; + unsigned char *dppriv; + + if (!cnt) cnt = &dummy_cnt; + *cnt = 0; + if (len < 1) return JBG_EAGAIN; + + /* read in 20-byte BIH */ + if (s->bie_len < 20) { + while (s->bie_len < 20 && *cnt < len) + s->buffer[s->bie_len++] = data[(*cnt)++]; + if (s->bie_len < 20) + return JBG_EAGAIN; + /* test whether this looks like a valid JBIG header at all */ + if (s->buffer[1] < s->buffer[0]) + return JBG_EINVAL | 1; + if (s->buffer[3] != 0) return JBG_EINVAL | 2; /* padding != 0 */ + if ((s->buffer[18] & 0xf0) != 0) return JBG_EINVAL | 3; /* padding != 0 */ + if ((s->buffer[19] & 0x80) != 0) return JBG_EINVAL | 4; /* padding != 0 */ + if (s->buffer[0] != s->d + 1) + return JBG_ENOCONT | 1; + s->dl = s->buffer[0]; + s->d = s->buffer[1]; + if (s->dl == 0) + s->planes = s->buffer[2]; + else + if (s->planes != s->buffer[2]) + return JBG_ENOCONT | 2; + x = (((long) s->buffer[ 4] << 24) | ((long) s->buffer[ 5] << 16) | + ((long) s->buffer[ 6] << 8) | (long) s->buffer[ 7]); + y = (((long) s->buffer[ 8] << 24) | ((long) s->buffer[ 9] << 16) | + ((long) s->buffer[10] << 8) | (long) s->buffer[11]); + if (s->dl != 0 && ((s->xd << (s->d - s->dl + 1)) != x && + (s->yd << (s->d - s->dl + 1)) != y)) + return JBG_ENOCONT | 3; + s->xd = x; + s->yd = y; + s->l0 = (((long) s->buffer[12] << 24) | ((long) s->buffer[13] << 16) | + ((long) s->buffer[14] << 8) | (long) s->buffer[15]); + /* ITU-T T.85 trick not directly supported by decoder; for full + * T.85 compatibility with respect to all NEWLEN marker scenarios, + * preprocess BIE with jbg_newlen() before passing it to the decoder, + * or consider using the decoder found in jbig85.c instead. */ + if (s->yd == 0xffffffff) + return JBG_EIMPL | 1; + if (!s->planes) return JBG_EINVAL | 5; + if (!s->xd) return JBG_EINVAL | 6; + if (!s->yd) return JBG_EINVAL | 7; + if (!s->l0) return JBG_EINVAL | 8; + /* prevent uint32 overflow: s->l0 * 2 ^ s->d < 2 ^ 32 */ + if (s->d > 31) + return JBG_EIMPL | 2; + if ((s->d != 0 && s->l0 >= (1UL << (32 - s->d)))) + return JBG_EIMPL | 3; + s->mx = s->buffer[16]; + if (s->mx > 127) + return JBG_EINVAL | 9; + s->my = s->buffer[17]; +#if 0 + if (s->my > 0) + return JBG_EIMPL | 4; +#endif + s->order = s->buffer[18]; + if (iindex[s->order & 7][0] < 0) + return JBG_EINVAL | 10; + /* HITOLO and SEQ currently not yet implemented */ + if (s->dl != s->d && (s->order & JBG_HITOLO || s->order & JBG_SEQ)) + return JBG_EIMPL | 5; + s->options = s->buffer[19]; + + /* calculate number of stripes that will be required */ + s->stripes = jbg_stripes(s->l0, s->yd, s->d); + + /* some initialization */ + s->ii[iindex[s->order & 7][STRIPE]] = 0; + s->ii[iindex[s->order & 7][LAYER]] = s->dl; + s->ii[iindex[s->order & 7][PLANE]] = 0; + if (s->dl == 0) { + s->s = (struct jbg_ardec_state **) + checked_malloc(s->planes, sizeof(struct jbg_ardec_state *)); + s->tx = (int **) checked_malloc(s->planes, sizeof(int *)); + s->ty = (int **) checked_malloc(s->planes, sizeof(int *)); + s->reset = (int **) checked_malloc(s->planes, sizeof(int *)); + s->lntp = (int **) checked_malloc(s->planes, sizeof(int *)); + s->lhp[0] = (unsigned char **) + checked_malloc(s->planes, sizeof(unsigned char *)); + s->lhp[1] = (unsigned char **) + checked_malloc(s->planes, sizeof(unsigned char *)); + for (i = 0; i < s->planes; i++) { + s->s[i] = (struct jbg_ardec_state *) + checked_malloc(s->d - s->dl + 1, sizeof(struct jbg_ardec_state)); + s->tx[i] = (int *) checked_malloc(s->d - s->dl + 1, sizeof(int)); + s->ty[i] = (int *) checked_malloc(s->d - s->dl + 1, sizeof(int)); + s->reset[i] = (int *) checked_malloc(s->d - s->dl + 1, sizeof(int)); + s->lntp[i] = (int *) checked_malloc(s->d - s->dl + 1, sizeof(int)); + s->lhp[ s->d & 1][i] = (unsigned char *) + checked_malloc(s->yd, jbg_ceil_half(s->xd, 3)); + s->lhp[(s->d-1) & 1][i] = (unsigned char *) + checked_malloc(jbg_ceil_half(s->yd, 1), jbg_ceil_half(s->xd, 1+3)); + } + } else { + for (i = 0; i < s->planes; i++) { + s->s[i] = (struct jbg_ardec_state *) + checked_realloc(s->s[i], s->d - s->dl + 1, + sizeof(struct jbg_ardec_state)); + s->tx[i] = (int *) checked_realloc(s->tx[i], + s->d - s->dl + 1, sizeof(int)); + s->ty[i] = (int *) checked_realloc(s->ty[i], + s->d - s->dl + 1, sizeof(int)); + s->reset[i] = (int *) checked_realloc(s->reset[i], + s->d - s->dl + 1, sizeof(int)); + s->lntp[i] = (int *) checked_realloc(s->lntp[i], + s->d - s->dl + 1, sizeof(int)); + s->lhp[ s->d & 1][i] = (unsigned char *) + checked_realloc(s->lhp[ s->d & 1][i], + s->yd, jbg_ceil_half(s->xd, 3)); + s->lhp[(s->d-1) & 1][i] = (unsigned char *) + checked_realloc(s->lhp[(s->d-1) & 1][i], + jbg_ceil_half(s->yd, 1), jbg_ceil_half(s->xd, 1+3)); + } + } + for (i = 0; i < s->planes; i++) + for (j = 0; j <= s->d - s->dl; j++) + arith_decode_init(s->s[i] + j, 0); + if (s->dl == 0 || (s->options & JBG_DPON && !(s->options & JBG_DPPRIV))) + s->dppriv = jbg_dptable; + s->comment_skip = 0; + s->buf_len = 0; + s->x = 0; + s->i = 0; + s->pseudo = 1; + s->at_moves = 0; + } + + /* read in DPTABLE */ + if (s->bie_len < 20 + 1728 && + (s->options & (JBG_DPON | JBG_DPPRIV | JBG_DPLAST)) == + (JBG_DPON | JBG_DPPRIV)) { + assert(s->bie_len >= 20); + if (!s->dppriv || s->dppriv == jbg_dptable) + s->dppriv = (char *) checked_malloc(1728, sizeof(char)); + while (s->bie_len < 20 + 1728 && *cnt < len) + s->dppriv[s->bie_len++ - 20] = data[(*cnt)++]; + if (s->bie_len < 20 + 1728) + return JBG_EAGAIN; + dppriv = (unsigned char *) s->dppriv; + s->dppriv = (char *) checked_malloc(6912, sizeof(char)); + jbg_dppriv2int(s->dppriv, dppriv); + checked_free(dppriv); + } + + /* + * BID processing loop + */ + + while (*cnt < len) { + + /* process floating marker segments */ + + /* skip COMMENT contents */ + if (s->comment_skip) { + if (s->comment_skip <= len - *cnt) { + *cnt += s->comment_skip; + s->comment_skip = 0; + } else { + s->comment_skip -= len - *cnt; + *cnt = len; + } + continue; + } + + /* load complete marker segments into s->buffer for processing */ + if (s->buf_len > 0) { + assert(s->buffer[0] == MARKER_ESC); + while (s->buf_len < 2 && *cnt < len) + s->buffer[s->buf_len++] = data[(*cnt)++]; + if (s->buf_len < 2) continue; + switch (s->buffer[1]) { + case MARKER_COMMENT: required_length = 6; break; + case MARKER_ATMOVE: required_length = 8; break; + case MARKER_NEWLEN: required_length = 6; break; + case MARKER_ABORT: + case MARKER_SDNORM: + case MARKER_SDRST: required_length = 2; break; + case MARKER_STUFF: + /* forward stuffed 0xff to arithmetic decoder */ + s->buf_len = 0; + decode_pscd(s, s->buffer, 2); + continue; + default: + return JBG_EMARKER; + } + while (s->buf_len < required_length && *cnt < len) + s->buffer[s->buf_len++] = data[(*cnt)++]; + if (s->buf_len < required_length) continue; + /* now the buffer is filled with exactly one marker segment */ + switch (s->buffer[1]) { + case MARKER_COMMENT: + s->comment_skip = + (((long) s->buffer[2] << 24) | ((long) s->buffer[3] << 16) | + ((long) s->buffer[4] << 8) | (long) s->buffer[5]); + break; + case MARKER_ATMOVE: + if (s->at_moves < JBG_ATMOVES_MAX) { + s->at_line[s->at_moves] = + (((long) s->buffer[2] << 24) | ((long) s->buffer[3] << 16) | + ((long) s->buffer[4] << 8) | (long) s->buffer[5]); + s->at_tx[s->at_moves] = (signed char) s->buffer[6]; + s->at_ty[s->at_moves] = s->buffer[7]; + if (s->at_tx[s->at_moves] < - (int) s->mx || + s->at_tx[s->at_moves] > (int) s->mx || + s->at_ty[s->at_moves] > (int) s->my || + (s->at_ty[s->at_moves] == 0 && s->at_tx[s->at_moves] < 0)) + return JBG_EINVAL | 11; + if (s->at_ty[s->at_moves] != 0) + return JBG_EIMPL | 6; + s->at_moves++; + } else + return JBG_EIMPL | 7; /* more than JBG_ATMOVES_MAX ATMOVES */ + break; + case MARKER_NEWLEN: + y = (((long) s->buffer[2] << 24) | ((long) s->buffer[3] << 16) | + ((long) s->buffer[4] << 8) | (long) s->buffer[5]); + if (y > s->yd) return JBG_EINVAL | 12; + if (!(s->options & JBG_VLENGTH)) return JBG_EINVAL | 13; + s->yd = y; + /* calculate again number of stripes that will be required */ + s->stripes = jbg_stripes(s->l0, s->yd, s->d); + break; + case MARKER_ABORT: + return JBG_EABORT; + + case MARKER_SDNORM: + case MARKER_SDRST: + /* decode final pixels based on trailing zero bytes */ + decode_pscd(s, s->buffer, 2); + + arith_decode_init(s->s[s->ii[iindex[s->order & 7][PLANE]]] + + s->ii[iindex[s->order & 7][LAYER]] - s->dl, + s->ii[iindex[s->order & 7][STRIPE]] != s->stripes - 1 + && s->buffer[1] != MARKER_SDRST); + + s->reset[s->ii[iindex[s->order & 7][PLANE]]] + [s->ii[iindex[s->order & 7][LAYER]] - s->dl] = + (s->buffer[1] == MARKER_SDRST); + + /* prepare for next SDE */ + s->x = 0; + s->i = 0; + s->pseudo = 1; + s->at_moves = 0; + + /* increment layer/stripe/plane loop variables */ + /* start and end value for each loop: */ + is[iindex[s->order & 7][STRIPE]] = 0; + ie[iindex[s->order & 7][STRIPE]] = s->stripes - 1; + is[iindex[s->order & 7][LAYER]] = s->dl; + ie[iindex[s->order & 7][LAYER]] = s->d; + is[iindex[s->order & 7][PLANE]] = 0; + ie[iindex[s->order & 7][PLANE]] = s->planes - 1; + i = 2; /* index to innermost loop */ + do { + j = 0; /* carry flag */ + if (++s->ii[i] > ie[i]) { + /* handling overflow of loop variable */ + j = 1; + if (i > 0) + s->ii[i] = is[i]; + } + } while (--i >= 0 && j); + + s->buf_len = 0; + + /* check whether this have been all SDEs */ + if (j) { +#ifdef DEBUG + fprintf(stderr, "This was the final SDE in this BIE, " + "%ld bytes left.\n", (long) (len - *cnt)); +#endif + s->bie_len = 0; + return JBG_EOK; + } + + /* check whether we have to abort because of xmax/ymax */ + if (iindex[s->order & 7][LAYER] == 0 && i < 0) { + /* LAYER is the outermost loop and we have just gone to next layer */ + if (jbg_ceil_half(s->xd, s->d - s->ii[0]) > s->xmax || + jbg_ceil_half(s->yd, s->d - s->ii[0]) > s->ymax) { + s->xmax = 4294967295UL; + s->ymax = 4294967295UL; + return JBG_EOK_INTR; + } + if (s->ii[0] > (unsigned long) s->dmax) { + s->dmax = 256; + return JBG_EOK_INTR; + } + } + + break; + } + s->buf_len = 0; + + } else if (data[*cnt] == MARKER_ESC) + s->buffer[s->buf_len++] = data[(*cnt)++]; + + else { + + /* we have found PSCD bytes */ + *cnt += decode_pscd(s, data + *cnt, len - *cnt); + if (*cnt < len && data[*cnt] != 0xff) { +#ifdef DEBUG + fprintf(stderr, "PSCD was longer than expected, unread bytes " + "%02x %02x %02x %02x ...\n", data[*cnt], data[*cnt+1], + data[*cnt+2], data[*cnt+3]); +#endif + return JBG_EINVAL | 14; + } + + } + } /* of BID processing loop 'while (*cnt < len) ...' */ + + return JBG_EAGAIN; +} + + +/* + * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call this + * function in order to find out the width of the image. Returns 0 if + * there is no image available yet. + */ +unsigned long jbg_dec_getwidth(const struct jbg_dec_state *s) +{ + if (s->d < 0) + return 0; + if (iindex[s->order & 7][LAYER] == 0) { + if (s->ii[0] < 1) + return 0; + else + return jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1)); + } + + return s->xd; +} + + +/* + * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call this + * function in order to find out the height of the image. Returns 0 if + * there is no image available yet. + */ +unsigned long jbg_dec_getheight(const struct jbg_dec_state *s) +{ + if (s->d < 0) + return 0; + if (iindex[s->order & 7][LAYER] == 0) { + if (s->ii[0] < 1) + return 0; + else + return jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1)); + } + + return s->yd; +} + + +/* + * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call this + * function in order to get a pointer to the image. Returns NULL if + * there is no image available yet. + */ +unsigned char *jbg_dec_getimage(const struct jbg_dec_state *s, int plane) +{ + if (s->d < 0) + return NULL; + if (iindex[s->order & 7][LAYER] == 0) { + if (s->ii[0] < 1) + return NULL; + else + return s->lhp[(s->ii[0] - 1) & 1][plane]; + } + + return s->lhp[s->d & 1][plane]; +} + + +/* + * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call + * this function in order to find out the size in bytes of one + * bitplane of the image. + */ +unsigned long jbg_dec_getsize(const struct jbg_dec_state *s) +{ + if (s->d < 0) + return 0; + if (iindex[s->order & 7][LAYER] == 0) { + if (s->ii[0] < 1) + return 0; + else + return + jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1) + 3) * /* overflow risk? */ + jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1)); + } + + return jbg_ceil_half(s->xd, 3) * s->yd; +} + + +/* + * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call + * this function in order to find out the size of the image that you + * can retrieve with jbg_merge_planes(). + */ +unsigned long jbg_dec_getsize_merged(const struct jbg_dec_state *s) +{ + if (s->d < 0) + return 0; + if (iindex[s->order & 7][LAYER] == 0) { + if (s->ii[0] < 1) + return 0; + else + return + jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1)) * /* overflow risk? */ + jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1)) * + ((s->planes + 7) / 8); + } + + return s->xd * s->yd * ((s->planes + 7) / 8); +} + + +/* + * The destructor function which releases any resources obtained by the + * other decoder functions. + */ +void jbg_dec_free(struct jbg_dec_state *s) +{ + int i; + + if (s->d < 0 || s->s == NULL) + return; + s->d = -2; + + for (i = 0; i < s->planes; i++) { + checked_free(s->s[i]); + checked_free(s->tx[i]); + checked_free(s->ty[i]); + checked_free(s->reset[i]); + checked_free(s->lntp[i]); + checked_free(s->lhp[0][i]); + checked_free(s->lhp[1][i]); + } + + checked_free(s->s); + checked_free(s->tx); + checked_free(s->ty); + checked_free(s->reset); + checked_free(s->lntp); + checked_free(s->lhp[0]); + checked_free(s->lhp[1]); + if (s->dppriv && s->dppriv != jbg_dptable) + checked_free(s->dppriv); + + s->s = NULL; + + return; +} + + +/* + * Split bigendian integer pixel field into separate bit planes. In the + * src array, every pixel is represented by a ((has_planes + 7) / 8) byte + * long word, most significant byte first. While has_planes describes + * the number of used bits per pixel in the source image, encode_plane + * is the number of most significant bits among those that we + * actually transfer to dest. + */ +void jbg_split_planes(unsigned long x, unsigned long y, int has_planes, + int encode_planes, + const unsigned char *src, unsigned char **dest, + int use_graycode) +{ + unsigned long bpl = jbg_ceil_half(x, 3); /* bytes per line in dest plane */ + unsigned long line, i; + unsigned k = 8; + int p; + unsigned prev; /* previous *src byte shifted by 8 bit to the left */ + register int bits, msb = has_planes - 1; + int bitno; + + /* sanity checks */ + if (encode_planes > has_planes) + encode_planes = has_planes; + use_graycode = use_graycode != 0 && encode_planes > 1; + + for (p = 0; p < encode_planes; p++) + memset(dest[p], 0, bpl * y); + + for (line = 0; line < y; line++) { /* lines loop */ + for (i = 0; i * 8 < x; i++) { /* dest bytes loop */ + for (k = 0; k < 8 && i * 8 + k < x; k++) { /* pixel loop */ + prev = 0; + for (p = 0; p < encode_planes; p++) { /* bit planes loop */ + /* calculate which bit in *src do we want */ + bitno = (msb - p) & 7; + /* put this bit with its left neighbor right adjusted into bits */ + bits = (prev | *src) >> bitno; + /* go to next *src byte, but keep old */ + if (bitno == 0) + prev = *src++ << 8; + /* make space for inserting new bit */ + dest[p][bpl * line + i] <<= 1; + /* insert bit, if requested apply Gray encoding */ + dest[p][bpl * line + i] |= (bits ^ (use_graycode & (bits>>1))) & 1; + /* + * Theorem: Let b(n),...,b(1),b(0) be the digits of a + * binary word and let g(n),...,g(1),g(0) be the digits of the + * corresponding Gray code word, then g(i) = b(i) xor b(i+1). + */ + } + /* skip unused *src bytes */ + for (;p < has_planes; p++) + if (((msb - p) & 7) == 0) + src++; + } + } + for (p = 0; p < encode_planes; p++) /* right padding loop */ + dest[p][bpl * (line + 1) - 1] <<= 8 - k; + } + + return; +} + +/* + * Merge the separate bit planes decoded by the JBIG decoder into an + * integer pixel field. This is essentially the counterpart to + * jbg_split_planes(). + */ +void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode, + void (*data_out)(unsigned char *start, size_t len, + void *file), void *file) +{ +#define BUFLEN 4096 + unsigned long bpl, line, i; + unsigned k = 8; + int p; + unsigned char buf[BUFLEN]; + unsigned char *bp = buf; + unsigned char **src; + unsigned long x, y; + unsigned v; + + /* sanity check */ + use_graycode = use_graycode != 0; + + x = jbg_dec_getwidth(s); + y = jbg_dec_getheight(s); + if (x == 0 || y == 0) + return; + bpl = jbg_ceil_half(x, 3); /* bytes per line in src plane */ + + if (iindex[s->order & 7][LAYER] == 0) + if (s->ii[0] < 1) + return; + else + src = s->lhp[(s->ii[0] - 1) & 1]; + else + src = s->lhp[s->d & 1]; + + for (line = 0; line < y; line++) { /* lines loop */ + for (i = 0; i * 8 < x; i++) { /* src bytes loop */ + for (k = 0; k < 8 && i * 8 + k < x; k++) { /* pixel loop */ + v = 0; + for (p = 0; p < s->planes;) { /* dest bytes loop */ + do { + v = (v << 1) | + (((src[p][bpl * line + i] >> (7 - k)) & 1) ^ + (use_graycode & v)); + } while ((s->planes - ++p) & 7); + *bp++ = v; + if (bp - buf == BUFLEN) { + data_out(buf, BUFLEN, file); + bp = buf; + } + } + } + } + } + + if (bp - buf > 0) + data_out(buf, bp - buf, file); + + return; +} + + +/* + * Given a pointer p to the first byte of either a marker segment or a + * PSCD, as well as the length len of the remaining data, return + * either the pointer to the first byte of the next marker segment or + * PSCD, or p+len if this was the last one, or NULL if some error was + * encountered. Possible errors are: + * + * - not enough bytes left for complete marker segment + * - no marker segment terminates the PSCD + * - unknown marker code encountered + * + */ +unsigned char *jbg_next_pscdms(unsigned char *p, size_t len) +{ + unsigned char *pp; + unsigned long l; + + if (len < 2) + return NULL; /* not enough bytes left for complete marker segment */ + + if (p[0] != MARKER_ESC || p[1] == MARKER_STUFF) { + do { + while (p[0] == MARKER_ESC && p[1] == MARKER_STUFF) { + p += 2; + len -= 2; + if (len < 2) + return NULL; /* not enough bytes left for complete marker segment */ + } + assert(len >= 2); + pp = (unsigned char *) memchr(p, MARKER_ESC, len - 1); + if (!pp) + return NULL; /* no marker segment terminates the PSCD */ + l = pp - p; + assert(l < len); + p += l; + len -= l; + } while (p[1] == MARKER_STUFF); + } else { + switch (p[1]) { + case MARKER_SDNORM: + case MARKER_SDRST: + case MARKER_ABORT: + return p + 2; + case MARKER_NEWLEN: + if (len < 6) + return NULL; /* not enough bytes left for complete marker segment */ + return p + 6; + case MARKER_ATMOVE: + if (len < 8) + return NULL; /* not enough bytes left for complete marker segment */ + return p + 8; + case MARKER_COMMENT: + if (len < 6) + return NULL; /* not enough bytes left for complete marker segment */ + l = (((long) p[2] << 24) | ((long) p[3] << 16) | + ((long) p[4] << 8) | (long) p[5]); + if (len - 6 < l) + return NULL; /* not enough bytes left for complete marker segment */ + return p + 6 + l; + default: + /* unknown marker sequence encountered */ + return NULL; + } + } + + return p; +} + + +/* + * Scan a complete BIE for a NEWLEN marker segment, then read the new + * YD value found in it and use it to overwrite the one in the BIE + * header. Use this procedure if a BIE initially declares an + * unreasonably high provisional YD value (e.g., 0xffffffff) or + * depends on the fact that section 6.2.6.2 of ITU-T T.82 says that a + * NEWLEN marker segment "could refer to a line in the immediately + * preceding stripe due to an unexpected termination of the image or + * the use of only such stripe". ITU-T.85 explicitely suggests the + * use of this for fax machines that start transmission before having + * encountered the end of the page. None of this is necessary for + * BIEs produced by JBIG-KIT, which normally does not use NEWLEN. + */ +int jbg_newlen(unsigned char *bie, size_t len) +{ + unsigned char *p = bie + 20; + int i; + unsigned long y, yn; + + if (len < 20) + return JBG_EAGAIN; + if ((bie[19] & (JBG_DPON | JBG_DPPRIV | JBG_DPLAST)) + == (JBG_DPON | JBG_DPPRIV)) + p += 1728; /* skip DPTABLE */ + if (p >= bie + len) + return JBG_EAGAIN; + + while ((p = jbg_next_pscdms(p, len - (p - bie)))) { + if (p == bie + len) + return JBG_EOK; + else if (p[0] == MARKER_ESC) + switch (p[1]) { + case MARKER_NEWLEN: + y = (((long) bie[ 8] << 24) | ((long) bie[ 9] << 16) | + ((long) bie[10] << 8) | (long) bie[11]); + yn = (((long) p[2] << 24) | ((long) p[3] << 16) | + ((long) p[4] << 8) | (long) p[5]); + if (yn > y) return JBG_EINVAL | 12; + /* overwrite YD in BIH with YD from NEWLEN */ + for (i = 0; i < 4; i++) { + bie[8+i] = p[2+i]; + } + return JBG_EOK; + case MARKER_ABORT: + return JBG_EABORT; + } + } + return JBG_EINVAL | 0; +} diff --git a/libjbig/jbig.h b/libjbig/jbig.h new file mode 100644 index 0000000..6799410 --- /dev/null +++ b/libjbig/jbig.h @@ -0,0 +1,233 @@ +/* + * Header file for the portable JBIG compression library + * + * Copyright 1995-2014 -- Markus Kuhn -- http://www.cl.cam.ac.uk/~mgk25/ + */ + +#ifndef JBG_H +#define JBG_H + +#include +#include "jbig_ar.h" + +/* + * JBIG-KIT version number + */ + +#define JBG_VERSION "2.1" +#define JBG_VERSION_MAJOR 2 +#define JBG_VERSION_MINOR 1 + +/* + * JBIG-KIT licence agreement reference code: + * If you use JBIG-KIT under a commercial licence, please replace + * below the letters GPL with the reference code that you received + * with your licence agreement. (This code is typically a letter "A" + * followed by four decimal digits, e.g. "A1234".) + */ + +#define JBG_LICENCE "GPL" + +/* + * Buffer block for SDEs which are temporarily stored by encoder + */ + +#define JBG_BUFSIZE 4000 + +struct jbg_buf { + unsigned char d[JBG_BUFSIZE]; /* one block of a buffer list */ + int len; /* length of the data in this block */ + struct jbg_buf *next; /* pointer to next block */ + struct jbg_buf *previous; /* pointer to previous block * + * (unused in freelist) */ + struct jbg_buf *last; /* only used in list head: final block of list */ + struct jbg_buf **free_list; /* pointer to pointer to head of free list */ +}; + +/* + * Maximum number of ATMOVEs per stripe that decoder can handle + */ + +#define JBG_ATMOVES_MAX 64 + +/* + * Option and order flags + */ + +#define JBG_HITOLO 0x08 +#define JBG_SEQ 0x04 +#define JBG_ILEAVE 0x02 +#define JBG_SMID 0x01 + +#define JBG_LRLTWO 0x40 +#define JBG_VLENGTH 0x20 +#define JBG_TPDON 0x10 +#define JBG_TPBON 0x08 +#define JBG_DPON 0x04 +#define JBG_DPPRIV 0x02 +#define JBG_DPLAST 0x01 + +/* encoding options that will not be indicated in the header */ + +#define JBG_DELAY_AT 0x100 /* Delay ATMOVE until the first line of the next + * stripe. Option available for compatibility + * with conformance test example in clause 7.2. */ + +#define JBG_SDRST 0x200 /* Use SDRST instead of SDNORM. This option is + * there for anyone who needs to generate + * test data that covers the SDRST cases. */ + +/* + * Possible error code return values + */ + +#define JBG_EOK (0 << 4) +#define JBG_EOK_INTR (1 << 4) +#define JBG_EAGAIN (2 << 4) +#define JBG_ENOMEM (3 << 4) +#define JBG_EABORT (4 << 4) +#define JBG_EMARKER (5 << 4) +#define JBG_EINVAL (6 << 4) +#define JBG_EIMPL (7 << 4) +#define JBG_ENOCONT (8 << 4) + +/* + * Status of a JBIG encoder + */ + +struct jbg_enc_state { + int d; /* resolution layer of the input image */ + unsigned long xd, yd; /* size of the input image (resolution layer d) */ + unsigned long yd1; /* BIH announced height of image, use yd1 != yd to + emulate T.85-style NEWLEN height updates for tests */ + int planes; /* number of different bitmap planes */ + int dl; /* lowest resolution layer in the next BIE */ + int dh; /* highest resolution layer in the next BIE */ + unsigned long l0; /* number of lines per stripe at lowest * + * resolution layer 0 */ + unsigned long stripes; /* number of stripes required (determ. by l0) */ + unsigned char **lhp[2]; /* pointers to lower/higher resolution images */ + int *highres; /* index [plane] of highres image in lhp[] */ + int order; /* SDE ordering parameters */ + int options; /* encoding parameters */ + unsigned mx, my; /* maximum ATMOVE window size */ + int *tx; /* array [plane] with x-offset of adaptive template pixel */ + char *dppriv; /* optional private deterministic prediction table */ + char *res_tab; /* table for the resolution reduction algorithm */ + struct jbg_buf ****sde; /* array [stripe][layer][plane] pointers to * + * buffers for stored SDEs */ + struct jbg_arenc_state *s; /* array [planes] for arithm. encoder status */ + struct jbg_buf *free_list; /* list of currently unused SDE block buffers */ + void (*data_out)(unsigned char *start, size_t len, void *file); + /* data write callback */ + void *file; /* parameter passed to data_out() */ + char *tp; /* buffer for temp. values used by diff. typical prediction */ + unsigned char *comment; /* content of comment marker segment to be added + at next opportunity (will be reset to NULL + as soon as comment has been written) */ + unsigned long comment_len; /* length of data pointed to by comment */ +}; + + +/* + * Status of a JBIG decoder + */ + +struct jbg_dec_state { + /* data from BIH */ + int d; /* resolution layer of the full image */ + int dl; /* first resolution layer in this BIE */ + unsigned long xd, yd; /* size of the full image (resolution layer d) */ + int planes; /* number of different bitmap planes */ + unsigned long l0; /* number of lines per stripe at lowest * + * resolution layer 0 */ + unsigned long stripes; /* number of stripes required (determ. by l0) */ + int order; /* SDE ordering parameters */ + int options; /* encoding parameters */ + int mx, my; /* maximum ATMOVE window size */ + char *dppriv; /* optional private deterministic prediction table */ + + /* loop variables */ + unsigned long ii[3]; /* current stripe, layer, plane (outer loop first) */ + + /* + * Pointers to array [planes] of lower/higher resolution images. + * lhp[d & 1] contains image of layer d. + */ + unsigned char **lhp[2]; + + /* status information */ + int **tx, **ty; /* array [plane][layer-dl] with x,y-offset of AT pixel */ + struct jbg_ardec_state **s; /* array [plane][layer-dl] for arithmetic * + * decoder status */ + int **reset; /* array [plane][layer-dl] remembers if previous stripe * + * in that plane/resolution ended with SDRST. */ + unsigned long bie_len; /* number of bytes read so far */ + unsigned char buffer[20]; /* used to store BIH or marker segments fragm. */ + int buf_len; /* number of bytes in buffer */ + unsigned long comment_skip; /* remaining bytes of a COMMENT segment */ + unsigned long x; /* x position of next pixel in current SDE */ + unsigned long i; /* line in current SDE (first line of each stripe is 0) */ + int at_moves; /* number of AT moves in the current stripe */ + unsigned long at_line[JBG_ATMOVES_MAX]; /* lines at which an * + * AT move will happen */ + int at_tx[JBG_ATMOVES_MAX], at_ty[JBG_ATMOVES_MAX]; /* ATMOVE offsets in * + * current stripe */ + unsigned long line_h1, line_h2, line_h3; /* variables of decode_pscd */ + unsigned long line_l1, line_l2, line_l3; + int pseudo; /* flag for TPBON/TPDON: next pixel is pseudo pixel */ + int **lntp; /* flag [plane][layer-dl] for TP: line is not typical */ + + unsigned long xmax, ymax; /* if possible abort before image gets * + * larger than this size */ + int dmax; /* abort after this layer */ +}; + + +/* some macros (too trivial for a function) */ + +#define jbg_dec_getplanes(s) ((s)->planes) + + +/* function prototypes */ + +void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y, + int planes, unsigned char **p, + void (*data_out)(unsigned char *start, size_t len, + void *file), + void *file); +int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long mwidth, + unsigned long mheight); +void jbg_enc_layers(struct jbg_enc_state *s, int d); +int jbg_enc_lrange(struct jbg_enc_state *s, int dl, int dh); +void jbg_enc_options(struct jbg_enc_state *s, int order, int options, + unsigned long l0, int mx, int my); +void jbg_enc_out(struct jbg_enc_state *s); +void jbg_enc_free(struct jbg_enc_state *s); + +void jbg_dec_init(struct jbg_dec_state *s); +void jbg_dec_maxsize(struct jbg_dec_state *s, unsigned long xmax, + unsigned long ymax); +int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len, + size_t *cnt); +unsigned long jbg_dec_getwidth(const struct jbg_dec_state *s); +unsigned long jbg_dec_getheight(const struct jbg_dec_state *s); +unsigned char *jbg_dec_getimage(const struct jbg_dec_state *s, int plane); +unsigned long jbg_dec_getsize(const struct jbg_dec_state *s); +void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode, + void (*data_out)(unsigned char *start, size_t len, + void *file), void *file); +unsigned long jbg_dec_getsize_merged(const struct jbg_dec_state *s); +void jbg_dec_free(struct jbg_dec_state *s); + +const char *jbg_strerror(int errnum); +void jbg_int2dppriv(unsigned char *dptable, const char *internal); +void jbg_dppriv2int(char *internal, const unsigned char *dptable); +unsigned long jbg_ceil_half(unsigned long x, int n); +void jbg_split_planes(unsigned long x, unsigned long y, int has_planes, + int encode_planes, + const unsigned char *src, unsigned char **dest, + int use_graycode); +int jbg_newlen(unsigned char *bie, size_t len); + +#endif /* JBG_H */ diff --git a/libjbig/jbig.txt b/libjbig/jbig.txt new file mode 100644 index 0000000..bdc14b1 --- /dev/null +++ b/libjbig/jbig.txt @@ -0,0 +1,810 @@ + +Using the JBIG-KIT library +-------------------------- + +Markus Kuhn -- 2013-09-10 + + +This text explains how to use the functions provided by the JBIG-KIT +portable image compression library jbig.c in your application +software. The jbig.c library is a full-featured implementation of the +JBIG1 standard aimed at applications that can hold the entire +uncompressed and compressed image in RAM. + +[For applications that require only the single-bit-per-pixel "fax +subset" of the JBIG1 standard defined in ITU-T Recommendation T.85 +, the alternative implementation +found in jbig85.c may be preferable. It keeps not more than three +lines of the uncompressed image in RAM, which makes it particularly +suitable for embedded applications. For information on how to use +jbig85.c, please refer to the separate documentation file jbig85.txt.] + + +1 Introduction to JBIG + +We start with a short introduction to JBIG1. More detailed information +is provided in the "Introduction and overview" section of the JBIG1 +standard. Information on how to obtain a copy of the standard is +available from or +. + +Image data encoded with the JBIG algorithm is separated into planes, +layers, and stripes. Each plane contains one bit per pixel. The number +of planes stored in a JBIG data stream is the number of bits per +pixel. Resolution layers are numbered from 0 to D with 0 being the +layer with the lowest resolution and D the one with the highest. Each +next higher resolution layer has twice the number of rows and columns. +Layer 0 is encoded independently of any other data, all other +resolution layers are encoded as only the difference between the next +lower and the current layer. For applications that require very quick +access to parts of an image, it is possible to divide an image into +several horizontal stripes. All stripes of one resolution layer have +equal size, except perhaps the final one. The number of stripes of an +image is equal in all resolution layers and in all bit planes. + +The compressed data stream specified by the JBIG standard is called a +bi-level image entity (BIE). A BIE consists of a 20-byte header, +followed by an optional 1728-byte table (usually not present, except +in special applications) followed by a sequence of stripe data +entities (SDE). Each SDE encodes the content of one single stripe in +one plane of one resolution layer. Between the SDEs, other information +blocks (called floating marker segments) can also be present. They are +used to change certain parameters of the algorithm in the middle of an +image or contain additional application specific information. A BIE +looks like this: + + + +------------------------------------------------+ + | | + | 20-byte header (with image size, #planes, | + | #layers, stripe size, first layer, options, | + | SDE ordering, ...) | + | | + +------------------------------------------------+ + | | + | optional 1728-byte table | + | | + +------------------------------------------------+ + | | + | optional floating marker segments | + | | + +------------------------------------------------+ + | | + | stripe data entity | + | | + +------------------------------------------------+ + | | + | optional floating marker segments | + | | + +------------------------------------------------+ + | | + | stripe data entity | + | | + +------------------------------------------------+ + ... + +------------------------------------------------+ + | | + | stripe data entity | + | | + +------------------------------------------------+ + + +One BIE can contain all resolution layers of an image, but it is also +possible to store various resolution layers in several BIEs. The BIE +header contains the number of the first and the last resolution layer +stored in this BIE, as well as the size of the highest resolution +layer stored in this BIE. Progressive coding is deactivated by simply +storing the image in one single resolution layer. + +Different applications might have different requirements for the order +in which the SDEs for stripes of various planes and layers are stored +in the BIE, so all possible sensible orderings are allowed by the +standard and indicated by four bits in the header. + +It is possible to use the raw BIE data stream as specified by the JBIG +standard directly as the format of a file used for storing images. +This is what the pbmtojbg, jbgtopbm, pbmtojbg85, and jbgtopbm85 +conversion tools do that are provided in this package as demonstration +applications. However, as the BIE format has been designed for a large +number of very different applications, and to allow efficient direct +processing by special JBIG hardware chip implementations, the BIE +header contains only the minimum amount of information absolutely +required by the decompression algorithm. Many features expected from a +good file format are missing in the BIE data stream: + + - no "magic code" in the first few bytes to allow identification + of the file format on a typeless file system and to allow + automatic distinction from other compression algorithms + + - no standardized way to encode additional information such as a + textual description, information about the meaning of various bit + planes, the physical size and resolution of the document, etc. + + - a checksum to ensure image integrity + + - encryption and signature mechanisms + + - many things more + +Raw BIE data streams alone may therefore not be a suitable format for +document archiving and exchange. A standard format for this purpose +would typically combine a BIE representing the image data with an +additional header providing auxiliary information into one file. +Existing established multi-purpose file formats with a rich set of +auxiliary information attributes like TIFF could be extended easily to +also hold JBIG compressed data. + +On the other hand, in e.g. database applications, a BIE might be +stored directly in a binary variable-length field. Auxiliary +information would then be stored in other fields of the same record, +to simplify search operations. + + +2 Compressing an image + +2.1 Format of the source image + +To be processed by the jbig.c encoder, the image has to be present in +memory as separate bitmap planes. Each byte of a bitmap contains eight +pixels, where the most significant bit represents the leftmost of +these. Each line of a bitmap has to be stored in an integral number of +bytes. If the image width is not an integral multiple of eight, then +the final byte has to be padded with zero bits. + +For example the 23x5 pixels large single plane image: + + .XXXXX..XXX...X...XXX.. + .....X..X..X..X..X..... + .....X..XXX...X..X.XXX. + .X...X..X..X..X..X...X. + ..XXX...XXX...X...XXX.. + +is represented by the 15 bytes + + 01111100 11100010 00111000 + 00000100 10010010 01000000 + 00000100 11100010 01011100 + 01000100 10010010 01000100 + 00111000 11100010 00111000 + +or in hexadecimal notation + + 7c e2 38 04 92 40 04 e2 5c 44 92 44 38 e2 38 + +This is the format used in binary PBM files and it can also be handled +directly by the Xlib library of the X Window System. + +As JBIG can also handle images with multiple bit planes, the jbig.c +library functions accept and return always arrays of pointers to +bitmaps with one pointer per plane. + +For single-plane images, the standard recommends that a 0 pixel +represents the background and a 1 pixel represents the foreground +colour of an image, in other words, 0 is white and 1 is black for +scanned paper documents. For images with several bits per pixel, the +JBIG standard makes no recommendations about how various colours should +be encoded. + +For grey-scale images, by using a Gray code instead of a simple binary +weighted representation of the pixel intensity, some increase in +coding efficiency can be reached. + +A Gray code is also a binary representation of integer numbers, but it +has the property that the representations of the integer numbers i and +(i+1) always differ in exactly one bit. For example, the numbers 0 to +7 can be represented in normal binary code and Gray code as in the +following table: + + normal + number binary code Gray code + --------------------------------------- + 0 000 000 + 1 001 001 + 2 010 011 + 3 011 010 + 4 100 110 + 5 101 111 + 6 110 101 + 7 111 100 + +The form of Gray code shown above has the property that the second +half of the code (numbers 4 - 7) is simply the mirrored first half +(numbers 3 - 0) with the first bit set to one. This way, arbitrarily +large Gray codes can be generated quickly by mirroring the above +example and prefixing the first half with zeros and the second half +with ones as often as required. In grey-scale images, it is common +practise to use the all-0 code for black and the all-1 code for white. + +No matter whether a Gray code or a binary code is used for encoding a +pixel intensity in several bit planes, it always makes sense to store +the most significant (leftmost) bit in plane 0, which is transmitted +first. This way, a decoder could increase the precision of the +displayed pixel intensities while data is still being received and the +basic structure of the image will become visible as early as possible +during the transmission. + + +2.2 A simple compression application + +In order to use jbig.c in your application, just link libjbig.a to +your executable (on Unix systems just add -ljbig and -L. to the +command line options of your compiler, on other systems you will have +to write a new Makefile anyway), copy the file jbig.h into your source +directory and put the line + + #include "jbig.h" + +into your source code. + +The library interface follows object-oriented programming principles. +You have to declare a variable (object) + + struct jbg_enc_state s; + +which contains the current status of an encoder. Then you initialize +the encoder by calling the constructor function + + void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y, + int pl, unsigned char **p, + void (*data_out)(unsigned char *start, size_t len, + void *file), + void *file); + +The parameters have the following meaning: + + s A pointer to the jbg_enc_state structure that you want + to initialize. + + x The width of your image in pixels. + + y The height of your image in pixels (lines). + + pl the number of bitmap planes you want to encode. + + p A pointer to an array of pl pointers, where each is again + pointing to the first byte of a bitmap as described in + section 2.1. + + data_out This is a call-back function that the encoder will + call during the compression process by in order to + deliver the BIE data to your application. The + parameters of the function data_out are a pointer + start to the new block of data being delivered, as + well as the number len of delivered bytes. The pointer + file is transparently delivered to data_out, as + specified in jbg_enc_init(). Typically, data_out will + write the BIE portion to a file, send it to a network + connection, or append it to some memory buffer. + + file A pointer parameter that is passed on to data_out() + and can be used, for instance, to allow data_out() to + distinguish by which compression task it has been + called in multi-threaded applications. + +In the simplest case, the compression is then started by calling the +function + + void jbg_enc_out(struct jbg_enc_state *s); + +which will deliver the complete BIE to data_out() in several calls. +After jbg_enc_out has returned, a call to the destructor function + + void jbg_enc_free(struct jbg_enc_state *s); + +will release any heap memory allocated by the previous functions. + + +A minimal example application, which sends the BIE of the above bitmap +to stdout, looks like this: + +--------------------------------------------------------------------------- +/* A sample JBIG encoding application */ + +#include +#include "jbig.h" + +void output_bie(unsigned char *start, size_t len, void *file) +{ + fwrite(start, 1, len, (FILE *) file); + + return; +} + +int main() +{ + unsigned char bitmap[15] = { + /* 23 x 5 pixels, "JBIG" */ + 0x7c, 0xe2, 0x38, 0x04, 0x92, 0x40, 0x04, 0xe2, + 0x5c, 0x44, 0x92, 0x44, 0x38, 0xe2, 0x38 + }; + unsigned char *bitmaps[1] = { bitmap }; + struct jbg_enc_state se; + + jbg_enc_init(&se, 23, 5, 1, bitmaps, + output_bie, stdout); /* initialize encoder */ + jbg_enc_out(&se); /* encode image */ + jbg_enc_free(&se); /* release allocated resources */ + + return 0; +} +--------------------------------------------------------------------------- + +This software produces a 42 byte long BIE. (JBIG is not very good at +compressing extremely small images like in this example, because the +arithmetic encoder requires some startup data in order to generate +reasonable statistics which influence the compression process and +because there is some header overhead.) + + +2.3 More about compression + +If jbg_enc_out() is called directly after jbg_enc_init(), the +following default values are used for various compression parameters: + + - Only one single resolution layer is used, i.e. no progressive + mode. + + - The number of lines per stripe is selected so that approximately + 35 stripes per image are used (as recommended in annex C of the + standard together with the suggested adaptive template change + algorithm). However, not less than 2 and not more than 128 lines + are used in order to stay within the suggested minimum parameter + support range specified in annex A of the standard). + + - All optional parts of the JBIG algorithm are activated (TPBON, + TPDON and DPON). + + - The default resolution reduction table and the default deterministic + prediction table are used + + - The maximal vertical offset of the adaptive template pixel is 0 + and the maximal horizontal offset is 8 (mx = 8, my = 0). + +In order to change any of these default parameters, additional +functions have to be called between jbg_enc_init() and jbg_enc_out(). + +In order to activate progressive encoding, it is possible to specify +with + + void jbg_enc_layers(struct jbg_enc_state *s, int d); + +the number d of differential resolution layers which shall be encoded +in addition to the lowest resolution layer 0. For example, if a +document with 60-micrometer pixels has to be stored, and the lowest +resolution layer shall have 240-micrometer pixels, so that a screen +previewer can directly decompress only the required resolution, then a +call + + jbg_enc_layers(&se, 2); + +will cause three layers with 240, 120 and 60 micrometers resolution to +be generated. + +If the application does not know what typical resolutions are used and +simply wants to ensure that the lowest resolution layer will fit into +a given maximal window size, then as an alternative, a call to + + int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long mwidth, + unsigned long mheight); + +will cause the library to automatically determine the suitable number +of resolutions so that the lowest resolution layer 0 will not be +larger than mwidth x mheight pixels. E.g. if one wants to ensure that +systems with a 640 x 480 pixel large screen can decode the required +resolution directly, then call + + jbg_enc_lrlmax(&se, 640, 480); + +The return value is the number of differential layers selected. + +After the number of resolution layers has been specified by calls to +jbg_enc_layers() or jbg_enc_lrlmax(), by default, all these layers +will be written into the BIE. This can be changed with a call to + + int jbg_enc_lrange(struct jbg_enc_state *s, int dl, int dh); + +Parameter dl specifies the lowest resolution layer and dh the highest +resolution layer that will appear in the BIE. For instance, if layer 0 +shall be written to the first BIE and layer 1 and 2 shall be written +to a second one, then before writing the first BIE, call + + jbg_enc_lrange(&se, 0, 0); + +and before writing the second BIE with jbg_enc_out(), call + + jbg_enc_lrange(&se, 1, 2); + +If any of the parameters is negative, it will be ignored. The return +value is the total number of differential layers that will represent +the input image. This way, jbg_enc_lrange(&se, -1, -1) can be used to +query the layer of the full image resolution. + +A number of other more exotic options of the JBIG algorithm can be +modified by calling + + void jbg_enc_options(struct jbg_enc_state *s, int order, int options, + long l0, int mx, int my); + +before calling jbg_enc_out(). + +The order parameter can be a combination of the bits JBG_HITOLO, +JBG_SEQ, JBG_ILEAVE and JBG_SMID and it determines in which order +the SDEs are stored in the BIE. The bits have the following meaning: + + JBG_HITOLO Usually, the lower resolution layers are stored before + the higher resolution layers, so that a decoder can + already start to display a low resolution version of + the full image once a prefix of the BIE has been + received. When this bit is set, however, the BIE will + contain the higher layers before the lower layers. This + avoids additional buffer memory in the encoder and is + intended for applications where the encoder is connected + to a database which can easily reorder the SDEs before + sending them to a decoder. Warning: JBIG decoders are + not expected to support the HITOLO option (e.g. the + jbig.c decoder currently does not) so you should + normally not use it. + + JBG_SEQ Usually, at first all stripes of one resolution layer + are written to the BIE and then all stripes of the next + layer, and so on. When the SEQ bit is set however, then + all layers of the first stripe will be written, + followed by all layers of the second stripe, etc. This + option also should normally never be required and is + not supported by the current jbig.c decoder. + + JBG_SMID In case there exist several bit planes, then the order of + the stripes is determined by three loops over all stripes, + all planes and all layers. When SMID is set, the loop + over all stripes is the middle loop. + + JBG_ILEAVE If this bit is set, then at first all layers of one + plane are written before the encoder starts with the next + plane. + +The above description may be somewhat confusing, but the following +table (see also Table 11 in ITU-T T.82) clarifies how the three bits +JBG_SEQ, JBIG_ILEAVE and JBG_SMID influence the ordering of the loops +over all stripes, planes and layers: + + + Loops: + JBG_SEQ JBG_ILEAVE JBG_SMID | Outer Middle Inner + ------------------------------------+--------------------------- + 0 0 0 | p d s + 0 1 0 | d p s + 0 1 1 | d s p + 1 0 0 | s p d + 1 0 1 | p s d + 1 1 0 | s d p + + p: plane, s: stripe, d: layer + + +By default, the order combination JBG_ILEAVE | JBG_SMID is used. + +The options value can contain the following bits, which activate +some of the optional algorithms defined by JBIG: + + JBG_LRLTWO Normally, in the lowest resolution layer, pixels + from three lines around the next pixel are used + in order to determine the context in which the next + pixel is encoded. Some people in the JBIG committee + seem to have argued that using only 2 lines will + make software implementations a little bit faster, + however others have argued that using only two lines + will decrease compression efficiency by around 5%. + As you might expect from a committee, now both + alternatives are allowed and if JBG_LRLTWO is set, + the slightly faster but 5% less well compressing two + line alternative is selected. God bless the committees. + Although probably nobody will ever need this option, + it has been implemented in jbig.c and is off by + default. + + JBG_TPDON This activates the "typical prediction" algorithm + for differential layers which avoids that large + areas of equal colour have to be encoded at all. + This is on by default and there is no good reason to + switch it off except for debugging or preparing data + for cheap JBIG hardware that might not support this + option. + + JBG_TPBON Like JBG_TPDON this activates the "typical prediction" + algorithm in the lowest resolution layer. Also activated + by default. + + JBG_DPON This bit activates for the differential resolution + layers the "deterministic prediction" algorithm, + which avoids that higher resolution layer pixels are + encoded when their value can already be determined + with the knowledge of the neighbour pixels, the + corresponding lower resolution pixels and the + resolution reduction algorithm. This is also + activated by default and one reason for deactivating + it would be if the default resolution reduction + algorithm were replaced by another one. + + JBG_DELAY_AT Use a slightly less efficient algorithm to determine + when an adaptive template change is necessary. With + this bit set, the encoder output is compatible to the + conformance test examples in cause 7.2 of ITU-T T.82. + Then all adaptive template changes are delayed until + the first line of the next stripe. This option is by + default deactivated and is only required for passing a + special compatibility test suite. + +In addition, parameter l0 in jbg_enc_options() allows you to specify +the number of lines per stripe in resolution layer 0. The parameters +mx and my change the maximal offset allowed for the adaptive template +pixel. JBIG-KIT now supports the full range of possible mx values up +to 127 in the encoder and decoder, but my is at the moment ignored and +always set to 0. As the standard requires of all decoder +implementations only to support maximum values mx = 16 and my = 0, +higher values should normally be avoided in order to guarantee +interoperability. The ITU-T T.85 profile for JBIG in fax machines +requires support for mx = 127 and my = 0. Default is mx = 8 and my = +0. If any of the parameters order, options, mx or my is negative, or +l0 is zero, then the corresponding current value remains unmodified. + +The resolution reduction and deterministic prediction tables can also +be replaced. However as these options are anyway only for experts, +please have a look at the source code of jbg_enc_out() and the struct +members dppriv and res_tab of struct jbg_enc_state for the details of +how to do this, in case you really need it. The functions +jbg_int2dppriv and jbg_dppriv2int are provided in order to convert the +DPTABLE data from the format used in the standard into the more +efficient format used internally by JBIG-KIT. + +If you want to encode a grey-scale image, you can use the library +function + + void jbg_split_planes(unsigned long x, unsigned long y, int has_planes, + int encode_planes, + const unsigned char *src, unsigned char **dest, + int use_graycode); + +It separates an image in which each pixel is represented by one or +more bytes into separate bit planes. The dest array of pointers to +these bit planes can then be handed over to jbg_enc_init(). The +variables x and y specify the width and height of the image in pixels, +and has_planes specifies how many bits per pixel are used. As each +pixel is represented by an integral number of consecutive bytes, of +which each contains up to eight bits, the total length of the input +image array src[] will therefore be x * y * ((has_planes + 7) / 8) +bytes. The pixels are stored as usually in English reading order, and +for each pixel the integer value is stored with the most significant +byte coming first (Bigendian). This is exactly the format used in raw +PGM files. In encode_planes, the number of bit planes that shall be +extracted can be specified. This allows for instance to extract only +the most significant 8 bits of a 12-bit image, where each pixel is +represented by two bytes, by specifying has_planes = 12 and +encode_planes = 8. If use_graycode is zero, then the binary code of +the pixel integer values will be used instead of the Gray code. Plane +0 contains always the most significant bit. + + +3 Decompressing an image + +Like with the compression functions, if you want to use the jbig.c +library, you have to put the line + + #include "jbig.h" + +into your source code and link your executable with libjbig.a. + +The state of a JBIG decoder is stored completely in a struct and you +will have to define a variable like + + struct jbg_dec_state sd; + +which is initialized by a call to + + void jbg_dec_init(struct jbg_dec_state *s); + +After this, you can directly start to pass data from the BIE to the decoder +by calling the function + + int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len, + size_t *cnt); + +The pointer data points to the first byte of a data block with length +len, which contains bytes from a BIE. It is not necessary to pass a +whole BIE at once to jbg_dec_in(), it can arrive fragmented in any way +by calling jbg_dec_in() several times. It is also possible to send +several BIEs concatenated to jbg_dec_in(), however these then have to +fit together. If you send several BIEs to the decoder, the lowest +resolution layer in each following BIE has to be the highest +resolution layer in the previous BIE plus one and the image sizes and +number of planes also have to fit together, otherwise jbg_dec_in() +will return the error JBG_ENOCONT after the header of the new BIE has +been received completely. + +If pointer cnt is not NULL, then the number of bytes actually read +from the data block will be stored there. In case the data block did +not contain the end of the BIE, then the value JBG_EAGAIN will be +returned and *cnt equals len. + +Once the end of a BIE has been reached, the return value of +jbg_dec_in() will be JBG_EOK. After this has happened, the functions +and macros + + unsigned long jbg_dec_getwidth(struct jbg_dec_state *s); + unsigned long jbg_dec_getheight(struct jbg_dec_state *s); + int jbg_dec_getplanes(struct jbg_dec_state *s); + unsigned char *jbg_dec_getimage(struct jbg_dec_state *s, int plane); + unsigned long jbg_dec_getsize(struct jbg_dec_state *s); + +can be used to query the dimensions of the now completely decoded +image and to get a pointer to all bitmap planes. The bitmaps are +stored as described in section 2.1. The function jbg_dec_getsize() +calculates the number of bytes which one bitmap requires. + +The function + + void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode, + void (*data_out)(unsigned char *start, size_t len, + void *file), void *file); + +allows you to merge the bit planes that can be accessed individually +with jbg_dec_getimage() into an array with one or more bytes per pixel +(i.e., the format provided to jbg_split_planes()). If use_graycode is +zero, then a binary encoding will be used. The output array will be +delivered via the callback function data_out, exactly in the same way +in which the encoder provides the BIE. The function + + unsigned long jbg_dec_getsize_merged(const struct jbg_dec_state *s); + +determines how long the data array delivered by jbg_dec_merge_planes() +is going to be. + +Before calling jbg_dec_in() the first time, it is possible to specify with +a call to + + void jbg_dec_maxsize(struct jbg_dec_state *s, unsigned long xmax, + unsigned long ymax); + +an abort criterion for progressively encoded images. For instance if an +application will display a whole document on a screen which is 1024 x +768 pixels large, then this application should call + + jbg_dec_maxsize(&sd, 1024, 768); + +before the decoding process starts. If the image has been encoded in +progressive mode (i.e. with several resolution layers), then the +decoder will stop with a return value JBG_EOK_INTR after the largest +resolution layer that is still smaller than 1024 x 768. However this +is no guarantee that the image which can then be read out using +jbg_dec_getimage(), etc. is really not larger than the specified +maximal size. The application will have to check the size of the +image, because the decoder does not automatically apply a resolution +reduction if no suitable resolution layer is available in the BIE. + +If jbg_dec_in() returned JBG_EOK_INTR or JBG_EOK, then it is possible +to continue calling jbg_dec_in() with the remaining data in order to +either decode the remaining resolution layers of the current BIE or in +order to add another BIE with additional resolution layers. In both +cases, after jbg_dec_in() returned JBG_EOK_INTR or JBG_EOK, *cnt is +probably not equal to len and the remainder of the data block which +has not yet been processed by the decoder has to be delivered to +jbg_dec_in() again. + +If any other return value than JBG_EOK, JBG_EOK_INTR or JBG_EAGAIN +has been returned by jbg_dec_in(), then an error has occurred and + + void jbg_dec_free(struct jbg_dec_state *s); + +should be called in order to release any allocated memory. The +destructor jbg_dec_free() should of course also be called, once the +decoded bitmap returned by jbg_dec_getimage() is no longer required +and the memory can be released. + +The function + + const char *jbg_strerror(int errnum); + +returns a pointer to a short single line test message that explains +the return value of jbg_dec_in(). This message can be used in order to +provide the user a brief informative message about what when wrong +while decompressing a JBIG image. The po/ subdirectory contains *.po +files that translate the English ASCII strings returned by +jbg_strerror() into other languages (e.g., for use with GNU gettext). +The four least-significant bits of the return value of jbg_dec_in() +may contain additional detailed technical information about the exact +test that spotted the error condition (see source code for details), +i.e. more than the text message returned by jbg_strerror() reveals. +Therefore it may be useful to display the return value itself as a +hexadecimal number, in addition to the string returned by +jbg_strerror(). + +The current implementation of the jbig.c decoder has the following +limitations: + + - The maximal vertical offset MY of the adaptive template pixel + must be zero. + + - HITOLO and SEQ bits must not be set in the order value. + + - Not more than JBG_ATMOVES_MAX (currently set to 64) ATMOVE + marker segments can be handled per stripe. + + - the number D of differential layers must be less than 32 + +None of the above limitations can be exceeded by a JBIG data stream +that conforms to the ITU-T T.85 application profile for the use of +JBIG1 in fax machines. + +The current implementation of the jbig.c decoder does not impose any +limits on the image size that it will process, as long as malloc() is +able to allocate enough heap space for the resulting bitmaps. The only +exception is that jbg_dec_in() will return "Input data stream uses +unimplemented JBIG features" (JBG_EIMPL | 1) if Y_D equals 0xffffffff, +which is an extreme value commonly used to encode images according to +ITU-T T.85 where the height was unknown when the BIH was emitted. +After jbg_dec_in() received the 20-byte long BIH at the start of the +BIE, it will malloc() to allocate enough memory to hold the requested +image planes and layers. If you want to defend your application +against excessive image-size parameters in a received BIH, then do +make sure that you check X_D, Y_D, and P against appropriate safety +limits before handing over the BIH to jbg_dec_in(). + +There are two more limitations of the current implementation of the +jbig.c decoder that might cause problems with processing JBIG data +stream that conform to ITU-T T.85: + + - The jbig.c decoder was designed to operate incrementally. + Each received byte is processed immediately as soon as it arrives. + As a result, it does not look beyond the SDRST/SDNORM at the end + of all stripes for any immediately following NEWLEN marker that + might reduce the number of lines encoded by the current stripe. + However section 6.2.6.2 of ITU-T T.82 says that a NEWLEN marker + segment "could refer to a line in the immediately preceding stripe + due to an unexpected termination of the image or the use of only + such stripe", and ITU-T.85 explicitly suggests the use of this + for fax machines that start transmission before having encountered + the end of the page. + + - The image size initially indicated in the BIE header is used to + allocate memory for a bitmap of this size. This means that BIEs + that set initially Y_D = 0xffffffff (as suggested in ITU-T T.85 + for fax machines that do not know the height of the page at the + start of the transmission) cannot be decoded directly by this + version. + +For both issues, there is a workaround available: + +If you encounter a BIE that has in the header the VLENGTH=1 option bit +set, then first wait until you have received the entire BIE and stored +it in memory. Then call the function + + int jbg_newlen(unsigned char *bie, size_t len); + +where bie is a pointer to the first byte of the BIE and len its length +in bytes. This function will scan the entire BIE for the first NEWLEN +marker segment. It will then take the updated image-height value YD +from it and use it to overwrite the YD value in the BIE header. The +jbg_newlen() can return some of the same error codes as jbg_dec_in(), +namely JBG_EOK if everything went fine, JBG_EAGAIN is the data +provided is too short to be a valid BIE, JBG_EINVAL if a format error +was encountered, and JBG_EABORT if an ABORT marker segment was found. +After having patched the image-height value in the BIE using +jbg_newlen(), simply hand over the BIE as usual to jbg_dec_in(). + +In general, for applications where NEWLEN markers can appear, in +particular fax reception, you should consider using the jbig85.c +decoder instead, as it can process BIEs with NEWLEN markers in a +single pass. + +A more detailed description of the JBIG-KIT implementation is + + Markus Kuhn: Effiziente Kompression von bi-level Bilddaten durch + kontextsensitive arithmetische Codierung. Studienarbeit, Lehrstuhl + für Betriebssysteme, IMMD IV, Universität Erlangen-Nürnberg, + Erlangen, July 1995. (German, 62 pages) + + +Please quote the above if you use JBIG-KIT in your research project. + +*** Happy compressing *** + +[end] diff --git a/libjbig/jbig85.c b/libjbig/jbig85.c new file mode 100644 index 0000000..ca9cf43 --- /dev/null +++ b/libjbig/jbig85.c @@ -0,0 +1,1091 @@ +/* + * T.85 "light" version of the portable JBIG image compression library + * + * Copyright 1995-2014 -- Markus Kuhn -- http://www.cl.cam.ac.uk/~mgk25/ + * + * This module implements a portable standard C encoder and decoder + * using the JBIG1 lossless bi-level image compression algorithm + * specified in International Standard ISO 11544:1993 and + * ITU-T Recommendation T.82. See the file jbig.txt for usage + * instructions and application examples. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * If you want to use this program under different license conditions, + * then contact the author for an arrangement. + */ + +#ifdef DEBUG +#include +#else +#define NDEBUG +#endif + +#include +#include +#include + +#include "jbig85.h" + +#define TPB2CX 0x195 /* contexts for TP special pixels */ +#define TPB3CX 0x0e5 + +/* marker codes */ +#define MARKER_STUFF 0x00 +#define MARKER_RESERVE 0x01 +#define MARKER_SDNORM 0x02 +#define MARKER_SDRST 0x03 +#define MARKER_ABORT 0x04 +#define MARKER_NEWLEN 0x05 +#define MARKER_ATMOVE 0x06 +#define MARKER_COMMENT 0x07 +#define MARKER_ESC 0xff + +/* object code version id */ + +const char jbg85_version[] = + "JBIG-KIT " JBG85_VERSION " (T.85 version) -- (c) 1995-2014 Markus Kuhn -- " + "Licence: " JBG85_LICENCE "\n"; + +#define _(String) String /* to mark translatable string for GNU gettext */ + +/* + * Array with English ASCII error messages that correspond + * to return values from public functions in this library. + */ +static const char *errmsg[] = { + _("All OK"), /* JBG_EOK */ + _("Reached specified image size"), /* JBG_EOK_INTR */ + _("Unexpected end of input data stream"), /* JBG_EAGAIN */ + _("Not enough memory available"), /* JBG_ENOMEM */ + _("ABORT marker segment encountered"), /* JBG_EABORT */ + _("Unknown marker segment encountered"), /* JBG_EMARKER */ + _("Input data stream contains invalid data"), /* JBG_EINVAL */ + _("Input data stream uses unimplemented JBIG features") /* JBG_EIMPL */ +}; + + +/* + * Callback adapter function for arithmetic encoder + */ +static void enc_byte_out(int byte, void *s) +{ + unsigned char c = byte; + ((struct jbg85_enc_state *)s)->data_out(&c, sizeof(unsigned char), + ((struct jbg85_enc_state *)s)->file); +} + + +/* + * Initialize the status struct for the encoder. + */ +void jbg85_enc_init(struct jbg85_enc_state *s, + unsigned long x0, unsigned long y0, + void (*data_out)(unsigned char *start, size_t len, + void *file), + void *file) +{ + assert(x0 > 0 && y0 > 0); + s->x0 = x0; + s->y0 = y0; + s->newlen = 0; /* no NEWLEN pending or output */ + s->data_out = data_out; + s->file = file; + + s->l0 = s->y0 / 35; /* 35 stripes/image suggested default */ + if (s->l0 > 128) s->l0 = 128; + else if (s->l0 < 2) s->l0 = 2; +#if 1 + s->l0 = 128; /* T.85 BASIC setting */ +#endif + s->mx = 127; + s->new_tx = -1; /* no ATMOVE pending */ + s->tx = 0; + s->options = JBG_TPBON | JBG_VLENGTH; + s->comment = NULL; /* no COMMENT pending */ + s->y = 0; + s->i = 0; + s->ltp_old = 0; + + /* initialize arithmetic encoder */ + arith_encode_init(&s->s, 0); + s->s.byte_out = &enc_byte_out; + s->s.file = s; + + return; +} + + +/* + * The following function allows to specify the bits describing the + * options of the format as well as the maximum AT movement window and + * the number of layer 0 lines per stripes. + */ +void jbg85_enc_options(struct jbg85_enc_state *s, int options, + unsigned long l0, int mx) +{ + if (s->y > 0) return; /* too late to change anything now */ + + if (options >= 0) s->options = options; + if (l0 > 0) s->l0 = l0; + if (mx >= 0 && mx < 128) s->mx = mx; + + return; +} + + +/* auxiliary routine to write out NEWLEN */ +static void output_newlen(struct jbg85_enc_state *s) +{ + unsigned char buf[6]; + + assert(s->i == 0); + if (s->newlen != 1) + return; + buf[0] = MARKER_ESC; + buf[1] = MARKER_NEWLEN; + buf[2] = s->y0 >> 24; + buf[3] = (s->y0 >> 16) & 0xff; + buf[4] = (s->y0 >> 8) & 0xff; + buf[5] = s->y0 & 0xff; + s->data_out(buf, 6, s->file); + s->newlen = 2; + if (s->y == s->y0) { + /* if newlen refers to a line in the preceeding stripe, ITU-T T.82 + * section 6.2.6.2 requires us to append another SDNORM */ + buf[1] = MARKER_SDNORM; + s->data_out(buf, 2, s->file); + } +} + + +/* + * Encode one full BIE and pass the generated data to the specified + * call-back function + */ +void jbg85_enc_lineout(struct jbg85_enc_state *s, unsigned char *line, + unsigned char *prevline, unsigned char *prevprevline) +{ + unsigned char buf[20]; + unsigned long bpl; + unsigned char *hp1, *hp2, *hp3, *p1, *q1; + unsigned long line_h1 = 0, line_h2, line_h3; + unsigned long j; /* loop variable for pixel column */ + long o; + unsigned a, p, t; + int ltp; + unsigned long cmin, cmax, clmin, clmax; + int tmax; +#ifdef DEBUG + static long tp_lines; + static long encoded_pixels; +#endif + + if (s->y >= s->y0) { + /* we have already output the full image, go away */ + return; + } + + /* line 0 has no previous line */ + if (s->y < 1) + prevline = NULL; + if (s->y < 2) + prevprevline = NULL; + + /* things that need to be done before the first line is encoded */ + if (s->y == 0) { + /* prepare BIH */ + buf[0] = 0; /* DL = initial layer to be transmitted */ + buf[1] = 0; /* D = number of differential layers */ + buf[2] = 1; /* P = number of bit planes */ + buf[3] = 0; + buf[4] = s->x0 >> 24; + buf[5] = (s->x0 >> 16) & 0xff; + buf[6] = (s->x0 >> 8) & 0xff; + buf[7] = s->x0 & 0xff; + buf[8] = s->y0 >> 24; + buf[9] = (s->y0 >> 16) & 0xff; + buf[10] = (s->y0 >> 8) & 0xff; + buf[11] = s->y0 & 0xff; + buf[12] = s->l0 >> 24; + buf[13] = (s->l0 >> 16) & 0xff; + buf[14] = (s->l0 >> 8) & 0xff; + buf[15] = s->l0 & 0xff; + buf[16] = s->mx; + buf[17] = 0; /* MY = maximum vertical offset allowed for AT pixel */ + buf[18] = 0; /* order: HITOLO = SEQ = ILEAVE = SMID = 0 */ + buf[19] = s->options & (JBG_LRLTWO | JBG_VLENGTH | JBG_TPBON); + + /* output BIH */ + s->data_out(buf, 20, s->file); + } + + /* things that need to be done before the next SDE is encoded */ + if (s->i == 0) { + + /* output NEWLEN if there is any pending */ + output_newlen(s); + + /* output comment marker segment if there is any pending */ + if (s->comment) { + buf[0] = MARKER_ESC; + buf[1] = MARKER_COMMENT; + buf[2] = s->comment_len >> 24; + buf[3] = (s->comment_len >> 16) & 0xff; + buf[4] = (s->comment_len >> 8) & 0xff; + buf[5] = s->comment_len & 0xff; + s->data_out(buf, 6, s->file); + s->data_out(s->comment, s->comment_len, s->file); + s->comment = NULL; + } + + /* output ATMOVE if there is any pending */ + if (s->new_tx != -1 && s->new_tx != s->tx) { + s->tx = s->new_tx; + buf[0] = MARKER_ESC; + buf[1] = MARKER_ATMOVE; + buf[2] = 0; + buf[3] = 0; + buf[4] = 0; + buf[5] = 0; + buf[6] = s->tx; + buf[7] = 0; + s->data_out(buf, 8, s->file); + } + + /* initialize adaptive template movement algorithm */ + if (s->mx == 0) { + s->new_tx = 0; /* ATMOVE has been disabled */ + } else { + s->c_all = 0; + for (t = 0; t <= s->mx; t++) + s->c[t] = 0; + s->new_tx = -1; /* we have yet to determine ATMOVE ... */ + } + + /* restart arithmetic encoder */ + arith_encode_init(&s->s, 1); + } + +#ifdef DEBUG + if (s->y == 0) + tp_lines = encoded_pixels = 0; + fprintf(stderr, "encode line %lu (%2lu of stripe)\n", s->y, s->i); +#endif + + /* bytes per line */ + bpl = (s->x0 >> 3) + !!(s->x0 & 7); + /* ensure correct zero padding of bitmap at the final byte of each line */ + if (s->x0 & 7) { + line[bpl - 1] &= ~((1 << (8 - (s->x0 & 7))) - 1); + } + + /* typical prediction */ + ltp = 0; + if (s->options & JBG_TPBON) { + p1 = line; + q1 = prevline; + ltp = 1; + if (q1) + while (p1 < line + bpl && (ltp = (*p1++ == *q1++)) != 0) ; + else + while (p1 < line + bpl && (ltp = (*p1++ == 0 )) != 0) ; + arith_encode(&s->s, (s->options & JBG_LRLTWO) ? TPB2CX : TPB3CX, + ltp == s->ltp_old); +#ifdef DEBUG + tp_lines += ltp; +#endif + s->ltp_old = ltp; + } + + if (!ltp) { + + /* + * Layout of the variables line_h1, line_h2, line_h3, which contain + * as bits the neighbour pixels of the currently coded pixel X: + * + * 76543210765432107654321076543210 line_h3 + * 76543210765432107654321076543210 line_h2 + * 76543210765432107654321X76543210 line_h1 + */ + + /* pointer to first image byte of the three lines of interest */ + hp3 = prevprevline; + hp2 = prevline; + hp1 = line; + + line_h1 = line_h2 = line_h3 = 0; + if (hp2) line_h2 = (long)*hp2 << 8; + if (hp3) line_h3 = (long)*hp3 << 8; + + /* encode line */ + for (j = 0; j < s->x0;) { + line_h1 |= *hp1; + if (j < bpl * 8 - 8 && hp2) { + line_h2 |= *(hp2 + 1); + if (hp3) + line_h3 |= *(hp3 + 1); + } + if (s->options & JBG_LRLTWO) { + /* two line template */ + do { + line_h1 <<= 1; line_h2 <<= 1; line_h3 <<= 1; + if (s->tx) { + if ((unsigned) s->tx > j) + a = 0; + else { + o = (j - s->tx) - (j & ~7L); + a = (hp1[o >> 3] >> (7 - (o & 7))) & 1; + a <<= 4; + } + assert(s->tx > 23 || + a == ((line_h1 >> (4 + s->tx)) & 0x010)); + arith_encode(&s->s, (((line_h2 >> 10) & 0x3e0) | a | + ((line_h1 >> 9) & 0x00f)), + (line_h1 >> 8) & 1); + } + else + arith_encode(&s->s, (((line_h2 >> 10) & 0x3f0) | + ((line_h1 >> 9) & 0x00f)), + (line_h1 >> 8) & 1); +#ifdef DEBUG + encoded_pixels++; +#endif + /* statistics for adaptive template changes */ + if (s->new_tx == -1 && j >= s->mx && j < s->x0 - 2) { + p = (line_h1 & 0x100) != 0; /* current pixel value */ + s->c[0] += ((line_h2 & 0x4000) != 0) == p; /* default position */ + assert(!(((line_h2 >> 6) ^ line_h1) & 0x100) == + (((line_h2 & 0x4000) != 0) == p)); + for (t = 5; t <= s->mx && t <= j; t++) { + o = (j - t) - (j & ~7L); + a = (hp1[o >> 3] >> (7 - (o & 7))) & 1; + assert(t > 23 || + (a == p) == !(((line_h1 >> t) ^ line_h1) & 0x100)); + s->c[t] += a == p; + } + for (; t <= s->mx; t++) { + s->c[t] += 0 == p; + } + ++s->c_all; + } + } while (++j & 7 && j < s->x0); + } else { + /* three line template */ + do { + line_h1 <<= 1; line_h2 <<= 1; line_h3 <<= 1; + if (s->tx) { + if ((unsigned) s->tx > j) + a = 0; + else { + o = (j - s->tx) - (j & ~7L); + a = (hp1[o >> 3] >> (7 - (o & 7))) & 1; + a <<= 2; + } + assert(s->tx > 23 || + a == ((line_h1 >> (6 + s->tx)) & 0x004)); + arith_encode(&s->s, (((line_h3 >> 8) & 0x380) | + ((line_h2 >> 12) & 0x078) | a | + ((line_h1 >> 9) & 0x003)), + (line_h1 >> 8) & 1); + } else + arith_encode(&s->s, (((line_h3 >> 8) & 0x380) | + ((line_h2 >> 12) & 0x07c) | + ((line_h1 >> 9) & 0x003)), + (line_h1 >> 8) & 1); +#ifdef DEBUG + encoded_pixels++; +#endif + /* statistics for adaptive template changes */ + if (s->new_tx == -1 && j >= s->mx && j < s->x0 - 2) { + p = (line_h1 & 0x100) != 0; /* current pixel value */ + s->c[0] += ((line_h2 & 0x4000) != 0) == p; /* default position */ + assert(!(((line_h2 >> 6) ^ line_h1) & 0x100) == + (((line_h2 & 0x4000) != 0) == p)); + for (t = 3; t <= s->mx && t <= j; t++) { + o = (j - t) - (j & ~7L); + a = (hp1[o >> 3] >> (7 - (o & 7))) & 1; + assert(t > 23 || + (a == p) == !(((line_h1 >> t) ^ line_h1) & 0x100)); + s->c[t] += a == p; + } + for (; t <= s->mx; t++) { + s->c[t] += 0 == p; + } + ++s->c_all; + } + } while (++j & 7 && j < s->x0); + } /* if (s->options & JBG_LRLTWO) */ + hp1++; + if (hp2) hp2++; + if (hp3) hp3++; + } /* for (j = ...) */ + } /* if (!ltp) */ + + /* line is complete now, deal with end of stripe */ + s->i++; s->y++; + if (s->i == s->l0 || s->y == s->y0) { + /* end of stripe reached */ + arith_encode_flush(&s->s); + buf[0] = MARKER_ESC; + buf[1] = MARKER_SDNORM; + s->data_out(buf, 2, s->file); + s->i = 0; + + /* output NEWLEN if there is any pending */ + output_newlen(s); + } + + /* check whether it is worth to perform an ATMOVE */ + if (s->new_tx == -1 && s->c_all > 2048) { + cmin = clmin = 0xffffffffL; + cmax = clmax = 0; + tmax = 0; + for (t = (s->options & JBG_LRLTWO) ? 5 : 3; t <= s->mx; t++) { + if (s->c[t] > cmax) cmax = s->c[t]; + if (s->c[t] < cmin) cmin = s->c[t]; + if (s->c[t] > s->c[tmax]) tmax = t; + } + clmin = (s->c[0] < cmin) ? s->c[0] : cmin; + clmax = (s->c[0] > cmax) ? s->c[0] : cmax; + if (s->c_all - cmax < (s->c_all >> 3) && + cmax - s->c[s->tx] > s->c_all - cmax && + cmax - s->c[s->tx] > (s->c_all >> 4) && + /* ^ T.82 said < here, fixed in Cor.1/25 */ + cmax - (s->c_all - s->c[s->tx]) > s->c_all - cmax && + cmax - (s->c_all - s->c[s->tx]) > (s->c_all >> 4) && + cmax - cmin > (s->c_all >> 2) && + (s->tx || clmax - clmin > (s->c_all >> 3))) { + /* we have decided to perform an ATMOVE */ + s->new_tx = tmax; +#ifdef DEBUG + fprintf(stderr, "ATMOVE: tx=%d, c_all=%lu\n", + s->new_tx, s->c_all); +#endif + } else { + s->new_tx = s->tx; /* we have decided not to perform an ATMOVE */ + } + } + assert(s->tx >= 0); /* i.e., tx can safely be cast to unsigned */ + +#ifdef DEBUG + if (s->y == s->y0) + fprintf(stderr, "tp_lines = %ld, encoded_pixels = %ld\n", + tp_lines, encoded_pixels); +#endif + + return; +} + + +/* + * Inform encoder about new (reduced) height of image + */ +void jbg85_enc_newlen(struct jbg85_enc_state *s, unsigned long newlen) +{ + unsigned char buf[6]; + + if (s->newlen == 2 || newlen >= s->y0 || newlen < 1 || + !(s->options & JBG_VLENGTH)) { + /* invalid invocation or parameter */ + return; + } + if (newlen < s->y) { + /* we are already beyond the new end, therefore move the new end */ + newlen = s->y; + } + if (s->y > 0 && s->y0 != newlen) + s->newlen = 1; + s->y0 = newlen; + if (s->y == s->y0) { + /* we are already at the end; finish the current stripe if necessary */ + if (s->i > 0) { + arith_encode_flush(&s->s); + buf[0] = MARKER_ESC; + buf[1] = MARKER_SDNORM; + s->data_out(buf, 2, s->file); + s->i = 0; + } + /* output NEWLEN if there is any pending */ + output_newlen(s); + } +} + + +/* + * Abort encoding process immediately by outputting an ABORT marker segment + */ +void jbg85_enc_abort(struct jbg85_enc_state *s) +{ + unsigned char buf[2]; + + buf[0] = MARKER_ESC; + buf[1] = MARKER_ABORT; + s->data_out(buf, 2, s->file); + s->y = s->y0; /* just to prevent further calls to jbg85_enc_lineout() */ +} + + +/* + * Convert the error codes used by jbg85_dec_in() into an English ASCII string + */ +const char *jbg85_strerror(int errnum) +{ + errnum >>= 4; + if (errnum < 0 || (unsigned) errnum >= sizeof(errmsg)/sizeof(errmsg[0])) + return "Unknown error code passed to jbg85_strerror()"; + + return errmsg[errnum]; +} + + +/* + * The constructor for a decoder + */ +void jbg85_dec_init(struct jbg85_dec_state *s, + unsigned char *buf, size_t buflen, + int (*line_out)(const struct jbg85_dec_state *s, + unsigned char *start, size_t len, + unsigned long y, void *file), + void *file) +{ + s->x0 = 0; + s->y0 = 0; + s->linebuf = buf; + s->linebuf_len = buflen; + s->line_out = line_out; + s->file = file; + s->bie_len = 0; + s->end_of_bie = 0; + s->x = 0; + s->y = 0; + s->i = 0; + s->comment_skip = 0; + s->buf_len = 0; + s->pseudo = 1; + s->at_moves = 0; + s->tx = 0; + s->lntp = 1; + s->p[0] = 0; + s->p[1] = -1; + s->p[2] = -1; + arith_decode_init(&s->s, 0); + return; +} + + +/* + * Decode the new len PSCD bytes to which data points and output + * decoded lines as they are completed. Return the number of bytes + * which have actually been read. This will be less than len if a + * marker segment was part of the data or if the final byte was + * 0xff, meaning that this code can not determine whether we have a + * marker segment. + */ +static size_t decode_pscd(struct jbg85_dec_state *s, unsigned char *data, + size_t len) +{ + unsigned char *hp1, *hp2, *hp3, *p1; + register unsigned long line_h1, line_h2, line_h3; + unsigned long x; + long o; + unsigned a; + int n; + int pix, slntp; + int buflines = 3 - !!(s->options & JBG_LRLTWO); + + /* forward data to arithmetic decoder */ + s->s.pscd_ptr = data; + s->s.pscd_end = data + len; + + /* restore a few local variables */ + line_h1 = s->line_h1; + line_h2 = s->line_h2; + line_h3 = s->line_h3; + x = s->x; + +#ifdef DEBUG + if (x == 0 && s->i == 0 && s->pseudo) + fprintf(stderr, "decode_pscd(%p, %p, %ld)\n", + (void *) s, (void *) data, (long) len); +#endif + + s->intr = 0; + for (; s->i < s->l0 && s->y < s->y0 && !s->intr; s->i++, s->y++) { + + /* pointer to image byte */ + hp1 = s->linebuf + s->p[0] * s->bpl + (x >> 3); + hp2 = s->linebuf + s->p[1] * s->bpl + (x >> 3); + hp3 = s->linebuf + s->p[2] * s->bpl + (x >> 3); + + /* adaptive template changes */ + if (x == 0 && s->pseudo) + for (n = 0; n < s->at_moves; n++) + if (s->at_line[n] == s->i) { + s->tx = s->at_tx[n]; +#ifdef DEBUG + fprintf(stderr, "ATMOVE: line=%lu, tx=%d.\n", s->i, s->tx); +#endif + } + assert(s->tx >= 0); /* i.e., tx can safely be cast to unsigned */ + + /* typical prediction */ + if (s->options & JBG_TPBON && s->pseudo) { + slntp = arith_decode(&s->s, (s->options & JBG_LRLTWO) ? TPB2CX : TPB3CX); + if (slntp < 0) + goto leave; + s->lntp = + !(slntp ^ s->lntp); + if (!s->lntp) { + /* this line is 'typical' (i.e. identical to the previous one) */ + if (s->p[1] < 0) { + /* first line of page or (following SDRST) of stripe */ + for (p1 = hp1; p1 < hp1 + s->bpl; *p1++ = 0) ; + s->intr = s->line_out(s, hp1, s->bpl, s->y, s->file); + /* rotate the ring buffer that holds the last three lines */ + s->p[2] = s->p[1]; + s->p[1] = s->p[0]; + if (++(s->p[0]) >= buflines) s->p[0] = 0; + } else { + s->intr = s->line_out(s, hp2, s->bpl, s->y, s->file); + /* duplicate the last line in the ring buffer */ + s->p[2] = s->p[1]; + } + continue; + } + /* this line is 'not typical' and has to be coded completely */ + } + s->pseudo = 0; + + /* + * Layout of the variables line_h1, line_h2, line_h3, which contain + * as bits the neighbour pixels of the currently decoded pixel X: + * + * 76543210 76543210 76543210 76543210 line_h3 + * 76543210 76543210 76543210 76543210 line_h2 + * 76543210 76543210 76543210 76543210 X line_h1 + */ + + if (x == 0) { + line_h1 = line_h2 = line_h3 = 0; + if (s->p[1] >= 0) + line_h2 = (long)*hp2 << 8; + if (s->p[2] >= 0) + line_h3 = (long)*hp3 << 8; + } + + /* decode line */ + while (x < s->x0) { + if ((x & 7) == 0) { + if (x < (s->bpl - 1) * 8 && s->p[1] >= 0) { + line_h2 |= *(hp2 + 1); + if (s->p[2] >= 0) + line_h3 |= *(hp3 + 1); + } + } + if (s->options & JBG_LRLTWO) { + /* two line template */ + do { + if (s->tx) { + if ((unsigned) s->tx > x) + a = 0; + else if (s->tx < 8) + a = ((line_h1 >> (s->tx - 5)) & 0x010); + else { + o = (x - s->tx) - (x & ~7L); + a = (hp1[o >> 3] >> (7 - (o & 7))) & 1; + a <<= 4; + } + assert(s->tx > 31 || + a == ((line_h1 >> (s->tx - 5)) & 0x010)); + pix = arith_decode(&s->s, (((line_h2 >> 9) & 0x3e0) | a | + (line_h1 & 0x00f))); + } else + pix = arith_decode(&s->s, (((line_h2 >> 9) & 0x3f0) | + (line_h1 & 0x00f))); + if (pix < 0) + goto leave; + line_h1 = (line_h1 << 1) | pix; + line_h2 <<= 1; + } while ((++x & 7) && x < s->x0); + } else { + /* three line template */ + do { + if (s->tx) { + if ((unsigned) s->tx > x) + a = 0; + else if (s->tx < 8) + a = ((line_h1 >> (s->tx - 3)) & 0x004); + else { + o = (x - s->tx) - (x & ~7L); + a = (hp1[o >> 3] >> (7 - (o & 7))) & 1; + a <<= 2; + } + assert(s->tx > 31 || + a == ((line_h1 >> (s->tx - 3)) & 0x004)); + pix = arith_decode(&s->s, (((line_h3 >> 7) & 0x380) | + ((line_h2 >> 11) & 0x078) | a | + (line_h1 & 0x003))); + } else + pix = arith_decode(&s->s, (((line_h3 >> 7) & 0x380) | + ((line_h2 >> 11) & 0x07c) | + (line_h1 & 0x003))); + if (pix < 0) + goto leave; + line_h1 = (line_h1 << 1) | pix; + line_h2 <<= 1; + line_h3 <<= 1; + } while ((++x & 7) && x < s->x0); + } /* if (s->options & JBG_LRLTWO) */ + *hp1++ = line_h1; + hp2++; + hp3++; + } /* while (x < s->x0) */ + *(hp1 - 1) <<= s->bpl * 8 - s->x0; + s->intr = s->line_out(s, s->linebuf + s->p[0] * s->bpl, + s->bpl, s->y, s->file); + x = 0; + s->pseudo = 1; + /* rotate the ring buffer that holds the last three lines */ + s->p[2] = s->p[1]; + s->p[1] = s->p[0]; + if (++(s->p[0]) >= buflines) s->p[0] = 0; + } /* for (i = ...) */ + + leave: + + /* save a few local variables */ + s->line_h1 = line_h1; + s->line_h2 = line_h2; + s->line_h3 = line_h3; + s->x = x; + + return s->s.pscd_ptr - data; +} + +/* + * Helper routine for processing SDNORM/SDRST marker segment + * (which is found in s->buffer[0..1]) + */ +static int finish_sde(struct jbg85_dec_state *s) +{ + /* decode final pixels based on trailing zero bytes */ + s->s.nopadding = 0; + if (decode_pscd(s, s->buffer, 2) != 2 && s->intr) + return 1; + + /* prepare decoder for next SDE */ + arith_decode_init(&s->s, s->buffer[1] == MARKER_SDNORM); + s->s.nopadding = s->options & JBG_VLENGTH; + + s->x = 0; + s->i = 0; + s->pseudo = 1; + s->at_moves = 0; + if (s->buffer[1] == MARKER_SDRST) { + s->tx = 0; + s->lntp = 1; + s->p[0] = 0; + s->p[1] = -1; + s->p[2] = -1; + } + + return 0; +} + +/* + * Provide to the decoder a new BIE fragment of len bytes starting at data. + * + * Unless cnt is NULL, *cnt will contain the number of actually read bytes + * on return. + * + * Normal return values: + * + * JBG_EAGAIN All data bytes provided so far have been processed + * (*cnt == len) but the end of the data stream has + * not yet been recognized. Call the function again + * with additional BIE bytes. + * JBG_EOK The function has reached the end of the BIE and + * the full image has been decoded. + * JBG_EOK_INTR Parsing the BIE has been interrupted as had been + * requested by a non-zero return value of line_out(). + * This function can be called again with the + * rest of the BIE to continue the decoding process. + * The remaining len - *cnt bytes of the previous + * data block will then have to be passed to this + * function again (only if len > *cnt). + * + * Any other return value indicates that the decoding process was + * aborted by a serious problem and the only function you can then + * still call is jbg85_strerror() to find out what to tell the user. + * (Looking at the least significant bits of the return value will + * provide additional information by identifying which test exactly + * has failed.) + */ +int jbg85_dec_in(struct jbg85_dec_state *s, unsigned char *data, size_t len, + size_t *cnt) +{ + int required_length; + unsigned long y; + size_t dummy_cnt; + + if (!cnt) cnt = &dummy_cnt; + *cnt = 0; + + /* read in 20-byte BIH */ + if (s->bie_len < 20) { + while (s->bie_len < 20 && *cnt < len) + s->buffer[s->bie_len++] = data[(*cnt)++]; + if (s->bie_len < 20) + return JBG_EAGAIN; + /* parse header parameters */ + s->x0 = (((long) s->buffer[ 4] << 24) | ((long) s->buffer[ 5] << 16) | + ((long) s->buffer[ 6] << 8) | (long) s->buffer[ 7]); + s->y0 = (((long) s->buffer[ 8] << 24) | ((long) s->buffer[ 9] << 16) | + ((long) s->buffer[10] << 8) | (long) s->buffer[11]); + s->l0 = (((long) s->buffer[12] << 24) | ((long) s->buffer[13] << 16) | + ((long) s->buffer[14] << 8) | (long) s->buffer[15]); + s->bpl = (s->x0 >> 3) + !!(s->x0 & 7); /* bytes per line */ + s->mx = s->buffer[16]; + s->options = s->buffer[19]; + s->s.nopadding = s->options & JBG_VLENGTH; + /* test whether this looks like a valid JBIG header at all */ + if (s->buffer[1] < s->buffer[0]) return JBG_EINVAL | 1; + /* are padding bits zero as required? */ + if (s->buffer[3] != 0) return JBG_EINVAL | 2; /* padding != 0 */ + if ((s->buffer[18] & 0xf0) != 0) return JBG_EINVAL | 3; /* padding != 0 */ + if ((s->buffer[19] & 0x80) != 0) return JBG_EINVAL | 4; /* padding != 0 */ + if (!s->buffer[2]) return JBG_EINVAL | 5; + if (!s->x0) return JBG_EINVAL | 6; + if (!s->y0) return JBG_EINVAL | 7; + if (!s->l0) return JBG_EINVAL | 8; + if (s->mx > 127) + return JBG_EINVAL | 9; + if (s->buffer[ 0] != 0) return JBG_EIMPL | 8; /* parameter outside T.85 */ + if (s->buffer[ 1] != 0) return JBG_EIMPL | 9; /* parameter outside T.85 */ + if (s->buffer[ 2] != 1) return JBG_EIMPL |10; /* parameter outside T.85 */ + if (s->buffer[17] != 0) return JBG_EIMPL |11; /* parameter outside T.85 */ +#if JBG85_STRICT_ORDER_BITS + if (s->buffer[18] != 0) return JBG_EIMPL |12; /* parameter outside T.85 */ +#endif + if (s->options & 0x17) return JBG_EIMPL |13; /* parameter outside T.85 */ + if (s->x0 > (s->linebuf_len / ((s->options & JBG_LRLTWO) ? 2 : 3)) * 8) + return JBG_ENOMEM; /* provided line buffer is too short */ + } + + /* + * BID processing loop + */ + + while (*cnt < len || s->end_of_bie == 1) { + if (s->end_of_bie == 1) s->end_of_bie = 2; + + /* process floating marker segments */ + + /* skip COMMENT contents */ + if (s->comment_skip) { + if (s->comment_skip <= len - *cnt) { + *cnt += s->comment_skip; + s->comment_skip = 0; + } else { + s->comment_skip -= len - *cnt; + *cnt = len; + } + continue; + } + + /* load marker segments into s->buffer for processing */ + if (s->buf_len > 0) { + assert(s->buffer[0] == MARKER_ESC); + /* load enough bytes to determine length of marker segment */ + while (s->buf_len < 2 && *cnt < len) + s->buffer[s->buf_len++] = data[(*cnt)++]; + if (s->buf_len < 2) continue; + switch (s->buffer[1]) { + case MARKER_COMMENT: required_length = 6; break; + case MARKER_ATMOVE: required_length = 8; break; + case MARKER_NEWLEN: required_length = 6; break; + case MARKER_SDNORM: + case MARKER_SDRST: + if ((s->options & JBG_VLENGTH) && !s->end_of_bie) { + /* peek ahead whether a NEWLEN marker segment follows */ + required_length = 2 + 1; + if (s->buf_len == 2 + 1 && s->buffer[2] == MARKER_ESC) + required_length = 2 + 2; /* SDNORM + 2 marker sequence bytes */ + else if (s->buf_len >= 2 + 2 && s->buffer[3] == MARKER_NEWLEN) + required_length = 2 + 6; /* SDNORM + NEWLEN */ + } else { + /* no further NEWLEN allowed or end of BIE reached */ + required_length = 2; + } + break; + case MARKER_ABORT: + s->buf_len = 0; + return JBG_EABORT; + case MARKER_STUFF: + /* forward stuffed 0xff to arithmetic decoder */ + if (decode_pscd(s, s->buffer, 2) == 2 || !s->intr) + s->buf_len = 0; + if (s->intr) + return JBG_EOK_INTR; /* line_out() requested interrupt */ + continue; + default: + return JBG_EMARKER; + } + /* load minimal number of additional bytes required for processing */ + while (s->buf_len < required_length && *cnt < len) + s->buffer[s->buf_len++] = data[(*cnt)++]; + if (s->buf_len < required_length) continue; + /* now the buffer is filled with exactly one marker segment + * (or in the case of SDNORM/SDRST sometimes also with + * two additional peek-ahead bytes) */ + switch (s->buffer[1]) { + case MARKER_COMMENT: + s->comment_skip = + (((long) s->buffer[2] << 24) | ((long) s->buffer[3] << 16) | + ((long) s->buffer[4] << 8) | (long) s->buffer[5]); + break; + case MARKER_ATMOVE: + if (s->at_moves < JBG85_ATMOVES_MAX) { + s->at_line[s->at_moves] = + (((long) s->buffer[2] << 24) | ((long) s->buffer[3] << 16) | + ((long) s->buffer[4] << 8) | (long) s->buffer[5]); + s->at_tx[s->at_moves] = (signed char) s->buffer[6]; + if (s->at_tx[s->at_moves] > (int) s->mx || + (s->at_tx[s->at_moves] < ((s->options & JBG_LRLTWO) ? 5 : 3) && + s->at_tx[s->at_moves] != 0) || + s->buffer[7] != 0) + return JBG_EINVAL | 11; + s->at_moves++; + } else + return JBG_EIMPL | 14; /* more than JBG85_ATMOVES_MAX ATMOVES */ + break; + case MARKER_NEWLEN: + y = (((long) s->buffer[2] << 24) | ((long) s->buffer[3] << 16) | + ((long) s->buffer[4] << 8) | (long) s->buffer[5]); + if (y > s->y0) return JBG_EINVAL | 12; +#ifndef JBG85_TOLERATE_MULTIPLE_NEWLEN + if (!(s->options & JBG_VLENGTH)) return JBG_EINVAL | 13; + s->options &= ~JBG_VLENGTH; +#endif + s->y0 = y; + break; + + case MARKER_SDNORM: + case MARKER_SDRST: + + switch (s->buf_len) { + case 2: + /* process regular SDNORM/SDRST without peek-ahead bytes */ + if (finish_sde(s)) + return JBG_EOK_INTR; /* line_out() requested interrupt */ + /* check whether this was the last SDE */ + if (s->y >= s->y0) return JBG_EOK; + break; + case 2+1: + /* process single peek-ahead byte */ + if (s->buffer[2] == MARKER_ESC) + continue; /* next time we'll have s->buf_len == 2 + 2 */ + else { + /* push back the single peek-ahead PCSD byte */ + assert(*cnt > 0); + (*cnt)--; + s->buf_len--; + if (finish_sde(s)) { + return JBG_EOK_INTR; /* line_out() requested interrupt */ + } + } + break; + case 2+2: + /* process 2-byte peek-ahead marker sequence */ + if (s->buffer[2] == MARKER_ESC && s->buffer[3] == MARKER_NEWLEN) + continue; /* next time we'll have s->buf_len == 2 + 6 */ + else { + if (finish_sde(s)) + return JBG_EOK_INTR; /* line_out() requested interrupt */ + /* recycle the two peek-ahead marker sequence bytes */ + s->buffer[0] = s->buffer[2]; + s->buffer[1] = s->buffer[3]; + s->buf_len = 2; + if (s->intr) + return JBG_EOK_INTR; /* line_out() requested interrupt */ + continue; + } + case 2+6: + /* process peek-ahead NEWLEN marker sequence */ + y = (((long) s->buffer[4] << 24) | ((long) s->buffer[5] << 16) | + ((long) s->buffer[6] << 8) | (long) s->buffer[7]); + if (y > s->y0) return JBG_EINVAL | 12; + if (!(s->options & JBG_VLENGTH)) return JBG_EINVAL | 13; + s->y0 = y; + if (finish_sde(s)) + return JBG_EOK_INTR; /* line_out() requested interrupt */ + s->buf_len = 0; + s->options &= ~JBG_VLENGTH; + /* we leave returning JBG_EOK to the following SDNORM/RST */ + break; + } + + if (s->intr) { + s->buf_len = 0; + return JBG_EOK_INTR; /* line_out() requested interrupt */ + } + + } /* switch (s->buffer[1]) */ + s->buf_len = 0; + + } else if (*cnt < len && data[*cnt] == MARKER_ESC) + s->buffer[s->buf_len++] = data[(*cnt)++]; + + else { + + /* we have found PSCD bytes */ + *cnt += decode_pscd(s, data + *cnt, len - *cnt); + if (s->intr) + return JBG_EOK_INTR; /* line_out() requested interrupt */ + if (*cnt < len && data[*cnt] != MARKER_ESC) { +#ifdef DEBUG + fprintf(stderr, "PSCD was longer than expected, unread bytes " + "%02x %02x %02x %02x ...\n", data[*cnt], data[*cnt+1], + data[*cnt+2], data[*cnt+3]); +#endif + return JBG_EINVAL | 14; /* PSCD was longer than expected */ + } + + } + } /* of BID processing loop 'while (*cnt < len) ...' */ + + return JBG_EAGAIN; +} + + +/* + * After the final BIE byte has been delivered to jbg85_dec_in(), it + * may still return with JBG_EAGAIN in case the VLENGTH=1 option was + * used and no NEWLEN marker section has appeared yet. This is because + * such a BIE is not self-terminating (i.e., there could still be a + * NEWLEN followed by an SDNORM or SDRST lurk after the final stripe, + * which needs to be processed before the final line is output, see + * ITU-T Recommendation T.85, Appendix I). Therefore, after the last + * byte has been delivered, call this routine to signal the end of the + * BIE. This is necessary to allow the routine to finish processing + * BIEs with option VLENGTH=1 that do not actually contain any NEWLEN + * marker section. + */ +int jbg85_dec_end(struct jbg85_dec_state *s) +{ + s->end_of_bie = 1; + return jbg85_dec_in(s, NULL, 0, NULL); +} diff --git a/libjbig/jbig85.h b/libjbig/jbig85.h new file mode 100644 index 0000000..125d563 --- /dev/null +++ b/libjbig/jbig85.h @@ -0,0 +1,173 @@ +/* + * Header file for the T.85 "light" version of the portable + * JBIG image compression library + * + * Copyright 1995-2014 -- Markus Kuhn -- http://www.cl.cam.ac.uk/~mgk25/ + */ + +#ifndef JBG85_H +#define JBG85_H + +#include +#include "jbig_ar.h" + +/* + * JBIG-KIT version number + */ + +#define JBG85_VERSION "2.1" +#define JBG85_VERSION_MAJOR 2 +#define JBG85_VERSION_MINOR 1 + +/* + * JBIG-KIT licence agreement reference code: + * If you use JBIG-KIT under a commercial licence, please replace + * below the letters GPL with the reference code that you received + * with your licence agreement. (This code is typically a letter "A" + * followed by four decimal digits, e.g. "A1234".) + */ + +#define JBG85_LICENCE "GPL" + +/* + * Maximum number of ATMOVEs per stripe that decoder can handle + */ + +#define JBG85_ATMOVES_MAX 1 + +#ifndef JBG_LRLTWO + +/* + * Option and order flags + */ + +#define JBG_LRLTWO 0x40 +#define JBG_VLENGTH 0x20 +#define JBG_TPBON 0x08 + +/* + * Possible error code return values + */ + +#define JBG_EOK (0 << 4) +#define JBG_EOK_INTR (1 << 4) +#define JBG_EAGAIN (2 << 4) +#define JBG_ENOMEM (3 << 4) +#define JBG_EABORT (4 << 4) +#define JBG_EMARKER (5 << 4) +#define JBG_EINVAL (6 << 4) +#define JBG_EIMPL (7 << 4) + +#endif + +/* + * Status of a JBIG encoder + */ + +struct jbg85_enc_state { + unsigned long x0, y0; /* size of the input image */ + unsigned long l0; /* number of lines per stripe */ + int options; /* encoding parameters */ + int newlen; /* 0 = jbg85_enc_newlen() has not yet been called + 1 = jbg85_enc_newlen() has updated y0, NEWLEN pending + 2 = NEWLEN has already been output */ + unsigned mx; /* maximum ATMOVE window size */ + unsigned long y; /* next line number to be encoded */ + unsigned long i; /* next per-stripe line number to be encoded */ + int tx; /* x-offset of adaptive template pixel */ + unsigned long c_all, c[128]; /* adaptive template algorithm variables */ + int new_tx; /* -1 = no ATMOVE pending, otherwise new TX value */ + int ltp_old; /* true if line y-1 was "typical" */ + struct jbg_arenc_state s; /* arithmetic encoder status */ + void (*data_out)(unsigned char *start, size_t len, void *file); + /* data write callback */ + void *file; /* parameter passed to data_out() */ + unsigned char *comment; /* content of comment marker segment to be added + at next opportunity (will be reset to NULL + as soon as comment has been written) */ + unsigned long comment_len; /* length of data pointed to by comment */ +}; + + +/* + * Status of a JBIG decoder + */ + +struct jbg85_dec_state { + /* data from BIH */ + unsigned long x0, y0; /* size of the full image */ + unsigned long l0; /* number of lines per stripe */ + int options; /* encoding parameters */ + int mx; /* maximum ATMOVE window size */ + /* image data */ + int p[3]; /* curr. line starts at linebuf+bpl*p[0], prev. line starts + * at linebuf+bpl*p[1], its predecessor at linebuf+bpl*p[2] */ + unsigned char *linebuf; /* buffer region provided by caller */ + size_t linebuf_len; + size_t bpl; /* bytes per line */ + /* status information */ + int tx; /* x-offset of AT pixel */ + struct jbg_ardec_state s; /* arithmetic decoder status */ + unsigned long bie_len; /* number of bytes read so far */ + unsigned char buffer[20]; /* used to store BIH or marker segments fragm. */ + int buf_len; /* number of bytes in buffer */ + unsigned long comment_skip; /* remaining bytes of a COMMENT segment */ + unsigned long x; /* x position of next pixel */ + unsigned long stripe; /* current stripe */ + unsigned long y; /* line in image (first line is 0) */ + unsigned long i; /* line in current stripe (first line of stripe is 0) */ + int at_moves; /* number of AT moves in the current stripe */ + unsigned long at_line[JBG85_ATMOVES_MAX]; /* lines at which an * + * AT move will happen */ + int at_tx[JBG85_ATMOVES_MAX]; /* ATMOVE x-offsets in current stripe */ + unsigned long line_h1, line_h2, line_h3; /* variables of decode_pscd */ + int pseudo; /* flag for TPBON/TPDON: next pixel is pseudo pixel */ + int lntp; /* flag for TP: line is not typical */ + int (*line_out)(const struct jbg85_dec_state *s, + unsigned char *start, size_t len, + unsigned long y, void *file); + /* data write callback */ + void *file; /* parameter passed to data_out() */ + int intr; /* flag that line_out requested interrupt */ + int end_of_bie; /* flag that the end of the BIE has been signalled */ +}; + + +/* function prototypes */ + +void jbg85_enc_init(struct jbg85_enc_state *s, + unsigned long x0, unsigned long y0, + void (*data_out)(unsigned char *start, size_t len, + void *file), + void *file); +void jbg85_enc_options(struct jbg85_enc_state *s, int options, + unsigned long l0, int mx); +void jbg85_enc_lineout(struct jbg85_enc_state *s, unsigned char *line, + unsigned char *prevline, unsigned char *prevprevline); +void jbg85_enc_newlen(struct jbg85_enc_state *s, unsigned long y0); +void jbg85_enc_abort(struct jbg85_enc_state *s); + +void jbg85_dec_init(struct jbg85_dec_state *s, + unsigned char *buf, size_t buflen, + int (*line_out)(const struct jbg85_dec_state *s, + unsigned char *start, size_t len, + unsigned long y, void *file), + void *file); +int jbg85_dec_in(struct jbg85_dec_state *s, unsigned char *data, size_t len, + size_t *cnt); +int jbg85_dec_end(struct jbg85_dec_state *s); +const char *jbg85_strerror(int errnum); + +/* some macros for examining decoder state */ + +#define jbg85_dec_finished(s) ((s)->bie_len == 20 && (s)->y >= (s)->y0) +/* enquire about image size */ +#define jbg85_dec_getwidth(s) ((s)->x0) +#define jbg85_dec_getheight(s) ((s)->y0) +/* enquire about validity of image-size results */ +#define jbg85_dec_validwidth(s) ((s)->bie_len == 20) +#define jbg85_dec_finalheight(s) ((s)->bie_len == 20 && \ + ((((s)->options & JBG_VLENGHT) == 0) || \ + ((s)->y >= (s)->y0))) + +#endif /* JBG85_H */ diff --git a/libjbig/jbig85.txt b/libjbig/jbig85.txt new file mode 100644 index 0000000..fd1eb38 --- /dev/null +++ b/libjbig/jbig85.txt @@ -0,0 +1,617 @@ + +Using the T.85 "light" version of the JBIG-KIT library +------------------------------------------------------ + +Markus Kuhn -- 2008-08-30 + + +This text explains how to use the functions provided by the JBIG-KIT +portable image compression library jbig85.c in your application +software. + + +1 Distinguishing features + +The jbig85.c library implements only the "single-progression +sequential coding" subset of the JBIG1 standard, which is defined in +ITU-T Recommendation T.85 , also +known as the "facsimile application profile". This means that the +JBIG1 data streams that the jbig85.c library can process can have + + - no progressive encoding, i.e. the image is always encoded in a + single resolution layer (and not as a sequence of layers of a + resolution pyramid); + + - only a single plane, i.e. the raw data are black/white images with + only one bit per pixel information. + +The jbig85.c library is not suitable for continuous-tone (colour or +grey-scale) image applications, including the fax method described in +ITU-R Recommendation T.43. For these applications, use the full jbig.c +library instead. + +The T.85 restrictions are sufficient for black/white fax transmission +and several other common bi-level image applications (printer drivers, +document archiving, etc.). They simplify the design of the encoder and +decoder and allow the jbig85.c library to provide several advantages +over the full-featured jbig.c: + + - Only the last three lines of the uncompressed image need to be + kept in RAM at any time. + + - All memory allocation is done outside the jbig85.c library, which + performs no calls to malloc(), free(), etc. + + - The implementation can handle images whose height (number of pixel + rows) is not yet known before the last line has been encoded or + decoded. + + - All usage modes of the NEWLEN marker segment are supported, + including a NEWLEN occurring after the final stripe, as required by + ITU-T Recommendation T.85, using only a single pass over the data. + + - The code is smaller and there is no need to store tables related + to the resolution-reduction algorithms. + +This makes the jbig85.c library particularly suited for very small +embedded applications, e.g. low-end fax machines, along with the fact +that the library is non-recursive and requires only a very small stack +(typically just a bit over 100 bytes on a 32-bit system). The jbig85.c +library may also be a good choice where very large black/white images +are processed. + +The jbig85.c and jbig.c libraries both can be linked simultaneously +with the same application if you #include jbig85.h after jbig.h into +your source code. + + +2 Introduction to JBIG (T.85 subset) + +We start with a short introduction to the T.85 subset of JBIG1. More +detailed information is provided in the "Introduction and overview" +section of the JBIG1 standard. Information on how to obtain a copy of +the standard is available from +or . + +The JBIG1 standard allows the encoder to divide an image into several +horizontal stripes. All stripes have equal size, except perhaps the +final one. + +The compressed data stream specified by the JBIG standard is called a +bi-level image entity (BIE). A BIE consists of a 20-byte header, +followed by a sequence of stripe data entities (SDE). Each SDE encodes +the content of one single stripe in one plane of one resolution layer. +Between the SDEs, other information blocks (called floating marker +segments) can also be present. They are used to change certain +parameters of the algorithm in the middle of an image or contain +additional application specific information. A BIE looks like this: + + + +------------------------------------------------+ + | | + | 20-byte header (specifying image size, stripe | + | size, and options) | + | | + +------------------------------------------------+ + | | + | optional floating marker segments | + | | + +------------------------------------------------+ + | | + | stripe data entity | + | | + +------------------------------------------------+ + | | + | optional floating marker segments | + | | + +------------------------------------------------+ + | | + | stripe data entity | + | | + +------------------------------------------------+ + ... + +------------------------------------------------+ + | | + | stripe data entity | + | | + +------------------------------------------------+ + +It is possible to use the raw BIE data stream as specified by the JBIG +standard directly as the format of a file used for storing images. +This is what the pbmtojbg, jbgtopbm, pbmtojbg85, and jbgtopbm85 +conversion tools do that are provided in this package as demonstration +applications. However, as the BIE format has been designed for a large +number of very different applications, and to allow efficient direct +processing by special JBIG hardware chip implementations, the BIE +header contains only the minimum amount of information absolutely +required by the decompression algorithm. Many features expected from a +good file format are missing in the BIE data stream: + + - no "magic code" in the first few bytes to allow identification + of the file format on a typeless file system and to allow + automatic distinction from other compression algorithms + + - no standardized way to encode additional information such as a + textual description, the physical size and resolution of the + document, etc. + + - a checksum to ensure image integrity + + - encryption and signature mechanisms + + - many things more + +Raw BIE data streams alone may therefore not be a suitable format for +document archiving and exchange. A standard format for this purpose +would typically combine a BIE representing the image data with an +additional header providing auxiliary information into one file. +Existing established multi-purpose file formats with a rich set of +auxiliary information attributes like TIFF could be extended easily to +also hold JBIG compressed data. + +On the other hand, in e.g. database applications, a BIE might be +stored directly in a binary variable-length field. Auxiliary +information would then be stored in other fields of the same record, +to simplify search operations. + + +2 Compressing an image + +2.1 Format of the source image + +To be processed by the jbig85.c encoder, the image has to be present +in memory a bitmap. Each byte of a bitmap contains eight pixels, where +the most significant bit represents the leftmost of these. Each line +of a bitmap has to be stored in an integral number of bytes. If the +image width is not an integral multiple of eight, then the final byte +has to be padded with zero bits. + +For example the 23x5 pixels large single plane image: + + .XXXXX..XXX...X...XXX.. + .....X..X..X..X..X..... + .....X..XXX...X..X.XXX. + .X...X..X..X..X..X...X. + ..XXX...XXX...X...XXX.. + +is represented by the 15 bytes + + 01111100 11100010 00111000 + 00000100 10010010 01000000 + 00000100 11100010 01011100 + 01000100 10010010 01000100 + 00111000 11100010 00111000 + +or in hexadecimal notation + + 7c e2 38 04 92 40 04 e2 5c 44 92 44 38 e2 38 + +This is the format used in binary PBM files and it can also be handled +directly by the Xlib library of the X Window System. + +The standard recommends that a 0 pixel represents the background and a +1 pixel represents the foreground colour of an image, in other words, 0 +is white and 1 is black for scanned paper documents. + + +2.2 A simple compression application + +In order to use the library in your application, just link libjbig85.a +to your executable (on Unix systems just add -ljbig85 and -L. to the +command line options of your compiler, on other systems you will have +to write a new Makefile anyway), copy the file jbig85.h into your +source directory and put the line + + #include "jbig85.h" + +into your source code. + +The library interface follows object-oriented programming principles. +You have to declare a variable (object) + + struct jbg85_enc_state s; + +which contains the current status of an encoder. Then you initialize +the encoder by calling + + void jbg85_enc_init(struct jbg85_enc_state *s, + unsigned long x, unsigned long y, + void (*data_out)(unsigned char *start, size_t len, + void *file), + void *file); + +The parameters have the following meaning: + + s A pointer to the jbg85_enc_state structure that you want + to initialize. + + x The width of your image in pixels. + + y The height of your image in pixels (lines). This can be + a larger value than the actual height of the image, or + even 2^32-1 (or equally -1), if the height of the + image is not yet known. In that case, leave the + JBG_VLENGTH option set (see below) and call + jbg85_enc_newlen() as soon as the actual image height + is known. + + data_out This is a call-back function that the encoder will + call during the compression process in order to + deliver the BIE data to your application. The + parameters of the function data_out are a pointer + start to the new block of data being delivered, as + well as the number len of delivered bytes. The pointer + file is transparently delivered to data_out, as + specified in jbg85_enc_init(). Typically, data_out + will write the BIE portion to a file, send it to a + network connection, or append it to some memory + buffer. + + file A pointer parameter that is passed on to data_out() + and can be used, for instance, to allow data_out() to + distinguish by which compression task it has been + called in multi-threaded applications. + +The compression can then be started by calling the function + + void jbg85_enc_lineout(struct jbg85_enc_state *s, unsigned char *line, + unsigned char *prevline, unsigned char *prevprevline); + +successively for each line of the image, top to bottom. The parameters +are: + + line A pointer to the first byte of the line to be encoded. + + prevline A pointer to the data that the line parameter pointed + to in the previous call. The value will be ignored + if this is the first call. + + prevprevline A pointer to the data that the prevline parameter pointed + to in the previous call. The value will be ignored + if this is the first or second call. + +After jbg85_enc_lineout() has been called for all lines of the image, +the complete BIE will have been delivered via several callbacks to +data_out(). These BIE bytes are delivered as soon as possible, as the +encoder cannot buffer more than a few bytes internally. + +A minimal example application, which sends the BIE of the above bitmap +to stdout, looks like this: + +--------------------------------------------------------------------------- +/* A sample JBIG T.85 encoding application */ + +#include +#include "jbig85.h" + +void output_bie(unsigned char *start, size_t len, void *file) +{ + fwrite(start, 1, len, (FILE *) file); + + return; +} + +int main() +{ + unsigned char bitmap[15] = { + /* 23 x 5 pixels, "JBIG" */ + 0x7c, 0xe2, 0x38, 0x04, 0x92, 0x40, 0x04, 0xe2, + 0x5c, 0x44, 0x92, 0x44, 0x38, 0xe2, 0x38 + }; + struct jbg85_enc_state se; + int i; + + jbg85_enc_init(&se, 23, 5, output_bie, stdout); /* initialize encoder */ + jbg85_enc_options(&se, JBG_TPBON, 0, -1); /* clear JBG_VLENGTH option */ + for (i = 0; i < 5; i++) { + /* encode line */ + jbg85_enc_lineout(&se, bitmap+i*3, bitmap+(i-1)*3, bitmap+(i-2)*3); + } + + return 0; +} +--------------------------------------------------------------------------- + +This software produces a 37 byte long BIE. (JBIG is not very good at +compressing extremely small images like in this example, because the +arithmetic encoder requires some startup data in order to generate +reasonable statistics which influence the compression process and +because there is some header overhead.) + + +2.3 More about compression + +If jbg85_enc_lineout() is called directly after jbg85_enc_init(), the +following default values are used for various compression parameters: + + - The number of lines per stripe (l0) is set to 128, which is the + T.85 BASIC setting. + + - The typical-prediction (TPBON) and variable-length (VLENGTH) options + are activated, but the two-line template (LRLTWO) option is not. + + - The maximal horizontal offset of the adaptive template pixel is 127 + (mx = 127, my = 0). + +In order to change any of these default parameters, an additional +function has to be called between jbg85_enc_init() and the first +jbg85_enc_lineout(): + + void jbg85_enc_options(struct jbg85_enc_state *s, int options, + unsigned long l0, int mx) + +The options value can contain the following bits, which activate some +of the optional algorithms defined by JBIG: + + JBG_LRLTWO This option bit changes the JBIG algorithm such that the + context in which the probability of a pixel is + estimated includes only the previous line (two-line + template), rather than the previous two lines + (three-line template). This option is off by default + and the author cannot think of a good reason to set it. + [Some people in the JBIG committee seem to have + argued that using a two-line template will make + software implementations a little bit faster, while + others have argued that using only two lines will + decrease compression efficiency by around 5%. As you + might expect from a committee, now both alternatives + are allowed (and add to the implementation and testing + complexity of every decoder).] + + JBG_TPBON This bit activates the "typical prediction" algorithm. It + is set by default. Typical prediction means that JBIG + prefixes each line to be encoded with a "pseudopixel" + that indicates if the line is identical to the + previous line, and skips encoding the line if it is. + This helps to encode empty parts of a page very + efficiently in just a few bytes, therefore this + option should be left on. (The only reason the author + could think of for ever deactivating this option is + if you know in advance that there will never be two + identical lines follow each other in the image to be + encoded, in which case deactivating this option might + provide a tiny performance improvement.) + + JBG_VLENGTH This bit indicates that the image height y provided + to jbg85_enc_init() was only an estimate and may + be lowered sometimes during the encoding process + using a call to jbg85_enc_newlen(). This feature + is intended for fax machines that start transmitting + a page while still scanning it and without knowing + how long the page is going to be. + +Value -1 for options keeps the current setting, the default is +JBG_TPBON | JBG_VLENGTH. + +The other parameters are: + + l0 Sets the number of lines per stripe (valid range: + 1 to 2^32-1, default 128, value 0 keeps the current + setting). + + mx Changes the maximal offset allowed for the adaptive + template pixel (valid range: 0 to 127, default 127, + value -1 keeps the current setting). + +If the JBG_VLENGTH option was set, then you can call at any time the +function + + void jbg85_enc_newlen(struct jbg85_enc_state *s, unsigned long newlen) + +in order to announce the actual height of the image. You can call this +function only once per image, and the provided new height value newlen +must not be larger than the estimate y originally provided. It is good +practice to call jbg85_enc_newlen() as soon as the height of the image +is known. However, it is even possible to call it after the last line +has already been encoded using jbg85_enc_lineout(). The latter case +will result in a somewhat odd BIE, where an additional empty stripe +has to be appended just to announce the new length. This is not pretty +and was not described in great detail in the original JBIG1 standard, +but decoders are required by ITU-T T.85 to understand even this +extremely late announcement of the end of the image. + +If the image height y initially given to jbg85_enc_init() is already +the correct final value and you will therefore never call +jbg85_enc_newlen(), then it is good practice to clear the JBG_VLENGTH +option bit, which is set by default, e.g. by calling + + jbg85_enc_options(&s, JBG_TPBON, 0, -1); + +between jbg85_enc_init() and jbg85_enc_lineout(). + +The JBIG standard also has a provision for aborting a BIE with a +special abort marker segment, and calling + + void jbg85_enc_abort(struct jbg85_enc_state *s); + +does that. This is probably only needed if there is no other way +(e.g., end-of-file) of telling the decoder that no further data bytes +will be coming. + + +3 Decompressing an image + +Like with the compression functions, if you want to use the jbig85.c +library, you have to put the line + + #include "jbig85.h" + +into your source code and link your executable with libjbig85.a. + +The state of a JBIG decoder is stored completely in a struct and you +will have to define a variable like + + struct jbg85_dec_state s; + +which is initialized by a call to + + void jbg85_dec_init(struct jbg85_dec_state *s, + unsigned char *buf, size_t buflen, + int (*line_out)(const struct jbg85_dec_state *s, + unsigned char *start, size_t len, + unsigned long y, void *file), + void *file); + +The parameters are: + + buf A memory buffer that is long enough to store up to + three lines of the image. This buffer will be used + by the decoder to temporarily store decoded lines. + If the decoded image uses the LRLTWO option, the buffer + has to be only sufficient for two uncompressed + image lines. + + buflen The length in bytes of the buffer area to which buf + points. Knowing this value prevents accidental buffer + overflows and allows the decoder to abort with + JBG_ENOMEM if the provided buffer was too small, once + it knows the width of the image to be decoded from + parsing its 20-byte header. If xmax is the expected + maximum width of the image in pixels, then buflen + should be at least ((xmax >> 3) + !!(xmax & 7)) * 3 + bytes. [If only BIEs with option LRLTWO set will be + received, then ((xmax >> 3) + !!(xmax & 7)) * 2 + bytes will be sufficient.] + + line_out This call-back function will be used whenever the decoder + has completed another line. The start parameter will + point to the location in buf where the len bytes of + the just decoded line reside. The line_out() function + has to read (and copy or output) this line, but it is + not allowed to modify it in-place, as the decoder will + also need to access it while decoding the following + two lines. The parameter y is just the line number + (starting from 0) and file is the jbg85_dec_init() + parameter of the same name passed on. The normal + return value of line_out is zero; a non-zero value + can be returned to request an interrupt of the decoding + process (see discussion of JBG_EOK_INTR below). + + file A pointer parameter that is passed on to line_out() + and can be used, for instance, to allow line_out() to + distinguish by which compression task it has been + called in multi-threaded applications. + +After this, you can directly start to pass data from the BIE to the decoder +by calling the function + + int jbg85_dec_in(struct jbg85_dec_state *s, unsigned char *data, size_t len, + size_t *cnt); + +The pointer data points to the first byte of a data block with length +len, which contains bytes from a BIE. It is not necessary to pass a +whole BIE at once to jbg85_dec_in(), it can arrive fragmented in any +way by calling jbg85_dec_in() several times. Only a single BIE can be +delivered via jbg85_dec_in() calls and the decoder has to be +reinitialized with jbg85_dec_init() before it is ready to accept +another BIE. + +If pointer cnt is not NULL, then the number of bytes actually read +from the data block will be stored there. In case the decoder did not +recognize the end of the BIE in the data block, then the value +JBG_EAGAIN will be returned and *cnt equals len. + +Once the end of a BIE has been reached, the return value of +jbg85_dec_in() will be JBG_EOK. + +The decoder can recognize the end of a BIE only if either the VLENGTH +option is not set, or if there has been a NEWLEN marker segment before +the start of the last stripe. Otherwise, the decoder cannot know +whether there is or is not a NEWLEN marker segment following the last +stripe. For this reason, jbg85_dec_in() can return JBG_EAGAIN even +though you have already given it the last byte of the BIE. In this +case, call + + int jbg85_dec_end(struct jbg85_dec_state *s); + +to explicitely signal to the decoder that it has already received all +bytes of the BIE. This function will then output any remaining lines +and return JBG_EOK if no problem has occurred. + +The macros + + unsigned long jbg85_dec_getwidth(struct jbg85_dec_state *s); + unsigned long jbg85_dec_getheight(struct jbg85_dec_state *s); + +can be used to query the dimensions of the image. The width will be +known already after the first 20 bytes of the BIE have been provided, +and also during the first callback to line_out(). But the height might +not have reached its final value before jbg85_dec_in() has returned +JBG_EOK. The additional boolean macros + + int jbg85_dec_validwidth(struct jbg85_dec_state *s); + int jbg85_dec_finalheight(struct jbg85_dec_state *s); + int jbg85_dec_finished(struct jbg85_dec_state *s); + +tell, whether the width and final height are already known, and +whether the decoder has finished outputting all lines. + +If one of the callbacks to line_out() provides a non-zero return +value, then the decoder will interrupt the decoding process and +jbg85_dec_in() or jbg85_dec_end() will return JBG_EOK_INTR. This +feature might be useful to stop the decoding process temporarily, e.g. +to load a new sheet of paper, where performing this task is +inconvenient to complete inside line_out(). It is then possible to +continue calling jbg85_dec_in() with the remaining data (or +jbg85_dec_end() if there isn't any left) in order to decode the +remaining lines of the BIE. After jbg85_dec_in() returned +JBG_EOK_INTR, *cnt is probably not equal to len and the remainder of +the data block which has not yet been processed by the decoder has to +be delivered to jbg85_dec_in() again. Any line that has already been +delivered to line_out() will not be delivered again. + +If any other return value than JBG_EOK, JBG_EOK_INTR or JBG_EAGAIN has +been returned by jbg85_dec_in() or jbg85_dec_end(), then an error has +occurred and the decoding process has been aborted. The function + + const char *jbg85_strerror(int errnum); + +returns a pointer to a short single-line test message that explains +the return value of jbg85_dec_in() or jbg85_dec_end(). This message +can be used in order to provide the user a brief informative message +about what when wrong while decompressing a JBIG image. The po/ +subdirectory contains *.po files that translate the English ASCII +strings returned by jbg85_strerror() into other languages (e.g., for +use with GNU gettext). The four least-significant bits of the return +value of jbg85_dec_in() or jbg85_dec_end() may contain additional +detailed technical information about the exact test that spotted the +error condition (see source code for details), i.e. more than the text +message returned by jbg85_strerror() reveals. Therefore it may be +useful to display the return value itself as a hexadecimal number, in +addition to the string returned by jbg85_strerror(). + + +4 Additional notes + +The following remarks will not affect the normal user of the library +but might be of interest to some users who have to deal with exotic +cases, in particular dealing with broken non-JBIG-KIT encoders out +there: + + - There has been one report about malformed BIEs produced by another + JBIG implementation that violates the standard by containing + several NEWLEN marker segments in the same BIE. The jbig85.c + decoder will normally abort with JBG_EINVALID when it encounters + such an illegal BIE. The compile-time option + JBG85_TOLERATE_MULTIPLE_NEWLEN can be used to make the decoder + more tolerant to this type of syntax error. + + - Even though the T.85 standard prescribes all-zero values for the + order bits HITOLO, SEQ, ILEAVE, SMID, the jbig85.c decoder will + not complain about any other values of these bits, as they do not + affect the decoding process when there is only a single plane and + resolution layer (the only case supported by this decoder). The + compile-time option JBG85_STRICT_ORDER_BITS will make the decoder + less tolerant and abort with JBG_EIMPL if the received order bits + do not comply with the T.85 "single-progression sequential coding" + requirements. + + - The T.85 standard allows only a single ATMOVE marker segment per + SDE, and the jbig85.c decoder enforces this limit by default. This + limit can be increased by setting JBG85_ATMOVES_MAX in jbig85.h to + the desired value. The encoder will never output more than a + single ATMOVE marker segment per stripe. + +*** Happy decompressing *** + +[end] diff --git a/libjbig/jbig_ar.c b/libjbig/jbig_ar.c new file mode 100644 index 0000000..d23a317 --- /dev/null +++ b/libjbig/jbig_ar.c @@ -0,0 +1,417 @@ +/* + * Arithmetic encoder and decoder of the portable JBIG + * compression library + * + * Markus Kuhn -- http://www.cl.cam.ac.uk/~mgk25/jbigkit/ + * + * This module implements a portable standard C arithmetic encoder + * and decoder used by the JBIG lossless bi-level image compression + * algorithm as specified in International Standard ISO 11544:1993 + * and ITU-T Recommendation T.82. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * If you want to use this program under different license conditions, + * then contact the author for an arrangement. + */ + +#include +#include "jbig_ar.h" + +/* + * Probability estimation tables for the arithmetic encoder/decoder + * given by ITU T.82 Table 24. + */ + +static short lsztab[113] = { + 0x5a1d, 0x2586, 0x1114, 0x080b, 0x03d8, 0x01da, 0x00e5, 0x006f, + 0x0036, 0x001a, 0x000d, 0x0006, 0x0003, 0x0001, 0x5a7f, 0x3f25, + 0x2cf2, 0x207c, 0x17b9, 0x1182, 0x0cef, 0x09a1, 0x072f, 0x055c, + 0x0406, 0x0303, 0x0240, 0x01b1, 0x0144, 0x00f5, 0x00b7, 0x008a, + 0x0068, 0x004e, 0x003b, 0x002c, 0x5ae1, 0x484c, 0x3a0d, 0x2ef1, + 0x261f, 0x1f33, 0x19a8, 0x1518, 0x1177, 0x0e74, 0x0bfb, 0x09f8, + 0x0861, 0x0706, 0x05cd, 0x04de, 0x040f, 0x0363, 0x02d4, 0x025c, + 0x01f8, 0x01a4, 0x0160, 0x0125, 0x00f6, 0x00cb, 0x00ab, 0x008f, + 0x5b12, 0x4d04, 0x412c, 0x37d8, 0x2fe8, 0x293c, 0x2379, 0x1edf, + 0x1aa9, 0x174e, 0x1424, 0x119c, 0x0f6b, 0x0d51, 0x0bb6, 0x0a40, + 0x5832, 0x4d1c, 0x438e, 0x3bdd, 0x34ee, 0x2eae, 0x299a, 0x2516, + 0x5570, 0x4ca9, 0x44d9, 0x3e22, 0x3824, 0x32b4, 0x2e17, 0x56a8, + 0x4f46, 0x47e5, 0x41cf, 0x3c3d, 0x375e, 0x5231, 0x4c0f, 0x4639, + 0x415e, 0x5627, 0x50e7, 0x4b85, 0x5597, 0x504f, 0x5a10, 0x5522, + 0x59eb +}; + +static unsigned char nmpstab[113] = { + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 13, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 9, 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, 32, + 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 48, + 81, 82, 83, 84, 85, 86, 87, 71, + 89, 90, 91, 92, 93, 94, 86, 96, + 97, 98, 99, 100, 93, 102, 103, 104, + 99, 106, 107, 103, 109, 107, 111, 109, + 111 +}; + +/* + * least significant 7 bits (mask 0x7f) of nlpstab[] contain NLPS value, + * most significant bit (mask 0x80) contains SWTCH bit + */ +static unsigned char nlpstab[113] = { + 129, 14, 16, 18, 20, 23, 25, 28, + 30, 33, 35, 9, 10, 12, 143, 36, + 38, 39, 40, 42, 43, 45, 46, 48, + 49, 51, 52, 54, 56, 57, 59, 60, + 62, 63, 32, 33, 165, 64, 65, 67, + 68, 69, 70, 72, 73, 74, 75, 77, + 78, 79, 48, 50, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 61, 61, + 193, 80, 81, 82, 83, 84, 86, 87, + 87, 72, 72, 74, 74, 75, 77, 77, + 208, 88, 89, 90, 91, 92, 93, 86, + 216, 95, 96, 97, 99, 99, 93, 223, + 101, 102, 103, 104, 99, 105, 106, 107, + 103, 233, 108, 109, 110, 111, 238, 112, + 240 +}; + +/* + * The next functions implement the arithmedic encoder and decoder + * required for JBIG. The same algorithm is also used in the arithmetic + * variant of JPEG. + */ + +/* marker codes */ +#define MARKER_STUFF 0x00 +#define MARKER_ESC 0xff + +void arith_encode_init(struct jbg_arenc_state *s, int reuse_st) +{ + int i; + + if (!reuse_st) + for (i = 0; i < 4096; s->st[i++] = 0) ; + s->c = 0; + s->a = 0x10000L; + s->sc = 0; + s->ct = 11; + s->buffer = -1; /* empty */ + + return; +} + + +void arith_encode_flush(struct jbg_arenc_state *s) +{ + unsigned long temp; + + /* find the s->c in the coding interval with the largest + * number of trailing zero bits */ + if ((temp = (s->a - 1 + s->c) & 0xffff0000L) < s->c) + s->c = temp + 0x8000; + else + s->c = temp; + /* send remaining bytes to output */ + s->c <<= s->ct; + if (s->c & 0xf8000000L) { + /* one final overflow has to be handled */ + if (s->buffer >= 0) { + s->byte_out(s->buffer + 1, s->file); + if (s->buffer + 1 == MARKER_ESC) + s->byte_out(MARKER_STUFF, s->file); + } + /* output 0x00 bytes only when more non-0x00 will follow */ + if (s->c & 0x7fff800L) + for (; s->sc; --s->sc) + s->byte_out(0x00, s->file); + } else { + if (s->buffer >= 0) + s->byte_out(s->buffer, s->file); + /* T.82 figure 30 says buffer+1 for the above line! Typo? */ + for (; s->sc; --s->sc) { + s->byte_out(0xff, s->file); + s->byte_out(MARKER_STUFF, s->file); + } + } + /* output final bytes only if they are not 0x00 */ + if (s->c & 0x7fff800L) { + s->byte_out((s->c >> 19) & 0xff, s->file); + if (((s->c >> 19) & 0xff) == MARKER_ESC) + s->byte_out(MARKER_STUFF, s->file); + if (s->c & 0x7f800L) { + s->byte_out((s->c >> 11) & 0xff, s->file); + if (((s->c >> 11) & 0xff) == MARKER_ESC) + s->byte_out(MARKER_STUFF, s->file); + } + } + + return; +} + + +void arith_encode(struct jbg_arenc_state *s, int cx, int pix) +{ + register unsigned lsz, ss; + register unsigned char *st; + long temp; + + assert(cx >= 0 && cx < 4096); + st = s->st + cx; + ss = *st & 0x7f; + assert(ss < 113); + lsz = lsztab[ss]; + +#if 0 + fprintf(stderr, "pix = %d, cx = %d, mps = %d, st = %3d, lsz = 0x%04x, " + "a = 0x%05lx, c = 0x%08lx, ct = %2d, buf = 0x%02x\n", + pix, cx, !!(s->st[cx] & 0x80), ss, lsz, s->a, s->c, s->ct, + s->buffer); +#endif + + if (((pix << 7) ^ s->st[cx]) & 0x80) { + /* encode the less probable symbol */ + if ((s->a -= lsz) >= lsz) { + /* If the interval size (lsz) for the less probable symbol (LPS) + * is larger than the interval size for the MPS, then exchange + * the two symbols for coding efficiency, otherwise code the LPS + * as usual: */ + s->c += s->a; + s->a = lsz; + } + /* Check whether MPS/LPS exchange is necessary + * and chose next probability estimator status */ + *st &= 0x80; + *st ^= nlpstab[ss]; + } else { + /* encode the more probable symbol */ + if ((s->a -= lsz) & 0xffff8000L) + return; /* A >= 0x8000 -> ready, no renormalization required */ + if (s->a < lsz) { + /* If the interval size (lsz) for the less probable symbol (LPS) + * is larger than the interval size for the MPS, then exchange + * the two symbols for coding efficiency: */ + s->c += s->a; + s->a = lsz; + } + /* chose next probability estimator status */ + *st &= 0x80; + *st |= nmpstab[ss]; + } + + /* renormalization of coding interval */ + do { + s->a <<= 1; + s->c <<= 1; + --s->ct; + if (s->ct == 0) { + /* another byte is ready for output */ + temp = s->c >> 19; + if (temp & 0xffffff00L) { + /* handle overflow over all buffered 0xff bytes */ + if (s->buffer >= 0) { + ++s->buffer; + s->byte_out(s->buffer, s->file); + if (s->buffer == MARKER_ESC) + s->byte_out(MARKER_STUFF, s->file); + } + for (; s->sc; --s->sc) + s->byte_out(0x00, s->file); + s->buffer = temp & 0xff; /* new output byte, might overflow later */ + assert(s->buffer != 0xff); + /* can s->buffer really never become 0xff here? */ + } else if (temp == 0xff) { + /* buffer 0xff byte (which might overflow later) */ + ++s->sc; + } else { + /* output all buffered 0xff bytes, they will not overflow any more */ + if (s->buffer >= 0) + s->byte_out(s->buffer, s->file); + for (; s->sc; --s->sc) { + s->byte_out(0xff, s->file); + s->byte_out(MARKER_STUFF, s->file); + } + s->buffer = temp; /* buffer new output byte (can still overflow) */ + } + s->c &= 0x7ffffL; + s->ct = 8; + } + } while (s->a < 0x8000); + + return; +} + + +void arith_decode_init(struct jbg_ardec_state *s, int reuse_st) +{ + int i; + + if (!reuse_st) + for (i = 0; i < 4096; s->st[i++] = 0) ; + s->c = 0; + s->a = 1; + s->ct = 0; + s->startup = 1; + s->nopadding = 0; + return; +} + +/* + * Decode and return one symbol from the provided PSCD byte stream + * that starts in s->pscd_ptr and ends in the byte before s->pscd_end. + * The context cx is a 12-bit integer in the range 0..4095. This + * function will advance s->pscd_ptr each time it has consumed all + * information from that PSCD byte. + * + * If a symbol has been decoded successfully, the return value will be + * 0 or 1 (depending on the symbol). + * + * If the decoder was not able to decode a symbol from the provided + * PSCD, then the return value will be -1, and two cases can be + * distinguished: + * + * s->pscd_ptr == s->pscd_end: + * + * The decoder has used up all information in the provided PSCD + * bytes. Further PSCD bytes have to be provided (via new values of + * s->pscd_ptr and/or s->pscd_end) before another symbol can be + * decoded. + * + * s->pscd_ptr == s->pscd_end - 1: + * + * The decoder has used up all provided PSCD bytes except for the + * very last byte, because that has the value 0xff. The decoder can + * at this point not yet tell whether this 0xff belongs to a + * MARKER_STUFF sequence or marks the end of the PSCD. Further PSCD + * bytes have to be provided (via new values of s->pscd_ptr and/or + * s->pscd_end), including the not yet processed 0xff byte, before + * another symbol can be decoded successfully. + * + * If s->nopadding != 0, the decoder will return -2 when it reaches + * the first two bytes of the marker segment that follows (and + * terminates) the PSCD, but before decoding the first symbol that + * depends on a bit in the input data that could have been the result + * of zero padding, and might, therefore, never have been encoded. + * This gives the caller the opportunity to lookahead early enough + * beyond a terminating SDNORM/SDRST for a trailing NEWLEN (as + * required by T.85) before decoding remaining symbols. Call the + * decoder again afterwards as often as necessary (leaving s->pscd_ptr + * pointing to the start of the marker segment) to retrieve any + * required remaining symbols that might depend on padding. + * + * [Note that each PSCD can be decoded into an infinitely long + * sequence of symbols, because the encoder might have truncated away + * an arbitrarily long sequence of trailing 0x00 bytes, which the + * decoder will append automatically as needed when it reaches the end + * of the PSCD. Therefore, the decoder cannot report any end of the + * symbol sequence and other means (external to the PSCD and + * arithmetic decoding process) are needed to determine that.] + */ + +int arith_decode(struct jbg_ardec_state *s, int cx) +{ + register unsigned lsz, ss; + register unsigned char *st; + int pix; + + /* renormalization */ + while (s->a < 0x8000 || s->startup) { + while (s->ct <= 8 && s->ct >= 0) { + /* first we can move a new byte into s->c */ + if (s->pscd_ptr >= s->pscd_end) { + return -1; /* more bytes needed */ + } + if (*s->pscd_ptr == 0xff) + if (s->pscd_ptr + 1 >= s->pscd_end) { + return -1; /* final 0xff byte not processed */ + } else { + if (*(s->pscd_ptr + 1) == MARKER_STUFF) { + s->c |= 0xffL << (8 - s->ct); + s->ct += 8; + s->pscd_ptr += 2; + } else { + s->ct = -1; /* start padding with zero bytes */ + if (s->nopadding) { + s->nopadding = 0; + return -2; /* subsequent symbols might depend on zero padding */ + } + } + } + else { + s->c |= (long)*(s->pscd_ptr++) << (8 - s->ct); + s->ct += 8; + } + } + s->c <<= 1; + s->a <<= 1; + if (s->ct >= 0) s->ct--; + if (s->a == 0x10000L) + s->startup = 0; + } + + st = s->st + cx; + ss = *st & 0x7f; + assert(ss < 113); + lsz = lsztab[ss]; + +#if 0 + fprintf(stderr, "cx = %d, mps = %d, st = %3d, lsz = 0x%04x, a = 0x%05lx, " + "c = 0x%08lx, ct = %2d\n", + cx, !!(s->st[cx] & 0x80), ss, lsz, s->a, s->c, s->ct); +#endif + + if ((s->c >> 16) < (s->a -= lsz)) + if (s->a & 0xffff8000L) + return *st >> 7; + else { + /* MPS_EXCHANGE */ + if (s->a < lsz) { + pix = 1 - (*st >> 7); + /* Check whether MPS/LPS exchange is necessary + * and chose next probability estimator status */ + *st &= 0x80; + *st ^= nlpstab[ss]; + } else { + pix = *st >> 7; + *st &= 0x80; + *st |= nmpstab[ss]; + } + } + else { + /* LPS_EXCHANGE */ + if (s->a < lsz) { + s->c -= s->a << 16; + s->a = lsz; + pix = *st >> 7; + *st &= 0x80; + *st |= nmpstab[ss]; + } else { + s->c -= s->a << 16; + s->a = lsz; + pix = 1 - (*st >> 7); + /* Check whether MPS/LPS exchange is necessary + * and chose next probability estimator status */ + *st &= 0x80; + *st ^= nlpstab[ss]; + } + } + + return pix; +} diff --git a/libjbig/jbig_ar.h b/libjbig/jbig_ar.h new file mode 100644 index 0000000..d58b1ae --- /dev/null +++ b/libjbig/jbig_ar.h @@ -0,0 +1,53 @@ +/* + * Header file for the arithmetic encoder and decoder of + * the portable JBIG compression library + * + * Markus Kuhn -- http://www.cl.cam.ac.uk/~mgk25/jbigkit/ + */ + +#ifndef JBG_AR_H +#define JBG_AR_H + +/* + * Status of arithmetic encoder + */ + +struct jbg_arenc_state { + unsigned char st[4096]; /* probability status for contexts, MSB = MPS */ + unsigned long c; /* register C: base of coding intervall, * + * layout as in Table 23 */ + unsigned long a; /* register A: normalized size of coding interval */ + long sc; /* number of buffered 0xff values that might still overflow */ + int ct; /* bit shift counter, determines when next byte will be written */ + int buffer; /* buffer for most recent output byte != 0xff */ + void (*byte_out)(int, void *); /* function that receives all PSCD bytes */ + void *file; /* parameter passed to byte_out */ +}; + +/* + * Status of arithmetic decoder + */ + +struct jbg_ardec_state { + unsigned char st[4096]; /* probability status for contexts, MSB = MPS */ + unsigned long c; /* register C: base of coding intervall, * + * layout as in Table 25 */ + unsigned long a; /* register A: normalized size of coding interval */ + unsigned char *pscd_ptr; /* pointer to next PSCD data byte */ + unsigned char *pscd_end; /* pointer to byte after PSCD */ + int ct; /* bit-shift counter, determines when next byte will be read; + * special value -1 signals that zero-padding has started */ + int startup; /* boolean flag that controls initial fill of s->c */ + int nopadding; /* boolean flag that triggers return -2 between + * reaching PSCD end and decoding the first symbol + * that might never have been encoded in the first + * place */ +}; + +void arith_encode_init(struct jbg_arenc_state *s, int reuse_st); +void arith_encode_flush(struct jbg_arenc_state *s); +void arith_encode(struct jbg_arenc_state *s, int cx, int pix); +void arith_decode_init(struct jbg_ardec_state *s, int reuse_st); +int arith_decode(struct jbg_ardec_state *s, int cx); + +#endif /* JBG_AR_H */ diff --git a/libjbig/po/README.txt b/libjbig/po/README.txt new file mode 100644 index 0000000..64ba523 --- /dev/null +++ b/libjbig/po/README.txt @@ -0,0 +1,20 @@ +Older versions of jbig.c contained a list of human-readable +result/error messages in both English and German. + +These messages are highly technical and unlikely to be of much use to +end users who are not familiar with the JBIG1 standard (which has only +been published in English, Spanish and French). Therefore, in the +interest of simplicity, since release 2.0 the source code contains in +errmsg[] now only the English version of these messages. + +The German version is preserved here in the form of a PO translation +file, as used by the GNU gettext package, just in case anyone still +finds it of use. + +See http://www.gnu.org/software/gettext/manual/gettext.html for +information on the PO file format and tools for creating and using +them. + +JBIG-KIT itself does not use gettext, but the included po files might +help users of the library to translate the strings returned by +jbg_strerror() or jbg85_strerror() into other languages. diff --git a/libjbig/po/de.po b/libjbig/po/de.po new file mode 100644 index 0000000..f29ead8 --- /dev/null +++ b/libjbig/po/de.po @@ -0,0 +1,52 @@ +# German translations for jbigkit package +# Copyright (C) 2008 Markus Kuhn +# This file is distributed under the same license as the jbigkit package. +# +msgid "" +msgstr "" +"Project-Id-Version: jbigkit 2.0\n" +"Report-Msgid-Bugs-To: http://www.cl.cam.ac.uk/~mgk25/jbigkit/\n" +"POT-Creation-Date: 2014-03-24 15:35+0000\n" +"PO-Revision-Date: 2008-08-27 20:16+0100\n" +"Last-Translator: Markus Kuhn \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: jbig.c:98 jbig85.c:69 +msgid "All OK" +msgstr "Kein Problem" + +#: jbig.c:99 jbig85.c:70 +msgid "Reached specified image size" +msgstr "Angeforderte Bildgröße erreicht" + +#: jbig.c:100 jbig85.c:71 +msgid "Unexpected end of input data stream" +msgstr "Unerwartetes Ende des Eingabedatenstroms" + +#: jbig.c:101 jbig85.c:72 +msgid "Not enough memory available" +msgstr "Nicht genügend Speicher vorhanden" + +#: jbig.c:102 jbig85.c:73 +msgid "ABORT marker segment encountered" +msgstr "Es wurde eine Abbruch-Sequenz gefunden" + +#: jbig.c:103 jbig85.c:74 +msgid "Unknown marker segment encountered" +msgstr "Es wurde eine unbekannte Marker-Sequenz gefunden" + +#: jbig.c:104 jbig85.c:75 +msgid "Input data stream contains invalid data" +msgstr "Es wurden ungültige Daten gefunden" + +#: jbig.c:105 jbig85.c:76 +msgid "Input data stream uses unimplemented JBIG features" +msgstr "Eingabedatenstrom benutzt nicht implementierte JBIG Optionen" + +#: jbig.c:106 +msgid "Incremental BIE does not continue previous one" +msgstr "Neue Bilddaten passen nicht zu vorangegangenen" diff --git a/libjbig/po/ru.po b/libjbig/po/ru.po new file mode 100644 index 0000000..6e07113 --- /dev/null +++ b/libjbig/po/ru.po @@ -0,0 +1,53 @@ +# Russian translations for jbigkit package. +# This file is distributed under the same license as the jbigkit package. +# Russian translation by ghostmansd@gmil.com, +# with some changes by Sergei Skorobogatov. +# +msgid "" +msgstr "" +"Project-Id-Version: jbigkit 2.1\n" +"Report-Msgid-Bugs-To: http://www.cl.cam.ac.uk/~mgk25/jbigkit/\n" +"POT-Creation-Date: 2014-03-24 15:35+0000\n" +"PO-Revision-Date: 2014-03-21 18:06+0000\n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#: jbig.c:98 jbig85.c:69 +msgid "All OK" +msgstr "Успешное завершение" + +#: jbig.c:99 jbig85.c:70 +msgid "Reached specified image size" +msgstr "Указанный размер достигнут" + +#: jbig.c:100 jbig85.c:71 +msgid "Unexpected end of input data stream" +msgstr "Неожиданный конец входного потока" + +#: jbig.c:101 jbig85.c:72 +msgid "Not enough memory available" +msgstr "Недостаточно памяти" + +#: jbig.c:102 jbig85.c:73 +msgid "ABORT marker segment encountered" +msgstr "Обнаружен сегмент прерывания" + +#: jbig.c:103 jbig85.c:74 +msgid "Unknown marker segment encountered" +msgstr "Обнаружен неизвестный сегмент" + +#: jbig.c:104 jbig85.c:75 +msgid "Input data stream contains invalid data" +msgstr "Входной поток содержит неверные данные" + +#: jbig.c:105 jbig85.c:76 +msgid "Input data stream uses unimplemented JBIG features" +msgstr "Входной поток использует нереализованные функции" + +#: jbig.c:106 +msgid "Incremental BIE does not continue previous one" +msgstr "Следующий тип данных BIE не продолжает предыдущий" diff --git a/libjbig/tstcodec.c b/libjbig/tstcodec.c new file mode 100644 index 0000000..9ba09cd --- /dev/null +++ b/libjbig/tstcodec.c @@ -0,0 +1,550 @@ +/* + * A sequence of test procedures for this JBIG implementation + * + * Run this test sequence after each modification on the JBIG library. + * + * Markus Kuhn -- http://www.cl.cam.ac.uk/~mgk25/ + */ + +#include +#include +#include +#include + +#include "jbig.h" + +#define TESTBUF_SIZE 400000L +#define TESTPIC_SIZE 477995L + +#define FAILED "F\bFA\bAI\bIL\bLE\bED\bD" +#define PASSED "PASSED" + +unsigned char *testbuf; +unsigned char *testpic; + +long testbuf_len; + + +static void *checkedmalloc(size_t n) +{ + void *p; + + if ((p = malloc(n)) == NULL) { + fprintf(stderr, "Sorry, not enough memory available!\n"); + exit(1); + } + + return p; +} + +static void testbuf_write(int v, void *dummy) +{ + if (testbuf_len < TESTBUF_SIZE) + testbuf[testbuf_len++] = v; + (void) dummy; + return; +} + + +static void testbuf_writel(unsigned char *start, size_t len, void *dummy) +{ + if (testbuf_len < TESTBUF_SIZE) { + if (testbuf_len + len < TESTBUF_SIZE) + memcpy(testbuf + testbuf_len, start, len); + else + memcpy(testbuf + testbuf_len, start, TESTBUF_SIZE - testbuf_len); + } + testbuf_len += len; + +#ifdef DEBUG + { + unsigned char *p; + unsigned sum = 0; + + for (p = start; p - start < (ptrdiff_t) len; sum = (sum ^ *p++) << 1); + printf(" testbuf_writel: %4lu bytes, checksum %04x\n", + (unsigned long) len, sum & 0xffff); + } +#endif + + (void) dummy; + return; +} + + +/* + * Store the artificial test image defined in T.82, clause 7.2.1 at + * pic. The image requires 477995 bytes of memory, is 1960 x 1951 pixels + * large and has one plane. + */ +static void testimage(unsigned char *pic) +{ + unsigned long i, j, sum; + unsigned int prsg, repeat[8]; + unsigned char *p; + + memset(pic, 0, TESTPIC_SIZE); + p = pic; + prsg = 1; + for (j = 0; j < 1951; j++) + for (i = 0; i < 1960; i++) { + if (j >= 192) { + if (j < 1023 || ((i >> 3) & 3) == 0) { + sum = (prsg & 1) + ((prsg >> 2) & 1) + ((prsg >> 11) & 1) + + ((prsg >> 15) & 1); + prsg = (prsg << 1) + (sum & 1); + if ((prsg & 3) == 0) { + *p |= 1 << (7 - (i & 7)); + repeat[i & 7] = 1; + } else { + repeat[i & 7] = 0; + } + } else { + if (repeat[i & 7]) + *p |= 1 << (7 - (i & 7)); + } + } + if ((i & 7) == 7) ++p; + } + + /* verify test image */ + sum = 0; + for (i = 0; i < TESTPIC_SIZE; i++) + for (j = 0; j < 8; j++) + sum += (pic[i] >> j) & 1; + if (sum != 861965L) + printf("WARNING: Artificial test image has %lu (not 861965) " + "foreground pixels!\n", sum); + + return; +} + + +/* + * Perform a full test cycle with one set of parameters. Encode an image + * and compare the length of the result with correct_length. Then decode + * the image again both in one single chunk or byte by byte and compare + * the results with the original input image. + */ +static int test_cycle(unsigned char **orig_image, int width, int height, + int options, int order, int layers, int planes, + unsigned long l0, int mx, long correct_length, + const char *test_id) +{ + struct jbg_enc_state sje; + struct jbg_dec_state sjd; + int trouble = 0; + long l; + size_t plane_size; + int i, result; + unsigned char **image; + + plane_size = ((width + 7) / 8) * height; + image = (unsigned char **) checkedmalloc(planes * sizeof(unsigned char *)); + for (i = 0; i < planes; i++) { + image[i] = (unsigned char *) checkedmalloc(plane_size); + memcpy(image[i], orig_image[i], plane_size); + } + + printf("\nTest %s.1: Encoding ...\n", test_id); + testbuf_len = 0; + jbg_enc_init(&sje, width, height, planes, image, testbuf_writel, NULL); + jbg_enc_layers(&sje, layers); + jbg_enc_options(&sje, order, options, l0, mx, 0); + jbg_enc_out(&sje); + jbg_enc_free(&sje); + for (i = 0; i < planes; i++) + free(image[i]); + free(image); + printf("Encoded BIE has %6ld bytes: ", testbuf_len); + if (correct_length >= 0) + if (testbuf_len == correct_length) + puts(PASSED); + else { + trouble++; + printf(FAILED ", correct would have been %ld\n", correct_length); + } + else + puts(""); + + printf("Test %s.2: Decoding whole chunk ...\n", test_id); + jbg_dec_init(&sjd); + result = jbg_dec_in(&sjd, testbuf, testbuf_len, NULL); + if (result != JBG_EOK) { + printf("Decoder complained with return value %d: " FAILED "\n" + "Cause: '%s'\n", result, jbg_strerror(result)); + trouble++; + } else { + printf("Image comparison: "); + result = 1; + for (i = 0; i < planes; i++) { + if (memcmp(orig_image[i], sjd.lhp[layers & 1][i], + ((width + 7) / 8) * height)) { + result = 0; + trouble++; + printf(FAILED " for plane %d\n", i); + } + } + if (result) + puts(PASSED); + } + jbg_dec_free(&sjd); + + printf("Test %s.3: Decoding with single-byte feed ...\n", test_id); + jbg_dec_init(&sjd); + result = JBG_EAGAIN; + for (l = 0; l < testbuf_len; l++) { + result = jbg_dec_in(&sjd, testbuf + l, 1, NULL); + if (l < testbuf_len - 1 && result != JBG_EAGAIN) { + printf("Decoder complained with return value %d at byte %ld: " FAILED + "\nCause: '%s'\n", result, l, jbg_strerror(result)); + trouble++; + break; + } + } + if (l == testbuf_len) { + if (result != JBG_EOK) { + printf("Decoder complained with return value %d at final byte: " FAILED + "\nCause: '%s'\n", result, jbg_strerror(result)); + trouble++; + } else { + printf("Image comparison: "); + result = 1; + for (i = 0; i < planes; i++) { + if (memcmp(orig_image[i], sjd.lhp[layers & 1][i], + ((width + 7) / 8) * height)) { + result = 0; + trouble++; + printf(FAILED " for plane %d\n", i); + } + } + if (result) + puts(PASSED); + } + } + + jbg_dec_free(&sjd); + puts(""); + + return trouble != 0; +} + + +int main(int argc, char **argv) +{ + int trouble, problems = 0; + struct jbg_arenc_state *se; + struct jbg_ardec_state *sd; + long i; + int pix, order, layers; + char test[10]; + size_t st; + unsigned char *pp; + unsigned char *ppp[4]; + + int t82pix[16] = { + 0x05e0, 0x0000, 0x8b00, 0x01c4, 0x1700, 0x0034, 0x7fff, 0x1a3f, + 0x951b, 0x05d8, 0x1d17, 0xe770, 0x0000, 0x0000, 0x0656, 0x0e6a + }; + int t82cx[16] = { + 0x0fe0, 0x0000, 0x0f00, 0x00f0, 0xff00, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }; + unsigned char t82sde[32] = { + 0x69, 0x89, 0x99, 0x5c, 0x32, 0xea, 0xfa, 0xa0, + 0xd5, 0xff, 0x00, 0x52, 0x7f, 0xff, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0x00, 0x2d, 0x20, 0x82, 0x91, 0xff, 0x02 + }; + + /* three 23x5 pixel test images with the letters JBIG */ + unsigned char jbig_normal[15*4] = { + 0x7c, 0xe2, 0x38, 0x04, 0x92, 0x40, 0x04, 0xe2, 0x5c, 0x44, + 0x92, 0x44, 0x38, 0xe2, 0x38, + 0x7c, 0xe2, 0x38, 0x04, 0x92, 0x40, 0x04, 0xe2, 0x5c, 0x44, + 0x92, 0x44, 0x38, 0xe2, 0x38, + 0x7c, 0xe2, 0x38, 0x04, 0x92, 0x40, 0x04, 0xe2, 0x5c, 0x44, + 0x92, 0x44, 0x38, 0xe2, 0x38, + 0x7c, 0xe2, 0x38, 0x04, 0x92, 0x40, 0x04, 0xe2, 0x5c, 0x44, + 0x92, 0x44, 0x38, 0xe2, 0x38 + }; + unsigned char jbig_upsidedown[15*4] = { + 0x38, 0xe2, 0x38, 0x44, 0x92, 0x44, 0x04, 0xe2, 0x5c, 0x04, + 0x92, 0x40, 0x7c, 0xe2, 0x38, + 0x38, 0xe2, 0x38, 0x44, 0x92, 0x44, 0x04, 0xe2, 0x5c, 0x04, + 0x92, 0x40, 0x7c, 0xe2, 0x38, + 0x38, 0xe2, 0x38, 0x44, 0x92, 0x44, 0x04, 0xe2, 0x5c, 0x04, + 0x92, 0x40, 0x7c, 0xe2, 0x38, + 0x38, 0xe2, 0x38, 0x44, 0x92, 0x44, 0x04, 0xe2, 0x5c, 0x04, + 0x92, 0x40, 0x7c, 0xe2, 0x38 + }; + unsigned char jbig_inverse[15*4] = { + 0xff^0x7c, 0xff^0xe2, 0xfe^0x38, 0xff^0x04, 0xff^0x92, + 0xfe^0x40, 0xff^0x04, 0xff^0xe2, 0xfe^0x5c, 0xff^0x44, + 0xff^0x92, 0xfe^0x44, 0xff^0x38, 0xff^0xe2, 0xfe^0x38, + 0xff^0x7c, 0xff^0xe2, 0xfe^0x38, 0xff^0x04, 0xff^0x92, + 0xfe^0x40, 0xff^0x04, 0xff^0xe2, 0xfe^0x5c, 0xff^0x44, + 0xff^0x92, 0xfe^0x44, 0xff^0x38, 0xff^0xe2, 0xfe^0x38, + 0xff^0x7c, 0xff^0xe2, 0xfe^0x38, 0xff^0x04, 0xff^0x92, + 0xfe^0x40, 0xff^0x04, 0xff^0xe2, 0xfe^0x5c, 0xff^0x44, + 0xff^0x92, 0xfe^0x44, 0xff^0x38, 0xff^0xe2, 0xfe^0x38, + 0xff^0x7c, 0xff^0xe2, 0xfe^0x38, 0xff^0x04, 0xff^0x92, + 0xfe^0x40, 0xff^0x04, 0xff^0xe2, 0xfe^0x5c, 0xff^0x44, + 0xff^0x92, 0xfe^0x44, 0xff^0x38, 0xff^0xe2, 0xfe^0x38 + }; + int orders[] = { + 0, + JBG_ILEAVE, + JBG_ILEAVE | JBG_SMID, +#if 0 + JBG_SEQ, + JBG_SEQ | JBG_SMID, + JBG_SEQ | JBG_ILEAVE, + JBG_HITOLO, + JBG_HITOLO | JBG_ILEAVE, + JBG_HITOLO | JBG_ILEAVE | JBG_SMID, + JBG_HITOLO | JBG_SEQ, + JBG_HITOLO | JBG_SEQ | JBG_SMID, + JBG_HITOLO | JBG_SEQ | JBG_ILEAVE +#endif + }; + + printf("\nAutomatic JBIG Compatibility Test Suite\n" + "---------------------------------------\n\n" + "JBIG-KIT Version " JBG_VERSION + " -- This test may take a few minutes.\n\n\n"); + + /* allocate test buffer memory */ + testbuf = (unsigned char *) checkedmalloc(TESTBUF_SIZE); + testpic = (unsigned char *) checkedmalloc(TESTPIC_SIZE); + se = (struct jbg_arenc_state *) checkedmalloc(sizeof(struct jbg_arenc_state)); + sd = (struct jbg_ardec_state *) checkedmalloc(sizeof(struct jbg_ardec_state)); + + /* test a few properties of the machine architecture */ + testbuf[0] = 42; + testbuf[0x10000L] = 0x42; + st = 1 << 16; + testbuf[st]++; + pp = testbuf + 0x4000; + pp += 0x4000; + pp += 0x4000; + pp += 0x4000; + if (testbuf[0] != 42 || *pp != 0x43) { + printf("Porting error detected:\n\n" + "Pointer arithmetic with this compiler has not at least 32 bits!\n" + "Are you sure, you have not compiled this program on an 8-bit\n" + "or 16-bit architecture? This compiler mode can obviously not\n" + "handle arrays with a size of more than 65536 bytes. With this\n" + "memory model, JBIG-KIT can only handle very small images and\n" + "not even this compatibility test suite will run. :-(\n\n"); + exit(1); + } + + /* only supported command line option: + * output file name for exporting test image */ + if (argc > 1) { + FILE *f; + + puts("Generating test image ..."); + testimage(testpic); + printf("Storing in '%s' ...\n", argv[1]); + + /* write out test image as PBM file */ + f = fopen(argv[1], "wb"); + if (!f) abort(); + fprintf(f, "P4\n"); +#if 0 + fprintf(f, "# Test image as defined in ITU-T T.82, clause 7.2.1\n"); +#endif + fprintf(f, "%10lu\n%10lu\n", 1960LU, 1951LU); + fwrite(testpic, 1, TESTPIC_SIZE, f); + fclose(f); + exit(0); + } + +#if 1 + puts("1) Arithmetic encoder test sequence from ITU-T T.82, clause 7.1\n" + "---------------------------------------------------------------\n"); + arith_encode_init(se, 0); + testbuf_len = 0; + se->byte_out = testbuf_write; + for (i = 0; i < 16 * 16; i++) + arith_encode(se, (t82cx[i >> 4] >> ((15 - i) & 15)) & 1, + (t82pix[i >> 4] >> ((15 - i) & 15)) & 1); + arith_encode_flush(se); + printf("result of encoder:\n "); + for (i = 0; i < testbuf_len && i < TESTBUF_SIZE; i++) + printf("%02x", testbuf[i]); + printf("\nexpected result:\n "); + for (i = 0; i < 30; i++) + printf("%02x", t82sde[i]); + printf("\n\nTest 1: "); + if (testbuf_len != 30 || memcmp(testbuf, t82sde, 30)) { + problems++; + printf(FAILED); + } else + printf(PASSED); + printf("\n\n"); + + + puts("2) Arithmetic decoder test sequence from ITU-T T.82, clause 7.1\n" + "---------------------------------------------------------------\n"); + printf("Test 2.1: Decoding whole chunk ...\n"); + arith_decode_init(sd, 0); + sd->pscd_ptr = t82sde; + sd->pscd_end = t82sde + 32; + trouble = 0; + for (i = 0; i < 16 * 16 && !trouble; i++) { + pix = arith_decode(sd, (t82cx[i >> 4] >> ((15 - i) & 15)) & 1); + if (pix < 0) { + printf("Problem at pixel %ld, byte %ld.\n\n", + i+1, (long) (sd->pscd_ptr - sd->pscd_end)); + trouble++; + break; + } + if (pix != ((t82pix[i >> 4] >> ((15 - i) & 15)) & 1)) { + printf("Wrong PIX answer (%d) at pixel %ld.\n\n", pix, i+1); + trouble++; + break; + } + } + if (!trouble && sd->pscd_ptr != sd->pscd_end - 2) { + printf("%ld bytes left after decoder finished.\n\n", + (long) (sd->pscd_end - sd->pscd_ptr - 2)); + trouble++; + } + printf("Test result: "); + if (trouble) { + problems++; + puts(FAILED); + } else + puts(PASSED); + printf("\n"); + + printf("Test 2.2: Decoding with single byte feed ...\n"); + arith_decode_init(sd, 0); + pp = t82sde; + sd->pscd_ptr = pp; + sd->pscd_end = pp + 1; + trouble = 0; + for (i = 0; i < 16 * 16 && !trouble; i++) { + pix = arith_decode(sd, (t82cx[i >> 4] >> ((15 - i) & 15)) & 1); + while (pix < 0 && sd->pscd_end < t82sde + 32) { + pp++; + if (sd->pscd_ptr != pp - 1) + sd->pscd_ptr = pp; + sd->pscd_end = pp + 1; + pix = arith_decode(sd, (t82cx[i >> 4] >> ((15 - i) & 15)) & 1); + } + if (pix < 0) { + printf("Problem at pixel %ld, byte %ld.\n\n", + i+1, (long) (sd->pscd_ptr - sd->pscd_end)); + trouble++; + break; + } + if (pix != ((t82pix[i >> 4] >> ((15 - i) & 15)) & 1)) { + printf("Wrong PIX answer (%d) at pixel %ld.\n\n", pix, i+1); + trouble++; + break; + } + } + if (!trouble && sd->pscd_ptr != sd->pscd_end - 2) { + printf("%ld bytes left after decoder finished.\n\n", + (long) (sd->pscd_end - sd->pscd_ptr - 2)); + trouble++; + } + printf("Test result: "); + if (trouble) { + problems++; + puts(FAILED); + } else + puts(PASSED); + printf("\n"); + + puts("3) Parametric algorithm test sequence from ITU-T T.82, clause 7.2\n" + "-----------------------------------------------------------------\n"); + puts("Generating test image ..."); + testimage(testpic); + putchar('\n'); + pp = testpic; + + puts("Test 3.1: TPBON=0, Mx=0, LRLTWO=0, L0=1951, 0 layers"); + problems += test_cycle(&pp, 1960, 1951, JBG_DELAY_AT, + 0, 0, 1, 1951, 0, 317384L, "3.1"); + puts("Test 3.2: TPBON=0, Mx=0, LRLTWO=1, L0=1951, 0 layers"); + problems += test_cycle(&pp, 1960, 1951, JBG_DELAY_AT | JBG_LRLTWO, + 0, 0, 1, 1951, 0, 317132L, "3.2"); + puts("Test 3.3: TPBON=1, Mx=8, LRLTWO=0, L0=128, 0 layers"); + problems += test_cycle(&pp, 1960, 1951, JBG_DELAY_AT | JBG_TPBON, + 0, 0, 1, 128, 8, 253653L, "3.3"); + puts("Test 3.4: TPBON=1, DPON=1, TPDON=1, Mx=8, LRLTWO=0, L0=2, 6 layers"); + problems += test_cycle(&pp, 1960, 1951, + JBG_DELAY_AT | JBG_TPBON | JBG_TPDON | JBG_DPON, + 0, 6, 1, 2, 8, 279314L, "3.4"); + puts("Test 3.5: as Test 3.4 but with DPPRIV=1"); + problems += test_cycle(&pp, 1960, 1951, + JBG_DELAY_AT | JBG_TPBON | JBG_TPDON | JBG_DPON | + JBG_DPPRIV, + 0, 6, 1, 2, 8, 279314L + 1728, "3.5"); +#if 0 /* Note: option SEQ is currently not supported by the decoder */ + puts("Test 3.6: as Test 3.4 but with order bit SEQ set"); + problems += test_cycle(&pp, 1960, 1951, + JBG_DELAY_AT | JBG_TPBON | JBG_TPDON | JBG_DPON, + JBG_SEQ, 6, 1, 2, 8, 279314L, "3.6"); +#endif +#endif + + puts("4) Same T.82 tests with SDRST instead of SDNORM\n" + "-----------------------------------------------\n"); + + puts("Test 4.0: TPBON=1, Mx=8, LRLTWO=0, L0=128, 0 layers"); + problems += test_cycle(&pp, 1960, 1951, JBG_SDRST | JBG_TPBON, + 0, 0, 1, 128, 8, -1, "4.0"); + + puts("Test 4.1: TPBON=0, Mx=0, LRLTWO=0, L0=1951, 0 layers"); + problems += test_cycle(&pp, 1960, 1951, JBG_SDRST, + 0, 0, 1, 1951, 0, -1, "4.1"); + puts("Test 4.2: TPBON=0, Mx=0, LRLTWO=1, L0=1951, 0 layers"); + problems += test_cycle(&pp, 1960, 1951, JBG_LRLTWO | JBG_SDRST, + 0, 0, 1, 1951, 0, -1, "4.2"); + puts("Test 4.3: TPBON=1, Mx=8, LRLTWO=0, L0=128, 0 layers"); + problems += test_cycle(&pp, 1960, 1951, JBG_TPBON | JBG_SDRST, + 0, 0, 1, 128, 8, -1, "4.3"); + puts("Test 4.4: TPBON=1, DPON=1, TPDON=1, Mx=8, LRLTWO=0, L0=2, 6 layers"); + problems += test_cycle(&pp, 1960, 1951, + JBG_TPBON | JBG_TPDON | + JBG_DPON | JBG_SDRST, + 0, 6, 1, 2, 8, -1, "4.4"); + + puts("5) Small test image, 0-3 layers, 4 planes, different orders\n" + "-----------------------------------------------------------\n"); + + /* test a simple multi-plane image */ + ppp[0] = jbig_normal; + ppp[1] = jbig_upsidedown; + ppp[2] = jbig_inverse; + ppp[3] = jbig_inverse; + + i = 0; + for (layers = 0; layers <= 3; layers++) + for (order = 0; order < (int) (sizeof(orders)/sizeof(int)); order++) { + sprintf(test, "5.%ld", ++i); + printf("Test %s: order=%d, %d layers, 4 planes", test, orders[order], + layers); + problems += test_cycle(ppp, 23, 5*4, JBG_TPBON | JBG_TPDON | JBG_DPON, + orders[order], layers, 4, 2, 8, -1, test); + } + + + printf("\nTest result summary: the library has %s the test suite.\n\n", + problems ? FAILED : PASSED); + if (problems) + puts("This is bad. If you cannot identify the problem yourself, please " + "send\nthis output plus a detailed description of your " + "compile environment\n(OS, compiler, version, options, etc.) to " + "Markus Kuhn\n."); + else + puts("Congratulations, everything is fine.\n"); + + return problems != 0; +} diff --git a/libjbig/tstcodec85.c b/libjbig/tstcodec85.c new file mode 100644 index 0000000..1a9d95e --- /dev/null +++ b/libjbig/tstcodec85.c @@ -0,0 +1,450 @@ +/* + * A sequence of test procedures for this JBIG implementation + * + * Run this test sequence after each modification on the JBIG library. + * + * Markus Kuhn -- http://www.cl.cam.ac.uk/~mgk25/ + */ + +#include +#include +#include +#include +#include + +#include "jbig85.h" + +#define TESTBUF_SIZE 400000L +#define TESTPIC_SIZE 477995L + +#define FAILED "F\bFA\bAI\bIL\bLE\bED\bD" +#define PASSED "PASSED" + +unsigned char *testbuf; +unsigned char *testpic; + +long testbuf_len; + + +static void *checkedmalloc(size_t n) +{ + void *p; + + if ((p = calloc(1, n)) == NULL) { + fprintf(stderr, "Sorry, not enough memory available!\n"); + exit(1); + } + + return p; +} + +static void testbuf_write(int v, void *dummy) +{ + if (testbuf_len < TESTBUF_SIZE) + testbuf[testbuf_len++] = v; + (void) dummy; + return; +} + + +static void testbuf_writel(unsigned char *start, size_t len, void *dummy) +{ + if (testbuf_len < TESTBUF_SIZE) { + if (testbuf_len + len < TESTBUF_SIZE) + memcpy(testbuf + testbuf_len, start, len); + else + memcpy(testbuf + testbuf_len, start, TESTBUF_SIZE - testbuf_len); + } + testbuf_len += len; + +#ifdef DEBUG + { + unsigned char *p; + unsigned sum = 0; + + for (p = start; p - start < (ptrdiff_t) len; sum = (sum ^ *p++) << 1); + printf(" testbuf_writel: %4lu bytes, checksum %04x\n", + (unsigned long) len, sum & 0xffff); + } +#endif + + (void) dummy; + return; +} + + +static int line_out(const struct jbg85_dec_state *s, + unsigned char *start, size_t len, + unsigned long y, void *bitmap) +{ + assert(jbg85_dec_validwidth(s)); + assert(len == (jbg85_dec_getwidth(s) >> 3) + !!(jbg85_dec_getwidth(s) & 7)); + assert(y < jbg85_dec_getheight(s)); + memcpy((unsigned char *) bitmap + len * y, start, len); + return 0; +} + + +/* + * Store the artificial test image defined in T.82, clause 7.2.1 at + * pic. The image requires 477995 bytes of memory, is 1960 x 1951 pixels + * large and has one plane. + */ +static void testimage(unsigned char *pic) +{ + unsigned long i, j, sum; + unsigned int prsg, repeat[8]; + unsigned char *p; + + memset(pic, 0, TESTPIC_SIZE); + p = pic; + prsg = 1; + for (j = 0; j < 1951; j++) + for (i = 0; i < 1960; i++) { + if (j >= 192) { + if (j < 1023 || ((i >> 3) & 3) == 0) { + sum = (prsg & 1) + ((prsg >> 2) & 1) + ((prsg >> 11) & 1) + + ((prsg >> 15) & 1); + prsg = (prsg << 1) + (sum & 1); + if ((prsg & 3) == 0) { + *p |= 1 << (7 - (i & 7)); + repeat[i & 7] = 1; + } else { + repeat[i & 7] = 0; + } + } else { + if (repeat[i & 7]) + *p |= 1 << (7 - (i & 7)); + } + } + if ((i & 7) == 7) ++p; + } + + /* verify test image */ + sum = 0; + for (i = 0; i < TESTPIC_SIZE; i++) + for (j = 0; j < 8; j++) + sum += (pic[i] >> j) & 1; + if (sum != 861965L) + printf("WARNING: Artificial test image has %lu (not 861965) " + "foreground pixels!\n", sum); + + return; +} + + +/* + * Perform a full test cycle with one set of parameters. Encode an image + * and compare the length of the result with correct_length. Then decode + * the image again both in one single chunk or byte by byte and compare + * the results with the original input image. + */ +static int test_cycle(unsigned char *orig_image, int width, int height, + int options, unsigned long l0, int mx, + long correct_length, const char *test_id) +{ + struct jbg85_enc_state sje; + struct jbg85_dec_state sjd; + int trouble = 0; + long l; + size_t plane_size, buffer_len; + int i, result; + unsigned char *image, *buffer; + size_t bpl; + size_t cnt; + + bpl = (width + 7) / 8; + plane_size = bpl * height; + image = (unsigned char *) checkedmalloc(plane_size); + memcpy(image, orig_image, plane_size); + + printf("\nTest-85 %s.1: Encoding ...\n", test_id); + testbuf_len = 0; + jbg85_enc_init(&sje, width, height, testbuf_writel, NULL); + jbg85_enc_options(&sje, options, l0, mx); + for (i = 0; i < height; i++) + jbg85_enc_lineout(&sje, + image + i * bpl, + image + (i-1) * bpl, + image + (i-2) * bpl); + free(image); + printf("Encoded BIE has %6ld bytes: ", testbuf_len); + if (correct_length >= 0) + if (testbuf_len == correct_length) + puts(PASSED); + else { + trouble++; + printf(FAILED ", correct would have been %ld\n", correct_length); + } + else + puts(""); + +#if 1 + buffer_len = ((width >> 3) + !!(width & 7)) * 3; + buffer = (unsigned char *) checkedmalloc(buffer_len); + image = (unsigned char *) checkedmalloc(plane_size); + printf("Test-85 %s.2: Decoding whole chunk ...\n", test_id); + jbg85_dec_init(&sjd, buffer, buffer_len, line_out, image); + result = jbg85_dec_in(&sjd, testbuf, testbuf_len, &cnt); + if (result != JBG_EOK) { + printf("Decoder complained with return value 0x%02x: " + FAILED "\nCause: '%s'\n", result, jbg85_strerror(result)); + printf("%ld bytes of BIE read, %lu lines decoded.\n", + (long) cnt, sjd.y); + trouble++; + } else { + printf("Image comparison: "); + result = 1; + if (memcmp(orig_image, image, plane_size)) { + result = 0; + trouble++; + printf(FAILED); + } + if (result) + puts(PASSED); + } + free(image); + + image = (unsigned char *) checkedmalloc(plane_size); + printf("Test-85 %s.3: Decoding with single-byte feed ...\n", test_id); + jbg85_dec_init(&sjd, buffer, buffer_len, line_out, image); + result = JBG_EAGAIN; + for (l = 0; l < testbuf_len; l++) { + result = jbg85_dec_in(&sjd, testbuf + l, 1, NULL); + if (l < testbuf_len - 1 && result != JBG_EAGAIN) { + printf("Decoder complained with return value 0x%02x at byte %ld: " + FAILED "\nCause: '%s'\n", result, l, jbg85_strerror(result)); + trouble++; + break; + } + } + if (l == testbuf_len) { + if (result != JBG_EOK) { + printf("Decoder complained with return value 0x%02x at final byte: " + FAILED "\nCause: '%s'\n", result, jbg85_strerror(result)); + trouble++; + } else { + printf("Image comparison: "); + result = 1; + if (memcmp(orig_image, image, plane_size)) { + result = 0; + trouble++; + printf(FAILED); + } + if (result) + puts(PASSED); + } + } + free(image); + +#endif + puts(""); + + return trouble != 0; +} + + +int main(int argc, char **argv) +{ + int trouble, problems = 0; + struct jbg_arenc_state *se; + struct jbg_ardec_state *sd; + long i; + int pix; + unsigned char *pp; + + int t82pix[16] = { + 0x05e0, 0x0000, 0x8b00, 0x01c4, 0x1700, 0x0034, 0x7fff, 0x1a3f, + 0x951b, 0x05d8, 0x1d17, 0xe770, 0x0000, 0x0000, 0x0656, 0x0e6a + }; + int t82cx[16] = { + 0x0fe0, 0x0000, 0x0f00, 0x00f0, 0xff00, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }; + unsigned char t82sde[32] = { + 0x69, 0x89, 0x99, 0x5c, 0x32, 0xea, 0xfa, 0xa0, + 0xd5, 0xff, 0x00, 0x52, 0x7f, 0xff, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0x00, 0x2d, 0x20, 0x82, 0x91, 0xff, 0x02 + }; + + printf("\nAutomatic JBIG Compatibility Test Suite\n" + "---------------------------------------\n\n" + "JBIG-KIT Version " JBG85_VERSION " (T.85 version)" + " -- This test may take a few minutes.\n\n\n"); + + /* allocate test buffer memory */ + testbuf = (unsigned char *) checkedmalloc(TESTBUF_SIZE); + testpic = (unsigned char *) checkedmalloc(TESTPIC_SIZE); + se = (struct jbg_arenc_state *) checkedmalloc(sizeof(struct jbg_arenc_state)); + sd = (struct jbg_ardec_state *) checkedmalloc(sizeof(struct jbg_ardec_state)); + + /* only supported command line option: + * output file name for exporting test image */ + if (argc > 1) { + FILE *f; + + puts("Generating test image ..."); + testimage(testpic); + printf("Storing in '%s' ...\n", argv[1]); + + /* write out test image as PBM file */ + f = fopen(argv[1], "wb"); + if (!f) abort(); + fprintf(f, "P4\n"); +#if 0 + fprintf(f, "# Test image as defined in ITU-T T.82, clause 7.2.1\n"); +#endif + fprintf(f, "1960 1951\n"); + fwrite(testpic, 1, TESTPIC_SIZE, f); + fclose(f); + exit(0); + } + +#if 1 + puts("1) Arithmetic encoder test sequence from ITU-T T.82, clause 7.1\n" + "---------------------------------------------------------------\n"); + arith_encode_init(se, 0); + testbuf_len = 0; + se->byte_out = testbuf_write; + for (i = 0; i < 16 * 16; i++) + arith_encode(se, (t82cx[i >> 4] >> ((15 - i) & 15)) & 1, + (t82pix[i >> 4] >> ((15 - i) & 15)) & 1); + arith_encode_flush(se); + printf("result of encoder:\n "); + for (i = 0; i < testbuf_len && i < TESTBUF_SIZE; i++) + printf("%02x", testbuf[i]); + printf("\nexpected result:\n "); + for (i = 0; i < 30; i++) + printf("%02x", t82sde[i]); + printf("\n\nTest 1: "); + if (testbuf_len != 30 || memcmp(testbuf, t82sde, 30)) { + problems++; + printf(FAILED); + } else + printf(PASSED); + printf("\n\n"); + + + puts("2) Arithmetic decoder test sequence from ITU-T T.82, clause 7.1\n" + "---------------------------------------------------------------\n"); + printf("Test 2.1: Decoding whole chunk ...\n"); + arith_decode_init(sd, 0); + sd->pscd_ptr = t82sde; + sd->pscd_end = t82sde + 32; + trouble = 0; + for (i = 0; i < 16 * 16 && !trouble; i++) { + pix = arith_decode(sd, (t82cx[i >> 4] >> ((15 - i) & 15)) & 1); + if (pix < 0) { + printf("Problem at pixel %ld, byte %ld.\n\n", + i+1, (long) (sd->pscd_ptr - sd->pscd_end)); + trouble++; + break; + } + if (pix != ((t82pix[i >> 4] >> ((15 - i) & 15)) & 1)) { + printf("Wrong PIX answer (%d) at pixel %ld.\n\n", pix, i+1); + trouble++; + break; + } + } + if (!trouble && sd->pscd_ptr != sd->pscd_end - 2) { + printf("%ld bytes left after decoder finished.\n\n", + (long) (sd->pscd_end - sd->pscd_ptr - 2)); + trouble++; + } + printf("Test result: "); + if (trouble) { + problems++; + puts(FAILED); + } else + puts(PASSED); + printf("\n"); + + printf("Test 2.2: Decoding with single byte feed ...\n"); + arith_decode_init(sd, 0); + pp = t82sde; + sd->pscd_ptr = pp; + sd->pscd_end = pp + 1; + trouble = 0; + for (i = 0; i < 16 * 16 && !trouble; i++) { + pix = arith_decode(sd, (t82cx[i >> 4] >> ((15 - i) & 15)) & 1); + while (pix < 0 && sd->pscd_end < t82sde + 32) { + pp++; + if (sd->pscd_ptr != pp - 1) + sd->pscd_ptr = pp; + sd->pscd_end = pp + 1; + pix = arith_decode(sd, (t82cx[i >> 4] >> ((15 - i) & 15)) & 1); + } + if (pix < 0) { + printf("Problem at pixel %ld, byte %ld.\n\n", + i+1, (long) (sd->pscd_ptr - sd->pscd_end)); + trouble++; + break; + } + if (pix != ((t82pix[i >> 4] >> ((15 - i) & 15)) & 1)) { + printf("Wrong PIX answer (%d) at pixel %ld.\n\n", pix, i+1); + trouble++; + break; + } + } + if (!trouble && sd->pscd_ptr != sd->pscd_end - 2) { + printf("%ld bytes left after decoder finished.\n\n", + (long) (sd->pscd_end - sd->pscd_ptr - 2)); + trouble++; + } + printf("Test result: "); + if (trouble) { + problems++; + puts(FAILED); + } else + puts(PASSED); + printf("\n"); + + puts("3) Parametric algorithm test sequence from ITU-T T.82, clause 7.2\n" + "-----------------------------------------------------------------\n"); + puts("Generating test image ..."); + testimage(testpic); + putchar('\n'); + + puts("Test-85 3.1: TPBON=0, Mx=0, LRLTWO=0, L0=1951, 0 layers"); + problems += test_cycle(testpic, 1960, 1951, 0, + 1951, 0, 317384L, "3.1"); + puts("Test-85 3.2: TPBON=0, Mx=0, LRLTWO=1, L0=1951, 0 layers"); + problems += test_cycle(testpic, 1960, 1951, JBG_LRLTWO, + 1951, 0, 317132L, "3.2"); + puts("Test-85 3.3: TPBON=1, Mx=8, LRLTWO=0, L0=128, 0 layers"); + problems += test_cycle(testpic, 1960, 1951, JBG_TPBON, + 128, 8, 253653L, "3.3"); +#endif + +#if 0 + puts("4) Same T.82 tests with SDRST instead of SDNORM\n" + "-----------------------------------------------\n"); + + puts("Test-85 4.0: TPBON=1, Mx=8, LRLTWO=0, L0=128, 0 layers"); + problems += test_cycle(&pp, 1960, 1951, JBG_SDRST | JBG_TPBON, + 128, 8, -1, "4.0"); + + puts("Test-85 4.1: TPBON=0, Mx=0, LRLTWO=0, L0=1951, 0 layers"); + problems += test_cycle(&pp, 1960, 1951, JBG_SDRST, + 1951, 0, -1, "4.1"); + puts("Test-85 4.2: TPBON=0, Mx=0, LRLTWO=1, L0=1951, 0 layers"); + problems += test_cycle(&pp, 1960, 1951, JBG_LRLTWO | JBG_SDRST, + 1951, 0, -1, "4.2"); + puts("Test-85 4.3: TPBON=1, Mx=8, LRLTWO=0, L0=128, 0 layers"); + problems += test_cycle(&pp, 1960, 1951, JBG_TPBON | JBG_SDRST, + 128, 8, -1, "4.3"); +#endif + + printf("\nTest result summary: the T.85 library has %s the test suite.\n\n", + problems ? FAILED : PASSED); + if (problems) + puts("This is bad. If you cannot identify the problem yourself, please " + "send\nthis output plus a detailed description of your " + "compile environment\n(OS, compiler, version, options, etc.) to " + "Markus Kuhn\n."); + else + puts("Congratulations, everything is fine.\n"); + + return problems != 0; +} diff --git a/pbmtools/Makefile b/pbmtools/Makefile new file mode 100644 index 0000000..6314af8 --- /dev/null +++ b/pbmtools/Makefile @@ -0,0 +1,166 @@ +# Unix makefile for the JBIG-KIT PBM tools + +# Select an ANSI/ISO C compiler here, e.g. GNU gcc is recommended +CC = gcc + +# Options for the compiler +CFLAGS = -g -O -W -Wall -Wno-unused-result -ansi -pedantic # --coverage +CPPFLAGS = -I../libjbig + +.SUFFIXES: .1 .5 .txt $(SUFFIXES) +.PHONY: txt test test82 test85 clean + +all: pbmtojbg jbgtopbm pbmtojbg85 jbgtopbm85 txt + +txt: pbmtojbg.txt jbgtopbm.txt pbm.txt pgm.txt + +pbmtojbg: pbmtojbg.o ../libjbig/libjbig.a + $(CC) $(CFLAGS) -o pbmtojbg pbmtojbg.o -L../libjbig -ljbig + +jbgtopbm: jbgtopbm.o ../libjbig/libjbig.a + $(CC) $(CFLAGS) -o jbgtopbm jbgtopbm.o -L../libjbig -ljbig + +pbmtojbg85: pbmtojbg85.o ../libjbig/libjbig85.a + $(CC) $(CFLAGS) -o pbmtojbg85 pbmtojbg85.o -L../libjbig -ljbig85 + +jbgtopbm85: jbgtopbm85.o ../libjbig/libjbig85.a + $(CC) $(CFLAGS) -o jbgtopbm85 jbgtopbm85.o -L../libjbig -ljbig85 + +jbgtopbm.o: jbgtopbm.c ../libjbig/jbig.h +pbmtojbg.o: pbmtojbg.c ../libjbig/jbig.h +jbgtopbm85.o: jbgtopbm85.c ../libjbig/jbig85.h +pbmtojbg85.o: pbmtojbg85.c ../libjbig/jbig85.h + +../libjbig/libjbig.a: ../libjbig/jbig.c ../libjbig/jbig.h \ + ../libjbig/jbig_ar.c ../libjbig/jbig_ar.h + make -C ../libjbig libjbig.a + +../libjbig/libjbig85.a: ../libjbig/jbig85.c ../libjbig/jbig85.h \ + ../libjbig/jbig_ar.c ../libjbig/jbig_ar.h + make -C ../libjbig libjbig85.a + +analyze: + clang $(CPPFLAGS) --analyze *.c + +test: test82 test85 + +test82: pbmtojbg jbgtopbm + make IMG=ccitt1 OPTIONSP= dotest1 + make IMG=ccitt2 OPTIONSP= dotest1 + make IMG=ccitt3 OPTIONSP= dotest1 + make IMG=xvlogo "OPTIONSP=-d 3" dotest1 + make IMG=sandra OPTIONSP= OPTIONSJ= dotest2g + make IMG=sandra OPTIONSP=-b OPTIONSJ=-b dotest2g + make IMG=sandra OPTIONSP=-q OPTIONSJ= dotest2g + make IMG=sandra "OPTIONSP=-o 0" OPTIONSJ= dotest2g + make IMG=sandra "OPTIONSP=-o 2" OPTIONSJ= dotest2g + make IMG=multi OPTIONSP= OPTIONSJ= dotest2g + make IMG=multi OPTIONSP=-b OPTIONSJ=-b dotest2g + make IMG=mx "OPTIONSP=-q -s 3 -m 128" dotest1 + make IMG=mx "OPTIONSP=-q -s 3 -m 128" dotest2b + make IMG=mx "OPTIONSP=-q -s 3 -m 128 -p 92" dotest2b + make IMG=mx "OPTIONSP=-q -Y -1" dotest2b + make IMG=mx "OPTIONSP=-Y -1" dotest2b + rm -f test-*.jbg test-*.pbm test-*.pgm + ./jbgtopbm ../examples/ccitt1.jbg | ./pbmtojbg > test-ccitt1.jbg + cmp ../examples/ccitt1.jbg test-ccitt1.jbg + rm -f test-*.jbg test-*.pbm test-*.pgm + ./jbgtopbm < ../examples/ccitt1.jbg | ./pbmtojbg - test-ccitt1.jbg + cmp ../examples/ccitt1.jbg test-ccitt1.jbg + rm -f test-*.jbg test-*.pbm test-*.pgm + ./jbgtopbm < ../examples/ccitt1.jbg - test-ccitt1.pbm ; \ + ./pbmtojbg test-ccitt1.pbm test-ccitt1.jbg + cmp ../examples/ccitt1.jbg test-ccitt1.jbg + rm -f test-*.jbg test-*.pbm test-*.pgm + ./jbgtopbm ../examples/ccitt1.jbg test-ccitt1.pbm ; \ + ./pbmtojbg test-ccitt1.pbm >test-ccitt1.jbg + cmp ../examples/ccitt1.jbg test-ccitt1.jbg + rm -f test-*.jbg test-*.pbm test-*.pgm + @echo + @echo "The pbmtools have PASSED the functional tests. Good!" + @echo + +dotest1: + ./jbgtopbm ../examples/$(IMG).jbg test-$(IMG).pbm + ./pbmtojbg $(OPTIONSP) test-$(IMG).pbm test-$(IMG).jbg + cmp test-$(IMG).jbg ../examples/$(IMG).jbg + +dotest2b: + ./pbmtojbg $(OPTIONSP) test-$(IMG).pbm test-$(IMG).jbg + ./jbgtopbm $(OPTIONSJ) test-$(IMG).jbg test-$(IMG)-2.pbm + cmp test-$(IMG).pbm test-$(IMG)-2.pbm + +dotest2g: + ./pbmtojbg $(OPTIONSP) ../examples/$(IMG).pgm test-$(IMG).jbg + ./jbgtopbm $(OPTIONSJ) test-$(IMG).jbg test-$(IMG).pgm + cmp test-$(IMG).pgm ../examples/$(IMG).pgm + +test85: pbmtojbg jbgtopbm pbmtojbg85 jbgtopbm85 test-t82.pbm + make IMG=t82 "OPTIONSP=-p 0" dotest85 + make IMG=t82 "OPTIONSP=-p 8" dotest85 + make IMG=t82 "OPTIONSP=-p 8 -r" dotest85b + make IMG=t82 "OPTIONSP=-p 64" dotest85 + make IMG=t82 "OPTIONSP=-p 72" dotest85 + make IMG=t82 "OPTIONSP=-s 2 -C c" dotest85 + make IMG=t82 "OPTIONSP=-s 99999" dotest85 + make IMG=t82 "OPTIONSP=-Y 9999 0" dotest85 + make IMG=t82 "OPTIONSP=-Y 1951 0" dotest85 + make IMG=t82 "OPTIONSP=-Y -1 127" dotest85 + make IMG=t82 "OPTIONSP=-Y -1 128" dotest85 + make IMG=t82 "OPTIONSP=-Y -1 1919" dotest85 + make IMG=t82 "OPTIONSP=-Y -1 1920" dotest85 + make IMG=t82 "OPTIONSP=-Y -1 1949" dotest85 + make IMG=t82 "OPTIONSP=-Y -1 1950" dotest85 + make IMG=ccitt1 dotest85 + make IMG=ccitt2 dotest85 + make IMG=ccitt3 dotest85 + rm -f test-*.jbg test-*.jbg85 test-*.pbm + @echo + @echo "The T.85 pbmtools have PASSED the functional tests. Good!" + @echo + +dotest85: test-$(IMG).pbm + ./pbmtojbg85 $(OPTIONSP) test-$(IMG).pbm test-$(IMG).jbg85 + ls -l test-$(IMG).jbg85 + ./jbgtopbm test-$(IMG).jbg85 test-$(IMG).pbm85 + cmp test-$(IMG).pbm test-$(IMG).pbm85 + rm test-$(IMG).pbm85 + ./jbgtopbm85 test-$(IMG).jbg85 test-$(IMG).pbm85 + cmp test-$(IMG).pbm test-$(IMG).pbm85 + rm test-$(IMG).pbm85 + ./jbgtopbm85 -B 1 test-$(IMG).jbg85 test-$(IMG).pbm85 + cmp test-$(IMG).pbm test-$(IMG).pbm85 + +dotest85b: test-$(IMG).pbm + ./pbmtojbg -f $(OPTIONSP) test-$(IMG).pbm test-$(IMG).jbg85 + ls -l test-$(IMG).jbg85 + ./jbgtopbm test-$(IMG).jbg85 test-$(IMG).pbm85 + cmp test-$(IMG).pbm test-$(IMG).pbm85 + rm test-$(IMG).pbm85 + ./jbgtopbm85 test-$(IMG).jbg85 test-$(IMG).pbm85 + cmp test-$(IMG).pbm test-$(IMG).pbm85 + rm test-$(IMG).pbm85 + ./jbgtopbm85 -B 1 test-$(IMG).jbg85 test-$(IMG).pbm85 + cmp test-$(IMG).pbm test-$(IMG).pbm85 + +test-%.pbm: ../examples/%.jbg + ./jbgtopbm $< $@ + +test-t82.pbm: + make -C ../libjbig tstcodec + ../libjbig/tstcodec $@ + +FOPT=-c 1000 -p 300000 -m 3 +fuzz: test-t82.pbm + while \ + ./pbmtojbg -f test-t82.pbm | ./jbgfuzz.pl $(FOPT) && \ + ./pbmtojbg test-t82.pbm | ./jbgfuzz.pl $(FOPT) -d jbgtopbm ; \ + do true; done + +.1.txt .5.txt: + groff -man -Tascii -P -c -P -b -P -u $< >$@ + +clean: + rm -f *.o *~ core pbmtojbg jbgtopbm pbmtojbg85 jbgtopbm85 + rm -f test-*.jbg test-*.pbm test-*.pgm test-*.jbg85 test-*.pbm85 + rm -f *.gcda *.gcno *.plist diff --git a/pbmtools/jbgfuzz.pl b/pbmtools/jbgfuzz.pl new file mode 100755 index 0000000..6f366a1 --- /dev/null +++ b/pbmtools/jbgfuzz.pl @@ -0,0 +1,105 @@ +#!/usr/bin/perl +# Simple fuzz tester for JBIG-KIT decoder -- Markus Kuhn +# +# Usage example: +# +# $ ../libjbig/tstcodec t.pbm +# $ ./pbmtojbg -f t.pbm | ./jbgfuzz.pl + +use strict; + +my $fntst = '/tmp/test.jbg'; # fuzz testing file to be generated +my $fntmp = $fntst . '~'; # temporary file (for atomic update) +my $fnvalid = '-'; # valid example BIE file +my $pbmtools = '.'; # location of jbgtopbm and jbgtopbm85 +my $count = "inf"; # how many times shall we try? +my @decoders; + +my $prefix_len = 2000; +my $rnd_suffix_len = 2000; +my $mutation_rate = 10; # percentage of bytes substituted in prefix + +while ($_ = shift @ARGV) { + if ($_ eq '-c') { + $count = shift @ARGV; + } elsif ($_ eq '-m') { + $mutation_rate = shift @ARGV; + } elsif ($_ eq '-p') { + $prefix_len = shift @ARGV; + } elsif ($_ eq '-r') { + $rnd_suffix_len = shift @ARGV; + } elsif ($_ eq '-d') { + push @decoders, shift @ARGV; + } elsif ($_ eq '-t') { + $pbmtools = shift @ARGV; + } else { + $fnvalid = $_; + } +} + +@decoders = ('jbgtopbm', 'jbgtopbm85') unless @decoders; + +# read some bytes from a valid BIE +my $valid_prefix; +my $in; +open($in, "<$fnvalid") || die("$fnvalid: $!\n"); +read $in, $valid_prefix, $prefix_len; +close $in || die("$fnvalid: $!\n"); + +# open a source of random bytes +my $fn_rnd = '/dev/urandom'; +my $rnd; +open($rnd, '<', $fn_rnd) || die; + +for (my $i = 0; $i < $count; $i++) { + my $out; + open($out, '>', $fntmp) || die("$fntmp: $!\n"); + my $prefix; + # randomly substitute some prefix bytes with random bytes + $prefix = $valid_prefix; + if (length($prefix) != $prefix_len) { + warn("Truncating requested $prefix_len byte prefix to available ". + length($prefix)." bytes.\n"); + $prefix_len = length($prefix); + } + #print "\nB: ".join(',', unpack('C4N3C4', substr($prefix, 0, 20)))."\n"; + for (my $p = 0; $p < $prefix_len; $p++) { + if (rand(100) < $mutation_rate) { + substr($prefix, $p, 1) = chr(int(rand(256))); + } + } + #print "A: ".join(',', unpack('C4N3C4', substr($prefix, 0, 20)))."\n"; + # constrain header + my ($dl,$d,$p,$res,$xd,$yd,$l0,$mx,$my,$order,$options,$rest) = + unpack('C4N3C4a*', $prefix); + redo if $xd * $yd > 1e9; # eliminate excessive image sizes + $prefix = pack('C4N3C4a*', $dl,$d,$p,$res,$xd,$yd,$l0,$mx,$my, + $order,$options,$rest); + print $out $prefix; + # append random suffix + my $data; + read $rnd, $data, $rnd_suffix_len; + print $out $data; + close($out) || die("$fntmp: $!\n"); + rename($fntmp, $fntst) || die("mv $fntmp $fntst: $!\n"); + # now feed fuzz input into decoder(s) + for my $jbgtopbm (@decoders) { + printf "%5d: ", $i; + $_ = `$pbmtools/$jbgtopbm $fntst /dev/null 2>&1`; + my $r = $?; + if ($r == 0) { + print "no error encountered\n"; + next; + } elsif ($r == 256) { + my $err; + if (/(\(error code.*\))/) { + $err = $1; + print $err, "\n"; + } else { + die("$_\nno error code found\n"); + } + } else { + die("$_\nreturn value: $r\n"); + } + } +} diff --git a/pbmtools/jbgtopbm.1 b/pbmtools/jbgtopbm.1 new file mode 100644 index 0000000..8da9cf4 --- /dev/null +++ b/pbmtools/jbgtopbm.1 @@ -0,0 +1,118 @@ +.TH JBGTOPBM 1 "2003-06-04" +.SH NAME +jbgtopbm \- JBIG1 to portable bitmap file converter +.SH SYNOPSIS +.B jbgtopbm +[ +.I options +] +[ +.I input-file +| \- [ +.I output-file +]] +.br +.SH DESCRIPTION +Reads in a +.I JBIG1 +bi-level image entity (BIE) from a file or standard +input, decompresses it, and outputs a portable bitmap (PBM) file. + +.I JBIG1 +is a highly effective lossless compression algorithm for +bi-level images (one bit per pixel), which is particularly suitable +for scanned document pages. + +A +.I JBIG1 +encoded image can be stored in several resolutions in one or several +BIEs. All resolution layers except the lowest one are stored +efficiently as differences to the next lower resolution layer. Options +.BI -x +and +.BI -y +can be used to stop the decompression at a specified maximal output +image size. With option +.BI -m +the input file can consist of multiple concatenated BIEs +which contain different increasing resolution layers of the same +image. + +If more than one bit per pixel is stored in the JBIG1 file, then a PGM +file will be produced. +.SH OPTIONS +.TP 14 +.BI \- +A single hyphen instead of an input file name will cause +.I jbgtopbm +to read the data from standard input instead from a file. +.TP +.BI \-x " number" +Decode only up to the largest resolution layer which is still not +more than +.I number +pixels wide. If no such resolution layer exists, then use the smallest +one available. +.TP +.BI \-y " number" +Decode only up to the largest resolution layer which is still not +more than +.I number +pixels high. If no such resolution layer exists, then use the smallest +one available. Options +.BI \-x +and +.BI \-y +can also be used together in which case the largest layer that satisfies +both limits will be selected. +.TP +.BI \-m +Process multiple concatenated BIEs. If there are bytes left after the +final SDE in the first BIE, then with this option +.I jbgtopbm +will attempt to decode these as the start of another BIE that may +contain higher resolution data. Normally, any remaining bytes will +generate a warning message. +.TP +.BI \-b +Use binary values instead of Gray code words in order to decode pixel +values from multiple bitplanes. This option has only an effect if the +input has more than one bitplane and a PGM output file is produced. +Note that the decoder has to be used in the same mode as the encoder +and cannot determine from the BIE, whether Gray or binary code words +were used by the encoder. +.TP +.BI \-d +Diagnose a single BIE. With this option, +.I jbgtopbm +will print a summary of the header information found in the input +file, followed by a list of all PSCD and ESC marker sequences +encountered until the end of the file is reached. +.TP +.BI \-p " number" +If the input contains multiple bitplanes, then extract only the +specified single plane as a PBM file. The first plane has number 0. +.SH BUGS +Using standard input and standard output for binary data works only on +systems where there is no difference between binary and text streams +(e.g., Unix). On other systems (e.g., MS-DOS), using standard input or +standard output may cause control characters like CR or LF to be +inserted or deleted and this will damage the binary data. +.SH STANDARDS +This program implements the +.I JBIG1 +image coding algorithm as specified in ISO/IEC 11544:1993 and +ITU-T T.82(1993). +.SH AUTHOR +The +.I jbgtopbm +program is part of the +.I JBIG-KIT +package, which has been developed by Markus Kuhn. +The most recent version of this +portable +.I JBIG1 +library and tools set is available from +. +.SH SEE ALSO +pbm(5), pgm(5), pbmtojbg(1) diff --git a/pbmtools/jbgtopbm.c b/pbmtools/jbgtopbm.c new file mode 100644 index 0000000..a6a8c78 --- /dev/null +++ b/pbmtools/jbgtopbm.c @@ -0,0 +1,481 @@ +/* + * jbgtopbm - JBIG to Portable Bitmap converter + * + * Markus Kuhn - http://www.cl.cam.ac.uk/~mgk25/jbigkit/ + */ + +#include +#include +#include +#include +#include "jbig.h" + +char *progname; /* global pointer to argv[0] */ + + +/* + * Print usage message and abort + */ +static void usage(void) +{ + fprintf(stderr, "JBIGtoPBM converter " JBG_VERSION " -- " + "reads a bi-level image entity (BIE) as input file\n\n" + "usage: %s [] [ | - []]\n\n" + "options:\n\n", progname); + fprintf(stderr, + " -x number\tif possible decode only up to a resolution layer not\n" + "\t\twider than the given number of pixels\n" + " -y number\tif possible decode only up to a resolution layer not\n" + "\t\thigher than the given number of pixels\n" + " -m\t\tdecode a progressive sequence of multiple concatenated BIEs\n" + " -b\t\tuse binary code for multiple bit planes (default: Gray code)\n" + " -d\t\tdiagnose single BIE, print header, list marker sequences\n" + " -p number\tdecode only one single bit plane (0 = first plane)\n\n"); + exit(1); +} + + +/* + * Call-back routine for merged image output + */ +void write_it(unsigned char *data, size_t len, void *file) +{ + fwrite(data, len, 1, (FILE *) file); +} + +/* + * Remalloc a buffer and append a file f into its content. + * If *buflen == 0, then malloc a buffer first. + */ +void read_file(unsigned char **buf, size_t *buflen, size_t *len, FILE *f) +{ + if (*buflen == 0) { + *buflen = 4000; + *len = 0; + *buf = (unsigned char *) malloc(*buflen); + if (!*buf) { + fprintf(stderr, "Sorry, not enough memory available!\n"); + exit(1); + } + } + do { + *len += fread(*buf + *len, 1, *buflen - *len, f); + if (*len == *buflen) { + *buflen *= 2; + *buf = (unsigned char *) realloc(*buf, *buflen); + if (!*buf) { + fprintf(stderr, "Sorry, not enough memory available!\n"); + exit(1); + } + } + if (ferror(f)) { + perror("Problem while reading input file"); + exit(1); + } + } while (!feof(f)); + *buflen = *len; + *buf = (unsigned char *) realloc(*buf, *buflen); + if (!*buf) { + fprintf(stderr, "Oops, realloc failed when shrinking buffer!\n"); + exit(1); + } + + return; +} + + +/* marker codes */ +#define MARKER_STUFF 0x00 +#define MARKER_SDNORM 0x02 +#define MARKER_SDRST 0x03 +#define MARKER_ABORT 0x04 +#define MARKER_NEWLEN 0x05 +#define MARKER_ATMOVE 0x06 +#define MARKER_COMMENT 0x07 +#define MARKER_ESC 0xff + + +/* + * Output (prefix of) a short byte sequence in hexadecimal + * for diagnostic purposes + */ +void fprint_bytes(FILE *f, unsigned char *p, size_t len, int width) +{ + size_t i; + size_t max = width / 3; + if (len > max) + max -= 7; + for (i = 0; i < len && i < max; i++) + fprintf(f, "%02x ", p[i]); + if (len > i) + fprintf(f, "... %lu bytes total", (unsigned long) len); + fprintf(f, "\n"); +} + +/* + * Read BIE and output human readable description of content + */ +void diagnose_bie(FILE *fin) +{ + unsigned char *bie, *p, *pnext; + size_t buflen = 0, len; + unsigned long xd, yd, l0; + int dl, d; + FILE *f = stdout; + extern unsigned char *jbg_next_pscdms(unsigned char *p, size_t len); + extern unsigned long jbg_stripes(unsigned long l0, unsigned long yd, + unsigned long d); + unsigned long stripes; + int layers, planes; + unsigned long sdes, sde = 0; + + /* read BIH */ + read_file(&bie, &buflen, &len, fin); + if (len < 20) { + fprintf(f, "Error: Input file is %lu < 20 bytes long and therefore " + "does not contain an intact BIE header!\n", (unsigned long) len); + return; + } + + /* parse BIH */ + fprintf(f, "BIH:\n\n DL = %d\n D = %d\n P = %d\n" + " - = %d\n XD = %lu\n YD = %lu\n L0 = %lu\n MX = %d\n" + " MY = %d\n", + dl = bie[0], d = bie[1], planes = bie[2], bie[3], + xd = ((unsigned long)bie[ 4] << 24) | ((unsigned long)bie[ 5] << 16)| + ((unsigned long) bie[ 6] << 8) | ((unsigned long) bie[ 7]), + yd = ((unsigned long)bie[ 8] << 24) | ((unsigned long)bie[ 9] << 16)| + ((unsigned long) bie[10] << 8) | ((unsigned long) bie[11]), + l0 = ((unsigned long)bie[12] << 24) | ((unsigned long)bie[13] << 16)| + ((unsigned long) bie[14] << 8) | ((unsigned long) bie[15]), + bie[16], bie[17]); + fprintf(f, " order = %d %s%s%s%s%s\n", bie[18], + bie[18] & JBG_HITOLO ? " HITOLO" : "", + bie[18] & JBG_SEQ ? " SEQ" : "", + bie[18] & JBG_ILEAVE ? " ILEAVE" : "", + bie[18] & JBG_SMID ? " SMID" : "", + bie[18] & 0xf0 ? " other" : ""); + fprintf(f, " options = %d %s%s%s%s%s%s%s%s\n", bie[19], + bie[19] & JBG_LRLTWO ? " LRLTWO" : "", + bie[19] & JBG_VLENGTH ? " VLENGTH" : "", + bie[19] & JBG_TPDON ? " TPDON" : "", + bie[19] & JBG_TPBON ? " TPBON" : "", + bie[19] & JBG_DPON ? " DPON" : "", + bie[19] & JBG_DPPRIV ? " DPPRIV" : "", + bie[19] & JBG_DPLAST ? " DPLAST" : "", + bie[19] & 0x80 ? " other" : ""); + stripes = jbg_stripes(l0, yd, d); + layers = d - dl + 1; + fprintf(f, "\n %lu stripes, %d layers, %d planes => ", + stripes, layers, planes); + if ((ULONG_MAX / layers) / planes >= stripes) { + sdes = stripes * layers * planes; + fprintf(f, "%lu SDEs\n\n", sdes); + } else { + /* handle integer overflow */ + fprintf(f, ">%lu SDEs!\n", ULONG_MAX); + return; + } + + /* parse BID */ + fprintf(f, "BID:\n\n"); + p = bie + 20; /* skip BIH */ + if ((bie[19] & (JBG_DPON | JBG_DPPRIV | JBG_DPLAST)) + == (JBG_DPON | JBG_DPPRIV)) + p += 1728; /* skip DPTABLE */ + if (p > bie + len) { + fprintf(f, "Error: Input file is %lu < 20+1728 bytes long and therefore " + "does not contain an intact BIE header with DPTABLE!\n", + (unsigned long) len); + return; + } + while (p != bie + len) { + if (p > bie + len - 2) { + fprintf(f, "%06lx: Error: single byte 0x%02x left\n", + (long) (p - bie), *p); + return; + } + pnext = jbg_next_pscdms(p, len - (p - bie)); + if (p[0] != MARKER_ESC || p[1] == MARKER_STUFF) { + fprintf(f, "%06lx: PSCD: ", (long) (p - bie)); + fprint_bytes(f, p, pnext ? (size_t) (pnext - p) : len - (p - bie), 60); + if (!pnext) { + fprintf(f, "Error: PSCD not terminated by SDNORM or SDRST marker\n"); + return; + } + } else + switch (p[1]) { + case MARKER_SDNORM: + case MARKER_SDRST: + fprintf(f, "%06lx: ESC %s, ending SDE #%lu", (long) (p - bie), + (p[1] == MARKER_SDNORM) ? "SDNORM" : "SDRST", ++sde); + if (sde == sdes) + fprintf(f, " (final SDE)"); + else if (sde == sdes + 1) + fprintf(f, " (first surplus SDE, VLENGTH = %d)", + (bie[19] & JBG_VLENGTH) > 0); + fprintf(f, "\n"); + break; + case MARKER_ABORT: + fprintf(f, "%06lx: ESC ABORT\n", (long) (p - bie)); + break; + case MARKER_NEWLEN: + fprintf(f, "%06lx: ESC NEWLEN ", (long) (p - bie)); + if (p + 5 < bie + len) { + fprintf(f, "YD = %lu\n", + yd = (((long) p[2] << 24) | ((long) p[3] << 16) | + ((long) p[4] << 8) | (long) p[5])); + stripes = jbg_stripes(l0, yd, d); + fprintf(f, " %lu stripes, %d layers, %d planes => ", + stripes, layers, planes); + if ((ULONG_MAX / layers) / planes >= stripes) { + sdes = stripes * layers * planes; + fprintf(f, "%lu SDEs\n", sdes); + } else { + /* handle integer overflow */ + fprintf(f, ">%lu SDEs!\n", ULONG_MAX); + return; + } + } else + fprintf(f, "unexpected EOF\n"); + break; + case MARKER_ATMOVE: + fprintf(f, "%06lx: ESC ATMOVE ", (long) (p - bie)); + if (p + 7 < bie + len) + fprintf(f, "YAT = %lu, tX = %d, tY = %d\n", + (((long) p[2] << 24) | ((long) p[3] << 16) | + ((long) p[4] << 8) | (long) p[5]), p[6], p[7]); + else + fprintf(f, "unexpected EOF\n"); + break; + case MARKER_COMMENT: + fprintf(f, "%06lx: ESC COMMENT ", (long) (p - bie)); + if (p + 5 < bie + len) + fprintf(f, "LC = %lu\n", + (((long) p[2] << 24) | ((long) p[3] << 16) | + ((long) p[4] << 8) | (long) p[5])); + else + fprintf(f, "unexpected EOF\n"); + break; + default: + fprintf(f, "%06lx: ESC 0x%02x\n", (long) (p - bie), p[1]); + } + if (!pnext) { + fprintf(f, "Error encountered!\n"); + return; + } + p = pnext; + } + + free(bie); + + return; +} + + +int main (int argc, char **argv) +{ + FILE *fin = stdin, *fout = stdout; + const char *fnin = NULL, *fnout = NULL; + int i, j, result; + int all_args = 0, files = 0; + struct jbg_dec_state s; + unsigned char *buffer, *p; + size_t buflen, len, cnt; + size_t bytes_read = 0; + unsigned long xmax = 4294967295UL, ymax = 4294967295UL, max; + int plane = -1, use_graycode = 1, diagnose = 0, multi = 0; + + buflen = 8000; + buffer = (unsigned char *) malloc(buflen); + if (!buffer) { + printf("Sorry, not enough memory available!\n"); + exit(1); + } + + /* parse command line arguments */ + progname = argv[0]; + for (i = 1; i < argc; i++) { + if (!all_args && argv[i][0] == '-') + if (argv[i][1] == 0) { + if (files++) usage(); + } else + for (j = 1; j > 0 && argv[i][j]; j++) + switch(argv[i][j]) { + case '-' : + all_args = 1; + break; + case 'b': + use_graycode = 0; + break; + case 'm': + multi = 1; + break; + case 'd': + diagnose = 1; + break; + case 'x': + if (++i >= argc) usage(); + xmax = atol(argv[i]); + j = -1; + break; + case 'y': + if (++i >= argc) usage(); + ymax = atol(argv[i]); + j = -1; + break; + case 'p': + if (++i >= argc) usage(); + plane = atoi(argv[i]); + j = -1; + break; + default: + usage(); + } + else + switch (files++) { + case 0: fnin = argv[i]; break; + case 1: fnout = argv[i]; break; + default: + usage(); + } + } + + if (fnin) { + fin = fopen(fnin, "rb"); + if (!fin) { + fprintf(stderr, "Can't open input file '%s", fnin); + perror("'"); + exit(1); + } + } else + fnin = ""; + if (diagnose) { + diagnose_bie(fin); + exit(0); + } + if (fnout) { + fout = fopen(fnout, "wb"); + if (!fout) { + fprintf(stderr, "Can't open input file '%s", fnout); + perror("'"); + exit(1); + } + } else + fnout = ""; + + /* send input file to decoder */ + jbg_dec_init(&s); + jbg_dec_maxsize(&s, xmax, ymax); + /* read BIH first to check VLENGTH */ + len = fread(buffer, 1, 20, fin); + if (len < 20) { + fprintf(stderr, "Input file '%s' (%lu bytes) must be at least " + "20 bytes long\n", fnin, (unsigned long) len); + if (fout != stdout) { + fclose(fout); + remove(fnout); + } + exit(1); + } + if (buffer[19] & JBG_VLENGTH) { + /* VLENGTH = 1 => we might encounter a NEWLEN, therefore read entire + * input file into memory and run two passes over it */ + read_file(&buffer, &buflen, &len, fin); + /* scan for NEWLEN marker segments and update BIE header accordingly */ + result = jbg_newlen(buffer, len); + /* feed data to decoder */ + if (result == JBG_EOK) { + p = (unsigned char *) buffer; + result = JBG_EAGAIN; + while (len > 0 && + (result == JBG_EAGAIN || (result == JBG_EOK && multi))) { + result = jbg_dec_in(&s, p, len, &cnt); + p += cnt; + len -= cnt; + bytes_read += cnt; + } + } + } else { + /* VLENGTH = 0 => we can simply pass the input file directly to decoder */ + result = JBG_EAGAIN; + do { + cnt = 0; + p = (unsigned char *) buffer; + while (len > 0 && + (result == JBG_EAGAIN || (result == JBG_EOK && multi))) { + result = jbg_dec_in(&s, p, len, &cnt); + p += cnt; + len -= cnt; + bytes_read += cnt; + } + if (!(result == JBG_EAGAIN || (result == JBG_EOK && multi))) + break; + len = fread(buffer, 1, buflen, fin); + } while (len > 0); + if (ferror(fin)) { + fprintf(stderr, "Problem while reading input file '%s", fnin); + perror("'"); + if (fout != stdout) { + fclose(fout); + remove(fnout); + } + exit(1); + } + } + if (result != JBG_EOK && result != JBG_EOK_INTR) { + fprintf(stderr, "Problem with input file '%s': %s\n" + "(error code 0x%02x, %lu = 0x%04lx BIE bytes processed)\n", + fnin, jbg_strerror(result), result, + (unsigned long) bytes_read, (unsigned long) bytes_read); + if (fout != stdout) { + fclose(fout); + remove(fnout); + } + exit(1); + } + if (plane >= 0 && jbg_dec_getplanes(&s) <= plane) { + fprintf(stderr, "Image has only %d planes!\n", jbg_dec_getplanes(&s)); + if (fout != stdout) { + fclose(fout); + remove(fnout); + } + exit(1); + } + + if (jbg_dec_getplanes(&s) == 1 || plane >= 0) { + /* write PBM output file */ + fprintf(fout, "P4\n%10lu\n%10lu\n", jbg_dec_getwidth(&s), + jbg_dec_getheight(&s)); + fwrite(jbg_dec_getimage(&s, plane < 0 ? 0 : plane), 1, + jbg_dec_getsize(&s), fout); + } else { + /* write PGM output file */ + if ((size_t) jbg_dec_getplanes(&s) > sizeof(unsigned long) * 8) { + fprintf(stderr, "Image has too many planes (%d)!\n", + jbg_dec_getplanes(&s)); + if (fout != stdout) { + fclose(fout); + remove(fnout); + } + exit(1); + } + max = 0; + for (i = jbg_dec_getplanes(&s); i > 0; i--) + max = (max << 1) | 1; + fprintf(fout, "P5\n%10lu\n%10lu\n%lu\n", jbg_dec_getwidth(&s), + jbg_dec_getheight(&s), max); + jbg_dec_merge_planes(&s, use_graycode, write_it, fout); + } + + /* check for file errors and close fout */ + if (ferror(fout) || fclose(fout)) { + fprintf(stderr, "Problem while writing output file '%s", fnout); + perror("'"); + exit(1); + } + + jbg_dec_free(&s); + + return 0; +} diff --git a/pbmtools/jbgtopbm.txt b/pbmtools/jbgtopbm.txt new file mode 100644 index 0000000..d9d0ca2 --- /dev/null +++ b/pbmtools/jbgtopbm.txt @@ -0,0 +1,93 @@ +JBGTOPBM(1) JBGTOPBM(1) + + + +NAME + jbgtopbm - JBIG1 to portable bitmap file converter + +SYNOPSIS + jbgtopbm [ options ] [ input-file | - [ output-file ]] + +DESCRIPTION + Reads in a JBIG1 bi-level image entity (BIE) from a file or standard + input, decompresses it, and outputs a portable bitmap (PBM) file. + + JBIG1 is a highly effective lossless compression algorithm for bi-level + images (one bit per pixel), which is particularly suitable for scanned + document pages. + + A JBIG1 encoded image can be stored in several resolutions in one or + several BIEs. All resolution layers except the lowest one are stored + efficiently as differences to the next lower resolution layer. Options + -x and -y can be used to stop the decompression at a specified maximal + output image size. With option -m the input file can consist of multi- + ple concatenated BIEs which contain different increasing resolution + layers of the same image. + + If more than one bit per pixel is stored in the JBIG1 file, then a PGM + file will be produced. + +OPTIONS + - A single hyphen instead of an input file name will cause + jbgtopbm to read the data from standard input instead + from a file. + + -x number Decode only up to the largest resolution layer which is + still not more than number pixels wide. If no such reso- + lution layer exists, then use the smallest one available. + + -y number Decode only up to the largest resolution layer which is + still not more than number pixels high. If no such reso- + lution layer exists, then use the smallest one available. + Options -x and -y can also be used together in which case + the largest layer that satisfies both limits will be + selected. + + -m Process multiple concatenated BIEs. If there are bytes + left after the final SDE in the first BIE, then with this + option jbgtopbm will attempt to decode these as the start + of another BIE that may contain higher resolution data. + Normally, any remaining bytes will generate a warning + message. + + -b Use binary values instead of Gray code words in order to + decode pixel values from multiple bitplanes. This option + has only an effect if the input has more than one bit- + plane and a PGM output file is produced. Note that the + decoder has to be used in the same mode as the encoder + and cannot determine from the BIE, whether Gray or binary + code words were used by the encoder. + + -d Diagnose a single BIE. With this option, jbgtopbm will + print a summary of the header information found in the + input file, followed by a list of all PSCD and ESC marker + sequences encountered until the end of the file is + reached. + + -p number If the input contains multiple bitplanes, then extract + only the specified single plane as a PBM file. The first + plane has number 0. + +BUGS + Using standard input and standard output for binary data works only on + systems where there is no difference between binary and text streams + (e.g., Unix). On other systems (e.g., MS-DOS), using standard input or + standard output may cause control characters like CR or LF to be + inserted or deleted and this will damage the binary data. + +STANDARDS + This program implements the JBIG1 image coding algorithm as specified + in ISO/IEC 11544:1993 and ITU-T T.82(1993). + +AUTHOR + The jbgtopbm program is part of the JBIG-KIT package, which has been + developed by Markus Kuhn. The most recent version of this portable + JBIG1 library and tools set is available from + . + +SEE ALSO + pbm(5), pgm(5), pbmtojbg(1) + + + + 2003-06-04 JBGTOPBM(1) diff --git a/pbmtools/jbgtopbm85.c b/pbmtools/jbgtopbm85.c new file mode 100644 index 0000000..9bce587 --- /dev/null +++ b/pbmtools/jbgtopbm85.c @@ -0,0 +1,205 @@ +/* + * jbgtopbm85 - JBIG to Portable Bitmap converter (T.85 version) + * + * Markus Kuhn - http://www.cl.cam.ac.uk/~mgk25/jbigkit/ + */ + +#include +#include +#include +#include +#include "jbig85.h" + +char *progname; /* global pointer to argv[0] */ +unsigned long y_0; +fpos_t ypos; +int ypos_error = 1; +unsigned long ymax = 0; + +/* + * Print usage message and abort + */ +static void usage(void) +{ + fprintf(stderr, "JBIGtoPBM converter " JBG85_VERSION " (T.85 version) --\n" + "reads a bi-level image entity (BIE) as input file\n\n" + "usage: %s [ | - []]\n\n", progname); + fprintf(stderr, "options:\n\n" + " -x number\tmaximum number of pixels per line for which memory\n" + "\t\tis allocated (default: 8192)\n" + " -y number\tinterrupt decoder after this number of lines\n" + " -B number\tinput buffer size\n\n"); + exit(1); +} + + +/* + * Call-back routine for merged image output + */ +int line_out(const struct jbg85_dec_state *s, + unsigned char *start, size_t len, unsigned long y, void *file) +{ + if (y == 0) { + /* prefix first line with PBM header */ + fprintf((FILE *) file, "P4\n"); + fprintf((FILE *) file, "%10lu\n", jbg85_dec_getwidth(s)); + /* store file position of height, so we can update it after NEWLEN */ + y_0 = jbg85_dec_getheight(s); + ypos_error = fgetpos((FILE *) file, &ypos); + fprintf((FILE *) file, "%10lu\n", y_0); /* pad number to 10 bytes */ + } + fwrite(start, len, 1, (FILE *) file); + return y == ymax - 1; +} + + +int main (int argc, char **argv) +{ + FILE *fin = stdin, *fout = stdout; + const char *fnin = NULL, *fnout = NULL; + int i, j, result; + int all_args = 0, files = 0; + struct jbg85_dec_state s; + unsigned char *inbuf, *outbuf; + size_t inbuflen = 8192, outbuflen, len, cnt, cnt2; + unsigned long xmax = 8192; + size_t bytes_read = 0; + + /* parse command line arguments */ + progname = argv[0]; + for (i = 1; i < argc; i++) { + if (!all_args && argv[i][0] == '-') + if (argv[i][1] == 0) { + if (files++) usage(); + } else + for (j = 1; j > 0 && argv[i][j]; j++) + switch(argv[i][j]) { + case '-' : + all_args = 1; + break; + case 'x': + if (++i >= argc) usage(); + j = -1; + xmax = atol(argv[i]); + break; + case 'y': + if (++i >= argc) usage(); + j = -1; + ymax = atol(argv[i]); + break; + case 'B': + if (++i >= argc) usage(); + j = -1; + inbuflen = atol(argv[i]); + if (inbuflen < 1) usage(); + break; + default: + usage(); + } + else + switch (files++) { + case 0: fnin = argv[i]; break; + case 1: fnout = argv[i]; break; + default: + usage(); + } + } + + inbuf = (unsigned char *) malloc(inbuflen); + outbuflen = ((xmax >> 3) + !!(xmax & 7)) * 3; + outbuf = (unsigned char *) malloc(outbuflen); + if (!inbuf || !outbuf) { + printf("Sorry, not enough memory available!\n"); + exit(1); + } + + if (fnin) { + fin = fopen(fnin, "rb"); + if (!fin) { + fprintf(stderr, "Can't open input file '%s", fnin); + perror("'"); + exit(1); + } + } else + fnin = ""; + if (fnout) { + fout = fopen(fnout, "wb"); + if (!fout) { + fprintf(stderr, "Can't open input file '%s", fnout); + perror("'"); + exit(1); + } + } else + fnout = ""; + + /* send input file to decoder */ + jbg85_dec_init(&s, outbuf, outbuflen, line_out, fout); + result = JBG_EAGAIN; + while ((len = fread(inbuf, 1, inbuflen, fin))) { + result = jbg85_dec_in(&s, inbuf, len, &cnt); + bytes_read += cnt; + while (result == JBG_EOK_INTR) { + /* demonstrate decoder interrupt at given line number */ + printf("Decoding interrupted after %lu lines and %lu BIE bytes " + "... continuing ...\n", s.y, (unsigned long) bytes_read); + /* and now continue decoding */ + result = jbg85_dec_in(&s, inbuf + cnt, len - cnt, &cnt2); + bytes_read += cnt2; + cnt += cnt2; + } + if (result != JBG_EAGAIN) + break; + } + if (ferror(fin)) { + fprintf(stderr, "Problem while reading input file '%s", fnin); + perror("'"); + if (fout != stdout) { + fclose(fout); + remove(fnout); + } + exit(1); + } + if (result == JBG_EAGAIN || result == JBG_EOK_INTR) { + /* signal end-of-BIE explicitely */ + result = jbg85_dec_end(&s); + while (result == JBG_EOK_INTR) { + /* demonstrate decoder interrupt at given line number */ + printf("Decoding interrupted after %lu lines and %lu BIE bytes " + "... continuing ...\n", s.y, (unsigned long) bytes_read); + result = jbg85_dec_end(&s); + } + } + if (result != JBG_EOK) { + fprintf(stderr, "Problem with input file '%s': %s\n" + "(error code 0x%02x, %lu = 0x%04lx BIE bytes " + "and %lu pixel rows processed)\n", + fnin, jbg85_strerror(result), result, + (unsigned long) bytes_read, (unsigned long) bytes_read, s.y); + if (fout != stdout) { + fclose(fout); + /*remove(fnout);*/ + } + exit(1); + } + + /* do we have to update the image height in the PBM header? */ + if (!ypos_error && y_0 != jbg85_dec_getheight(&s)) { + if (fsetpos(fout, &ypos) == 0) { + fprintf(fout, "%10lu", jbg85_dec_getheight(&s)); /* pad to 10 bytes */ + } else { + fprintf(stderr, "Problem while updating height in output file '%s", + fnout); + perror("'"); + exit(1); + } + } + + /* check for file errors and close fout */ + if (ferror(fout) || fclose(fout)) { + fprintf(stderr, "Problem while writing output file '%s", fnout); + perror("'"); + exit(1); + } + + return 0; +} diff --git a/pbmtools/pbm.5 b/pbmtools/pbm.5 new file mode 100644 index 0000000..9b46dc0 --- /dev/null +++ b/pbmtools/pbm.5 @@ -0,0 +1,91 @@ +.TH pbm 5 "27 September 1991" +.SH NAME +pbm - portable bitmap file format +.SH DESCRIPTION +The portable bitmap format is a lowest common denominator monochrome +file format. +.IX "PBM file format" +It was originally designed to make it reasonable to mail bitmaps +between different types of machines using the typical stupid network +mailers we have today. +Now it serves as the common language of a large family of bitmap +conversion filters. +The definition is as follows: +.IP - 2 +A "magic number" for identifying the file type. +A pbm file's magic number is the two characters "P1". +.IX "magic numbers" +.IP - 2 +Whitespace (blanks, TABs, CRs, LFs). +.IP - 2 +A width, formatted as ASCII characters in decimal. +.IP - 2 +Whitespace. +.IP - 2 +A height, again in ASCII decimal. +.IP - 2 +Whitespace. +.IP - 2 +Width * height bits, each either '1' or '0', starting at the top-left +corner of the bitmap, proceeding in normal English reading order. +.IP - 2 +The character '1' means black, '0' means white. +.IP - 2 +Whitespace in the bits section is ignored. +.IP - 2 +Characters from a "#" to the next end-of-line are ignored (comments). +.IP - 2 +No line should be longer than 70 characters. +.PP +Here is an example of a small bitmap in this format: +.nf +P1 +# feep.pbm +24 7 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 +0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 +0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 1 0 +0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 +0 1 0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +.fi +.PP +Programs that read this format should be as lenient as possible, +accepting anything that looks remotely like a bitmap. +.PP +There is also a variant on the format, available +by setting the RAWBITS option at compile time. This variant is +.IX RAWBITS +different in the following ways: +.IP - 2 +The "magic number" is "P4" instead of "P1". +.IP - 2 +The bits are stored eight per byte, high bit first low bit last. +.IP - 2 +No whitespace is allowed in the bits section, and only a single character +of whitespace (typically a newline) is allowed after the height. +.IP - 2 +The files are eight times smaller and many times faster to read and write. +.SH "SEE ALSO" +atktopbm(1), brushtopbm(1), cmuwmtopbm(1), g3topbm(1), +gemtopbm(1), icontopbm(1), +macptopbm(1), mgrtopbm(1), pi3topbm(1), xbmtopbm(1), +ybmtopbm(1), +pbmto10x(1), pnmtoascii(1), pbmtoatk(1), pbmtobbnbg(1), +pbmtocmuwm(1), pbmtoepson(1), +pbmtog3(1), pbmtogem(1), pbmtogo(1), pbmtoicon(1), pbmtolj(1), +pbmtomacp(1), pbmtomgr(1), pbmtopi3(1), pbmtoplot(1), pbmtoptx(1), +pbmtox10bm(1), pbmtoxbm(1), pbmtoybm(1), +pbmtozinc(1), +pbmlife(1), pbmmake(1), pbmmask(1), pbmreduce(1), +pbmtext(1), pbmupc(1), +pnm(5), pgm(5), ppm(5) +.SH AUTHOR +Copyright (C) 1989, 1991 by Jef Poskanzer. +.\" Permission to use, copy, modify, and distribute this software and its +.\" documentation for any purpose and without fee is hereby granted, provided +.\" that the above copyright notice appear in all copies and that both that +.\" copyright notice and this permission notice appear in supporting +.\" documentation. This software is provided "as is" without express or +.\" implied warranty. diff --git a/pbmtools/pbm.txt b/pbmtools/pbm.txt new file mode 100644 index 0000000..bed561e --- /dev/null +++ b/pbmtools/pbm.txt @@ -0,0 +1,85 @@ +pbm(5) pbm(5) + + + +NAME + pbm - portable bitmap file format + +DESCRIPTION + The portable bitmap format is a lowest common denominator monochrome + file format. It was originally designed to make it reasonable to mail + bitmaps between different types of machines using the typical stupid + network mailers we have today. Now it serves as the common language of + a large family of bitmap conversion filters. The definition is as fol- + lows: + + - A "magic number" for identifying the file type. A pbm file's magic + number is the two characters "P1". + + - Whitespace (blanks, TABs, CRs, LFs). + + - A width, formatted as ASCII characters in decimal. + + - Whitespace. + + - A height, again in ASCII decimal. + + - Whitespace. + + - Width * height bits, each either '1' or '0', starting at the top-left + corner of the bitmap, proceeding in normal English reading order. + + - The character '1' means black, '0' means white. + + - Whitespace in the bits section is ignored. + + - Characters from a "#" to the next end-of-line are ignored (comments). + + - No line should be longer than 70 characters. + + Here is an example of a small bitmap in this format: + P1 + # feep.pbm + 24 7 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 + 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 + 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 1 0 + 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 + 0 1 0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + + Programs that read this format should be as lenient as possible, + accepting anything that looks remotely like a bitmap. + + There is also a variant on the format, available by setting the RAWBITS + option at compile time. This variant is different in the following + ways: + + - The "magic number" is "P4" instead of "P1". + + - The bits are stored eight per byte, high bit first low bit last. + + - No whitespace is allowed in the bits section, and only a single char- + acter of whitespace (typically a newline) is allowed after the + height. + + - The files are eight times smaller and many times faster to read and + write. + +SEE ALSO + atktopbm(1), brushtopbm(1), cmuwmtopbm(1), g3topbm(1), gemtopbm(1), + icontopbm(1), macptopbm(1), mgrtopbm(1), pi3topbm(1), xbmtopbm(1), ybm- + topbm(1), pbmto10x(1), pnmtoascii(1), pbmtoatk(1), pbmtobbnbg(1), pbm- + tocmuwm(1), pbmtoepson(1), pbmtog3(1), pbmtogem(1), pbmtogo(1), pbmto- + icon(1), pbmtolj(1), pbmtomacp(1), pbmtomgr(1), pbmtopi3(1), pbmto- + plot(1), pbmtoptx(1), pbmtox10bm(1), pbmtoxbm(1), pbmtoybm(1), pbmtoz- + inc(1), pbmlife(1), pbmmake(1), pbmmask(1), pbmreduce(1), pbmtext(1), + pbmupc(1), pnm(5), pgm(5), ppm(5) + +AUTHOR + Copyright (C) 1989, 1991 by Jef Poskanzer. + + + + 27 September 1991 pbm(5) diff --git a/pbmtools/pbmtojbg.1 b/pbmtools/pbmtojbg.1 new file mode 100644 index 0000000..c1c63cd --- /dev/null +++ b/pbmtools/pbmtojbg.1 @@ -0,0 +1,276 @@ +.TH PBMTOJBG 1 "2003-06-04" +.SH NAME +pbmtojbg \- portable bitmap to JBIG1 file converter +.SH SYNOPSIS +.B pbmtojbg +[ +.I options +] +[ +.I input-file +| \- [ +.I output-file +]] +.br +.SH DESCRIPTION +Reads in a portable bitmap (PBM) +from a file or standard +input, compresses it, and outputs the image as a +.I JBIG1 +bi-level image entity (BIE) file. + +.I JBIG1 +is a highly effective lossless compression algorithm for +bi-level images (one bit per pixel), which is particularly suitable +for scanned document pages. + +A +.I JBIG1 +encoded image can be stored in several resolutions (progressive mode). +These resolution layers can be stored all in one single BIE or they +can be stored in several separate BIE files. +All resolution layers except the lowest one are stored merely as +differences to the next lower resolution layer, because this requires less +space than encoding the full image completely every time. Each resolution +layer has twice the number of horizontal and vertical pixels than +the next lower layer. +.I JBIG1 +files can also store several bits per pixel as separate bitmap planes, +and +.I pbmtojbg +can read a PGM file and transform it into a multi-bitplane BIE. + +.SH OPTIONS +.TP 14 +.BI \- +A single hyphen instead of an input file name will cause +.I pbmtojbg +to read the data from standard input instead from a file. +.TP +.BI \-q +Encode the image in one single resolution layer (sequential mode). This +is usually the most efficient compression method. By default, the number +of resolution layers is chosen automatically such that the lowest layer +image is not larger than 640 \(mu 480 pixels. This is a shortcut for +.BR "-d 0" . +.TP +.BI \-x " number" +Specify the maximal horizontal size of the lowest resolution layer. +The default is 640 pixels. +.TP +.BI \-y " number" +Specify the maximal vertical size of the lowest resolution layer. +The default is 480 pixels. +.TP +.BI \-l " number" +Select the lowest resolution layer that will be written to the +BIE. It is possible to store the various resolution layers of a +.I JBIG1 +image in progressive mode into different BIEs. Options +.B \-l +and +.B \-h +allow to select the resolution-layer interval that will appear +in the created BIE. The lowest resolution layer has number 0 and +this is also the default value. By default all layers will be written. +.TP +.BI \-h " number" +Select the highest resolution layer that will be written to the +BIE. By default all layers will be written. See also option +.BR \-l . +.TP +.BI \-b +Use binary values instead of Gray code words in order to encode pixel +values in multiple bitplanes. This option has only an effect if the +input is a PGM file and if more than one bitplane is produced. Note +that the decoder has to make the same selection but cannot determine +from the BIE, whether Gray or binary code words were used by the +encoder. +.TP +.BI \-d " number" +Specify the total number of differential resolution layers into which the +input image will be split in addition to the lowest layer. Each additional +layer reduces the size of layer 0 by 50 %. This option overrides options +.BI \-x +and +.BI \-y +which are usually a more comfortable way of selecting the number of +resolution layers. +.TP +.BI \-s " number" +The +.I JBIG1 +algorithm splits each image into a number of horizontal stripes. This +option specifies that each stripe shall have +.I number +lines in layer 0. The default value is selected so that approximately +35 stripes will be used for the whole image. +.TP +.BI \-m " number" +Select the maximum horizontal offset of the adaptive template pixel. +The +.I JBIG1 +encoder uses ten neighbour pixels to estimate the probability of the +next pixel being black or white. It can move one out of these ten +pixels. This is especially useful for dithered images, as long as the +distance of this adaptive pixel can be adjusted to the period of the +dither pattern. By default, the adaptive template pixel is allowed to +move up to 8 pixels away horizontally. This encoder supports distances +up to 127 pixels. Annex A of the standard suggests that decoders +should support at least a horizontal distance of 16 pixels, so using +values not higher than 16 for +.I number +might increase the chances of interoperability with other +.I JBIG1 +implementations. On the other hand, the T.85 fax application profile +requires decoders to support horizontal offsets up to 127 pixels, +which the maximum value permitted by the standard. (The maximal +vertical offset of the adaptive template pixel is always zero for this +encoder.) +.TP +.BI \-t " number" +Encode only the specified number of most significant bit planes. This +option allows to reduce the depth of an input PGM file if not all +bits per pixel are needed in the output. +.TP +.BI \-o " number" +.I JBIG1 +separates an image into several horizontal stripes, resolution layers +and planes, were each plane contains one bit per pixel. One single +stripe in one plane and layer is encoded as a data unit called stripe +data entity (SDE) inside the BIE. There are 12 different possible +orders in which the SDEs can be stored inside the BIE and +.I number +selects which one shall be used. The order of the SDEs is only relevant +for applications that want to decode a +.I JBIG1 +file which has not yet completely arrived from e.g. a slow network connection. +For instance some applications prefer that the outermost of the three loops +(stripes, layers, planes) is over all layers so that all data of the lowest +resolution layer is transmitted first. +.br +The following values for +.I number +select these loop arrangements for writing the SDEs (outermost +loop first): + + 0 planes, layers, stripes +.br + 2 layers, planes, stripes +.br + 3 layers, stripes, planes +.br + 4 stripes, planes, layers +.br + 5 planes, stripes, layers +.br + 6 stripes, layers, planes + +All loops count starting with zero, however by adding 8 to the above +order code, the layer loop can be reversed so that it counts down to zero +and then higher resolution layers will be stored before lower layers. +Default order is 3 which writes at first all planes of the first +stripe and then completes layer 0 before continuing with the next +layer and so on. +.TP +.BI \-p " number" +This option allows to activate or deactivate various optional algorithms +defined in the +.I JBIG1 +standard. Just add the numbers of the following options which you want to +activate in +order to get the +.I number +value: + + 4 deterministic prediction (DPON) +.br + 8 layer 0 typical prediction (TPBON) +.br + 16 diff. layer typ. pred. (TPDON) +.br + 64 layer 0 two-line template (LRLTWO) + +Except for special applications (like communication with +.I JBIG1 +subset implementations) and for debugging purposes you will normally +not want to change anything here. The default is 28, which provides +the best compression result. +.TP +.BI \-C " string" +Add the +.I string +in a comment marker segment to the produced data stream. (There is no +support at present for adding comments that contain the zero byte.) +.TP +.BI \-c +Determine the adaptive template pixel movement as suggested in annex C +of the standard. By default the template change takes place directly +in the next line, which is most effective. However, a few conformance +test examples in the standard require the adaptive template change to +be delayed until the first line of the next stripe. This option +selects this special behavior, which is normally not required except +in order to pass some conformance tests. +.TP +.BI \-r +Use the SDRST marker instead of the normal SDNORM marker. The probably +only useful application of this option is to generate test data for +checking whether a +.I JBIG1 +decoder has implemented SDRST correctly. In a normal +.I JBIG1 +data stream, each stripe data entity (SDE) is terminated by an SDNORM +marker, which preserves the state of the arithmetic encoder (and more) +for the next stripe in the same layer. The alternative SDRST marker +resets this state at the end of the stripe. +.TP +.BI \-Y " number" +A long time ago, there were fax machines that couldn't even hold a +single page in memory. They had to start transmitting data before the +page was scanned in completely and the length of the image was known. +The authors of the standard added a rather ugly hack to the otherwise +beautiful JBIG1 format to support this. The NEWLEN marker segment can +override the image height stated in the BIE header anywhere later in +the data stream. Normally +.I pbmtojbg +never generates NEWLEN marker segments, as it knows the correct image +height when it outputs the header. This option is solely intended for +the purpose of generating test files with NEWLEN marker segments. It +can be used to specify a higher initial image height for use in the +BIE header, and +.I pbmtojbg +will then add a NEWLEN marker segment at the latest possible +opportunity to the data stream to signal the correct final height. +.TP +.BI \-f +This option makes the output file comply to the "facsimile application +profile" defined in ITU-T Recommendation T.85. It is a shortcut for +.BR "-q -o 0 -p 8 -s 128 -t 1 -m 127" . +.TP +.BI \-v +After the BIE has been created, a few technical details of the created +file will be listed (verbose mode). +.SH BUGS +Using standard input and standard output for binary data works only on +systems where there is no difference between binary and text streams +(e.g., Unix). On other systems (e.g., MS-DOS), using standard input or +standard output may cause control characters like CR or LF to be +inserted or deleted and this will damage the binary data. +.SH STANDARDS +This program implements the +.I JBIG1 +image coding algorithm as specified in ISO/IEC 11544:1993 and +ITU-T T.82(1993). +.SH AUTHOR +The +.I pbmtojbg +program is part of the +.I JBIG-KIT +package, which has been developed by Markus Kuhn. +The most recent version of this +portable +.I JBIG1 +library and tools set is available from +. +.SH SEE ALSO +pbm(5), pgm(5), jbgtopbm(1) diff --git a/pbmtools/pbmtojbg.c b/pbmtools/pbmtojbg.c new file mode 100644 index 0000000..90c4581 --- /dev/null +++ b/pbmtools/pbmtojbg.c @@ -0,0 +1,433 @@ +/* + * pbmtojbg - Portable Bitmap to JBIG converter + * + * Markus Kuhn - http://www.cl.cam.ac.uk/~mgk25/jbigkit/ + */ + +#include +#include +#include +#include +#include "jbig.h" + + +char *progname; /* global pointer to argv[0] */ +unsigned long total_length = 0; /* used for determining output file length */ + + +/* + * Print usage message and abort + */ +static void usage(void) +{ + fprintf(stderr, + "PBMtoJBIG converter " JBG_VERSION " -- " + "creates bi-level image entity (BIE) as output file\n\n" + "usage: %s [] [ | - []]\n\n" + "options:\n\n", progname); + fprintf(stderr, + " -q\t\tsequential coding, no differential layers (like -d 0)\n" + " -x number\tmaximum width of lowest resolution layer (default 640)\n" + " -y number\tmaximum height of lowest resolution layer (default 480)\n" + " -l number\tlowest layer written to output file (default 0)\n" + " -h number\thighest layer written to output file (default max)\n" + " -b\t\tuse binary code for multiple bitplanes (default: Gray code)\n" + " -d number\ttotal number of differential layers (overrides -x and -y)\n" + " -s number\theight of a stripe in layer 0\n"); + fprintf(stderr, + " -m number\tmaximum adaptive template pixel horizontal offset (default 8)\n" + " -t number\tencode only that many most significant planes\n" + " -o number\torder byte value: add 1=SMID, 2=ILEAVE, 4=SEQ, 8=HITOLO\n" + "\t\t(default 3 = ILEAVE+SMID)\n" + " -p number\toptions byte value: add DPON=4, TPBON=8, TPDON=16, LRLTWO=64\n" + "\t\t(default 28 = DPON+TPBON+TPDON)\n"); + fprintf(stderr, + " -C string\tadd the provided string as a comment marker segment\n" + " -c\t\tdelay adaptive template changes to first line of next stripe\n" + "\t\t(only provided for a conformance test)\n" + " -r\t\tterminate each stripe with SDRST marker\n" + "\t\t(only intended for decoder testing)\n" ); + fprintf(stderr, + " -Y number\tannounce in header initially this larger image height\n" + "\t\t(only for generating test files with NEWLEN and VLENGTH=1)\n" + " -f\t\tchose encoding options for T.85 fax profile complianance\n" + " -v\t\tverbose output\n\n"); + exit(1); +} + + +/* + * malloc() with exception handler + */ +void *checkedmalloc(size_t n) +{ + void *p; + + if ((p = malloc(n)) == NULL) { + fprintf(stderr, "Sorry, not enough memory available!\n"); + exit(1); + } + + return p; +} + + +/* + * Read an ASCII integer number from file f and skip any PBM + * comments which are encountered. + */ +static unsigned long getint(FILE *f) +{ + int c; + unsigned long i; + + while ((c = getc(f)) != EOF && !isdigit(c)) + if (c == '#') + while ((c = getc(f)) != EOF && !(c == 13 || c == 10)) ; + if (c != EOF) { + ungetc(c, f); + fscanf(f, "%lu", &i); + } + + return i; +} + + +/* + * Callback procedure which is used by JBIG encoder to deliver the + * encoded data. It simply sends the bytes to the output file. + */ +static void data_out(unsigned char *start, size_t len, void *file) +{ + fwrite(start, len, 1, (FILE *) file); + total_length += len; + return; +} + + +int main (int argc, char **argv) +{ + FILE *fin = stdin, *fout = stdout; + const char *fnin = NULL, *fnout = NULL; + int i, j, c; + int all_args = 0, files = 0; + unsigned long x, y; + unsigned long width, height, max, v; + unsigned long bpl; + int bpp, planes, encode_planes = -1; + size_t bitmap_size; + char type; + unsigned char **bitmap, *p, *image; + struct jbg_enc_state s; + int verbose = 0, delay_at = 0, reset = 0, use_graycode = 1; + long mwidth = 640, mheight = 480; + int dl = -1, dh = -1, d = -1, mx = -1; + unsigned long l0 = 0, y1 = 0; + char *comment = NULL; + int options = JBG_TPDON | JBG_TPBON | JBG_DPON; + int order = JBG_ILEAVE | JBG_SMID; + + /* parse command line arguments */ + progname = argv[0]; + for (i = 1; i < argc; i++) { + if (!all_args && argv[i][0] == '-') + if (argv[i][1] == 0) { + if (files++) usage(); + } else + for (j = 1; j > 0 && argv[i][j]; j++) + switch(argv[i][j]) { + case '-' : + all_args = 1; + break; + case 0 : + if (files++) usage(); + break; + case 'v': + verbose = 1; + break; + case 'b': + use_graycode = 0; + break; + case 'c': + delay_at = 1; + break; + case 'r': + reset = 1; + break; + case 'f': + d = 0; + order = 0; + options = 8; + l0 = 128; + encode_planes = 1; + mx = 127; + break; + case 'x': + if (++i >= argc) usage(); + j = -1; + mwidth = atol(argv[i]); + break; + case 'y': + if (++i >= argc) usage(); + j = -1; + mheight = atol(argv[i]); + break; + case 'Y': + if (++i >= argc) usage(); + j = -1; + y1 = atol(argv[i]); + break; + case 'o': + if (++i >= argc) usage(); + j = -1; + order = atoi(argv[i]); + break; + case 'p': + if (++i >= argc) usage(); + j = -1; + options = atoi(argv[i]); + break; + case 'l': + if (++i >= argc) usage(); + j = -1; + dl = atoi(argv[i]); + break; + case 'h': + if (++i >= argc) usage(); + j = -1; + dh = atoi(argv[i]); + break; + case 'q': + d = 0; + break; + case 'd': + if (++i >= argc) usage(); + j = -1; + d = atoi(argv[i]); + break; + case 's': + if (++i >= argc) usage(); + j = -1; + l0 = atol(argv[i]); + break; + case 't': + if (++i >= argc) usage(); + j = -1; + encode_planes = atoi(argv[i]); + break; + case 'm': + if (++i >= argc) usage(); + j = -1; + mx = atoi(argv[i]); + break; + case 'C': + if (++i >= argc) usage(); + j = -1; + comment = argv[i]; + break; + default: + usage(); + } + else + switch (files++) { + case 0: fnin = argv[i]; break; + case 1: fnout = argv[i]; break; + default: + usage(); + } + } + + if (fnin) { + fin = fopen(fnin, "rb"); + if (!fin) { + fprintf(stderr, "Can't open input file '%s", fnin); + perror("'"); + exit(1); + } + } else + fnin = ""; + if (fnout) { + fout = fopen(fnout, "wb"); + if (!fout) { + fprintf(stderr, "Can't open input file '%s", fnout); + perror("'"); + exit(1); + } + } else + fnout = ""; + + /* read PBM header */ + while ((c = getc(fin)) != EOF && (isspace(c) || c == '#')) + if (c == '#') + while ((c = getc(fin)) != EOF && !(c == 13 || c == 10)) ; + if (c != 'P') { + fprintf(stderr, "Input file '%s' does not look like a PBM file!\n", fnin); + exit(1); + } + type = getc(fin); + width = getint(fin); + height = getint(fin); + if (type == '2' || type == '5' || + type == '3' || type == '6') + max = getint(fin); + else + max = 1; + for (planes = 0, v = max; v; planes++, v >>= 1) ; + bpp = (planes + 7) / 8; + if (encode_planes < 0 || encode_planes > planes) + encode_planes = planes; + fgetc(fin); /* skip line feed */ + + /* read PBM image data */ + bpl = (width + 7) / 8; /* bytes per line */ + bitmap_size = bpl * (size_t) height; + bitmap = (unsigned char **) checkedmalloc(sizeof(unsigned char *) * + encode_planes); + for (i = 0; i < encode_planes; i++) + bitmap[i] = (unsigned char *) checkedmalloc(bitmap_size); + switch (type) { + case '1': + /* PBM text format */ + p = bitmap[0]; + for (y = 0; y < height; y++) + for (x = 0; x <= ((width-1) | 7); x++) { + *p <<= 1; + if (x < width) + *p |= getint(fin) & 1; + if ((x & 7) == 7) + ++p; + } + break; + case '4': + /* PBM raw binary format */ + fread(bitmap[0], bitmap_size, 1, fin); + break; + case '2': + case '5': + /* PGM */ + image = (unsigned char *) checkedmalloc(width * height * bpp); + if (type == '2') { + for (x = 0; x < width * height; x++) { + v = getint(fin); + for (j = 0; j < bpp; j++) + image[x * bpp + (bpp - 1) - j] = v >> (j * 8); + } + } else + fread(image, width * height, bpp, fin); + jbg_split_planes(width, height, planes, encode_planes, image, bitmap, + use_graycode); + free(image); + break; + default: + fprintf(stderr, "Unsupported PBM type P%c!\n", type); + exit(1); + } + if (ferror(fin)) { + fprintf(stderr, "Problem while reading input file '%s", fnin); + perror("'"); + exit(1); + } + if (feof(fin)) { + fprintf(stderr, "Unexpected end of input file '%s'!\n", fnin); + exit(1); + } + + /* Test for valid parameters */ + if (width < 1 || height < 1) { + fprintf(stderr, "Image dimensions must be positive!\n"); + exit(1); + } + if (encode_planes < 1 || encode_planes > 255) { + fprintf(stderr, "Number of planes must be in range 1-255!\n"); + exit(1); + } + + /* Test the final byte in each image line for correct zero padding */ + if ((width & 7) && type == '4') { + for (y = 0; y < height; y++) + if (bitmap[0][y * bpl + bpl - 1] & ((1 << (8 - (width & 7))) - 1)) { + fprintf(stderr, "Warning: No zero padding in last byte (0x%02x) of " + "line %lu!\n", bitmap[0][y * bpl + bpl - 1], y + 1); + break; + } + } + + /* Apply JBIG algorithm and write BIE to output file */ + + /* initialize parameter struct for JBIG encoder*/ + jbg_enc_init(&s, width, height, encode_planes, bitmap, data_out, fout); + + /* Select number of resolution layers either directly or based + * on a given maximum size for the lowest resolution layer */ + if (d >= 0) + jbg_enc_layers(&s, d); + else + jbg_enc_lrlmax(&s, mwidth, mheight); + + /* Specify a few other options (each is ignored if negative) */ + if (delay_at) + options |= JBG_DELAY_AT; + if (reset) + options |= JBG_SDRST; + if (comment) { + s.comment_len = strlen(comment); + s.comment = (unsigned char *) comment; + } + if (y1) + s.yd1 = y1; + jbg_enc_lrange(&s, dl, dh); + jbg_enc_options(&s, order, options, l0, mx, -1); + + /* now encode everything and send it to data_out() */ + jbg_enc_out(&s); + + /* give encoder a chance to free its temporary data structures */ + jbg_enc_free(&s); + + /* check for file errors and close fout */ + if (ferror(fout) || fclose(fout)) { + fprintf(stderr, "Problem while writing output file '%s", fnout); + perror("'"); + exit(1); + } + + /* In case the user wants to know all the gory details ... */ + if (verbose) { + fprintf(stderr, "Information about the created JBIG bi-level image entity " + "(BIE):\n\n"); + fprintf(stderr, " input image size: %lu x %lu pixel\n", + s.xd, s.yd); + fprintf(stderr, " bit planes: %d\n", s.planes); + if (s.planes > 1) + fprintf(stderr, " encoding: %s code, MSB first\n", + use_graycode ? "Gray" : "binary"); + fprintf(stderr, " stripes: %lu\n", s.stripes); + fprintf(stderr, " lines per stripe in layer 0: %lu\n", s.l0); + fprintf(stderr, " total number of diff. layers: %d\n", s.d); + fprintf(stderr, " lowest layer in BIE: %d\n", s.dl); + fprintf(stderr, " highest layer in BIE: %d\n", s.dh); + fprintf(stderr, " lowest layer size: %lu x %lu pixel\n", + jbg_ceil_half(s.xd, s.d - s.dl), jbg_ceil_half(s.yd, s.d - s.dl)); + fprintf(stderr, " highest layer size: %lu x %lu pixel\n", + jbg_ceil_half(s.xd, s.d - s.dh), jbg_ceil_half(s.yd, s.d - s.dh)); + fprintf(stderr, " option bits:%s%s%s%s%s%s%s\n", + s.options & JBG_LRLTWO ? " LRLTWO" : "", + s.options & JBG_VLENGTH ? " VLENGTH" : "", + s.options & JBG_TPDON ? " TPDON" : "", + s.options & JBG_TPBON ? " TPBON" : "", + s.options & JBG_DPON ? " DPON" : "", + s.options & JBG_DPPRIV ? " DPPRIV" : "", + s.options & JBG_DPLAST ? " DPLAST" : ""); + fprintf(stderr, " order bits:%s%s%s%s\n", + s.order & JBG_HITOLO ? " HITOLO" : "", + s.order & JBG_SEQ ? " SEQ" : "", + s.order & JBG_ILEAVE ? " ILEAVE" : "", + s.order & JBG_SMID ? " SMID" : ""); + fprintf(stderr, " AT maximum x-offset: %d\n" + " AT maximum y-offset: %d\n", s.mx, s.my); + fprintf(stderr, " length of output file: %lu byte\n\n", + total_length); + } + + return 0; +} diff --git a/pbmtools/pbmtojbg.txt b/pbmtools/pbmtojbg.txt new file mode 100644 index 0000000..20e40da --- /dev/null +++ b/pbmtools/pbmtojbg.txt @@ -0,0 +1,227 @@ +PBMTOJBG(1) PBMTOJBG(1) + + + +NAME + pbmtojbg - portable bitmap to JBIG1 file converter + +SYNOPSIS + pbmtojbg [ options ] [ input-file | - [ output-file ]] + +DESCRIPTION + Reads in a portable bitmap (PBM) from a file or standard input, com- + presses it, and outputs the image as a JBIG1 bi-level image entity + (BIE) file. + + JBIG1 is a highly effective lossless compression algorithm for bi-level + images (one bit per pixel), which is particularly suitable for scanned + document pages. + + A JBIG1 encoded image can be stored in several resolutions (progressive + mode). These resolution layers can be stored all in one single BIE or + they can be stored in several separate BIE files. All resolution lay- + ers except the lowest one are stored merely as differences to the next + lower resolution layer, because this requires less space than encoding + the full image completely every time. Each resolution layer has twice + the number of horizontal and vertical pixels than the next lower layer. + JBIG1 files can also store several bits per pixel as separate bitmap + planes, and pbmtojbg can read a PGM file and transform it into a multi- + bitplane BIE. + + +OPTIONS + - A single hyphen instead of an input file name will cause + pbmtojbg to read the data from standard input instead + from a file. + + -q Encode the image in one single resolution layer (sequen- + tial mode). This is usually the most efficient compres- + sion method. By default, the number of resolution layers + is chosen automatically such that the lowest layer image + is not larger than 640 x 480 pixels. This is a shortcut + for -d 0. + + -x number Specify the maximal horizontal size of the lowest resolu- + tion layer. The default is 640 pixels. + + -y number Specify the maximal vertical size of the lowest resolu- + tion layer. The default is 480 pixels. + + -l number Select the lowest resolution layer that will be written + to the BIE. It is possible to store the various resolu- + tion layers of a JBIG1 image in progressive mode into + different BIEs. Options -l and -h allow to select the + resolution-layer interval that will appear in the created + BIE. The lowest resolution layer has number 0 and this is + also the default value. By default all layers will be + written. + + -h number Select the highest resolution layer that will be written + to the BIE. By default all layers will be written. See + also option -l. + + -b Use binary values instead of Gray code words in order to + encode pixel values in multiple bitplanes. This option + has only an effect if the input is a PGM file and if more + than one bitplane is produced. Note that the decoder has + to make the same selection but cannot determine from the + BIE, whether Gray or binary code words were used by the + encoder. + + -d number Specify the total number of differential resolution lay- + ers into which the input image will be split in addition + to the lowest layer. Each additional layer reduces the + size of layer 0 by 50 %. This option overrides options -x + and -y which are usually a more comfortable way of + selecting the number of resolution layers. + + -s number The JBIG1 algorithm splits each image into a number of + horizontal stripes. This option specifies that each + stripe shall have number lines in layer 0. The default + value is selected so that approximately 35 stripes will + be used for the whole image. + + -m number Select the maximum horizontal offset of the adaptive tem- + plate pixel. The JBIG1 encoder uses ten neighbour pixels + to estimate the probability of the next pixel being black + or white. It can move one out of these ten pixels. This + is especially useful for dithered images, as long as the + distance of this adaptive pixel can be adjusted to the + period of the dither pattern. By default, the adaptive + template pixel is allowed to move up to 8 pixels away + horizontally. This encoder supports distances up to 127 + pixels. Annex A of the standard suggests that decoders + should support at least a horizontal distance of 16 pix- + els, so using values not higher than 16 for number might + increase the chances of interoperability with other JBIG1 + implementations. On the other hand, the T.85 fax applica- + tion profile requires decoders to support horizontal off- + sets up to 127 pixels, which the maximum value permitted + by the standard. (The maximal vertical offset of the + adaptive template pixel is always zero for this encoder.) + + -t number Encode only the specified number of most significant bit + planes. This option allows to reduce the depth of an + input PGM file if not all bits per pixel are needed in + the output. + + -o number JBIG1 separates an image into several horizontal stripes, + resolution layers and planes, were each plane contains + one bit per pixel. One single stripe in one plane and + layer is encoded as a data unit called stripe data entity + (SDE) inside the BIE. There are 12 different possible + orders in which the SDEs can be stored inside the BIE and + number selects which one shall be used. The order of the + SDEs is only relevant for applications that want to + decode a JBIG1 file which has not yet completely arrived + from e.g. a slow network connection. For instance some + applications prefer that the outermost of the three loops + (stripes, layers, planes) is over all layers so that all + data of the lowest resolution layer is transmitted first. + The following values for number select these loop + arrangements for writing the SDEs (outermost loop first): + + 0 planes, layers, stripes + 2 layers, planes, stripes + 3 layers, stripes, planes + 4 stripes, planes, layers + 5 planes, stripes, layers + 6 stripes, layers, planes + + All loops count starting with zero, however by adding 8 + to the above order code, the layer loop can be reversed + so that it counts down to zero and then higher resolution + layers will be stored before lower layers. Default order + is 3 which writes at first all planes of the first stripe + and then completes layer 0 before continuing with the + next layer and so on. + + -p number This option allows to activate or deactivate various + optional algorithms defined in the JBIG1 standard. Just + add the numbers of the following options which you want + to activate in order to get the number value: + + 4 deterministic prediction (DPON) + 8 layer 0 typical prediction (TPBON) + 16 diff. layer typ. pred. (TPDON) + 64 layer 0 two-line template (LRLTWO) + + Except for special applications (like communication with + JBIG1 subset implementations) and for debugging purposes + you will normally not want to change anything here. The + default is 28, which provides the best compression + result. + + -C string Add the string in a comment marker segment to the pro- + duced data stream. (There is no support at present for + adding comments that contain the zero byte.) + + -c Determine the adaptive template pixel movement as sug- + gested in annex C of the standard. By default the tem- + plate change takes place directly in the next line, which + is most effective. However, a few conformance test exam- + ples in the standard require the adaptive template change + to be delayed until the first line of the next stripe. + This option selects this special behavior, which is nor- + mally not required except in order to pass some confor- + mance tests. + + -r Use the SDRST marker instead of the normal SDNORM marker. + The probably only useful application of this option is to + generate test data for checking whether a JBIG1 decoder + has implemented SDRST correctly. In a normal JBIG1 data + stream, each stripe data entity (SDE) is terminated by an + SDNORM marker, which preserves the state of the arith- + metic encoder (and more) for the next stripe in the same + layer. The alternative SDRST marker resets this state at + the end of the stripe. + + -Y number A long time ago, there were fax machines that couldn't + even hold a single page in memory. They had to start + transmitting data before the page was scanned in com- + pletely and the length of the image was known. The + authors of the standard added a rather ugly hack to the + otherwise beautiful JBIG1 format to support this. The + NEWLEN marker segment can override the image height + stated in the BIE header anywhere later in the data + stream. Normally pbmtojbg never generates NEWLEN marker + segments, as it knows the correct image height when it + outputs the header. This option is solely intended for + the purpose of generating test files with NEWLEN marker + segments. It can be used to specify a higher initial + image height for use in the BIE header, and pbmtojbg will + then add a NEWLEN marker segment at the latest possible + opportunity to the data stream to signal the correct + final height. + + -f This option makes the output file comply to the "facsim- + ile application profile" defined in ITU-T Recommendation + T.85. It is a shortcut for -q -o 0 -p 8 -s 128 -t 1 -m + 127. + + -v After the BIE has been created, a few technical details + of the created file will be listed (verbose mode). + +BUGS + Using standard input and standard output for binary data works only on + systems where there is no difference between binary and text streams + (e.g., Unix). On other systems (e.g., MS-DOS), using standard input or + standard output may cause control characters like CR or LF to be + inserted or deleted and this will damage the binary data. + +STANDARDS + This program implements the JBIG1 image coding algorithm as specified + in ISO/IEC 11544:1993 and ITU-T T.82(1993). + +AUTHOR + The pbmtojbg program is part of the JBIG-KIT package, which has been + developed by Markus Kuhn. The most recent version of this portable + JBIG1 library and tools set is available from + . + +SEE ALSO + pbm(5), pgm(5), jbgtopbm(1) + + + + 2003-06-04 PBMTOJBG(1) diff --git a/pbmtools/pbmtojbg85.c b/pbmtools/pbmtojbg85.c new file mode 100644 index 0000000..27bdbbd --- /dev/null +++ b/pbmtools/pbmtojbg85.c @@ -0,0 +1,274 @@ +/* + * pbmtojbg85 - Portable Bitmap to JBIG converter (T.85 version) + * + * Markus Kuhn - http://www.cl.cam.ac.uk/~mgk25/jbigkit/ + */ + +#include +#include +#include +#include +#include "jbig85.h" + + +char *progname; /* global pointer to argv[0] */ + + +/* + * Print usage message and abort + */ +static void usage(void) +{ + fprintf(stderr, + "PBMtoJBIG converter " JBG85_VERSION " (T.85 version) --\n" + "creates bi-level image entity (BIE) as output file\n\n" + "usage: %s [] [ | - []]\n\n" + "options:\n\n", progname); + fprintf(stderr, + " -s number\theight of a stripe\n"); + fprintf(stderr, + " -m number\tmaximum adaptive template pixel horizontal offset (default 8)\n" + " -p number\toptions byte value: add TPBON=8, LRLTWO=64\n" + "\t\t(default 8 = TPBON)\n"); + fprintf(stderr, + " -C string\tadd the provided string as a comment marker segment\n"); + fprintf(stderr, + " -Y yi yr\tannounce in header initially the larger image height yi\n" + "\t\tand then announce after line yr has been encoded the real height\n" + "\t\tusing NEWLEN marker (for testing NEWLEN and VLENGTH=1 function)\n\n"); + exit(1); +} + + +/* + * malloc() with exception handler + */ +void *checkedmalloc(size_t n) +{ + void *p; + + if ((p = malloc(n)) == NULL) { + fprintf(stderr, "Sorry, not enough memory available!\n"); + exit(1); + } + + return p; +} + + +/* + * Read an ASCII integer number from file f and skip any PBM + * comments which are encountered. + */ +static unsigned long getint(FILE *f) +{ + int c; + unsigned long i; + + while ((c = getc(f)) != EOF && !isdigit(c)) + if (c == '#') + while ((c = getc(f)) != EOF && !(c == 13 || c == 10)) ; + if (c != EOF) { + ungetc(c, f); + fscanf(f, "%lu", &i); + } + + return i; +} + + +/* + * Callback procedure which is used by JBIG encoder to deliver the + * encoded data. It simply sends the bytes to the output file. + */ +static void data_out(unsigned char *start, size_t len, void *file) +{ + fwrite(start, len, 1, (FILE *) file); + return; +} + + +int main (int argc, char **argv) +{ + FILE *fin = stdin, *fout = stdout; + const char *fnin = NULL, *fnout = NULL; + int i, j, c; + int all_args = 0, files = 0; + unsigned long x, y; + unsigned long width, height; + size_t bpl; + char type; + unsigned char *p, *lines, *next_line; + unsigned char *prev_line = NULL, *prevprev_line = NULL; + struct jbg85_enc_state s; + int mx = -1; + unsigned long l0 = 0, yi = 0, yr = 0; + char *comment = NULL; + int options = JBG_TPBON; + + /* parse command line arguments */ + progname = argv[0]; + for (i = 1; i < argc; i++) { + if (!all_args && argv[i][0] == '-') + if (argv[i][1] == 0) { + if (files++) usage(); + } else + for (j = 1; j > 0 && argv[i][j]; j++) + switch(argv[i][j]) { + case '-' : + all_args = 1; + break; + case 0 : + if (files++) usage(); + break; + case 'Y': + if (i+2 >= argc) usage(); + j = -1; + yi = atol(argv[++i]); + yr = atol(argv[++i]); + break; + case 'p': + if (++i >= argc) usage(); + j = -1; + options = atoi(argv[i]); + break; + case 's': + if (++i >= argc) usage(); + j = -1; + l0 = atol(argv[i]); + break; + case 'm': + if (++i >= argc) usage(); + j = -1; + mx = atoi(argv[i]); + break; + case 'C': + if (++i >= argc) usage(); + j = -1; + comment = argv[i]; + break; + default: + usage(); + } + else + switch (files++) { + case 0: fnin = argv[i]; break; + case 1: fnout = argv[i]; break; + default: + usage(); + } + } + + /* open input file */ + if (fnin) { + fin = fopen(fnin, "rb"); + if (!fin) { + fprintf(stderr, "Can't open input file '%s", fnin); + perror("'"); + exit(1); + } + } else + fnin = ""; + + /* read PBM header */ + while ((c = getc(fin)) != EOF && (isspace(c) || c == '#')) + if (c == '#') + while ((c = getc(fin)) != EOF && !(c == 13 || c == 10)) ; + type = getc(fin); + if (c != 'P' || (type != '1' && type != '4')) { + fprintf(stderr, "Input file '%s' does not look like a PBM file!\n", fnin); + exit(1); + } + width = getint(fin); + height = getint(fin); + fgetc(fin); /* skip line feed */ + + /* Test for valid parameters */ + if (width < 1 || height < 1) { + fprintf(stderr, "Image dimensions must be positive!\n"); + exit(1); + } + + /* allocate buffer for a single image line */ + bpl = (width >> 3) + !!(width & 7); /* bytes per line */ + lines = (unsigned char *) checkedmalloc(bpl * 3); + + /* open output file */ + if (fnout) { + fout = fopen(fnout, "wb"); + if (!fout) { + fprintf(stderr, "Can't open input file '%s", fnout); + perror("'"); + exit(1); + } + } else + fnout = ""; + + /* initialize parameter struct for JBIG encoder*/ + jbg85_enc_init(&s, width, yi ? yi : height, data_out, fout); + + /* Specify a few other options (each is ignored if negative) */ + if (yi) + options |= JBG_VLENGTH; + if (comment) { + s.comment_len = strlen(comment); + s.comment = (unsigned char *) comment; + } + jbg85_enc_options(&s, options, l0, mx); + + for (y = 0; y < height; y++) { + + /* Use a 3-line ring buffer, because the encoder requires that the two + * previously supplied lines are still in memory when the next line is + * processed. */ + next_line = lines + (y%3)*bpl; + + switch (type) { + case '1': + /* PBM text format */ + p = next_line; + for (x = 0; x <= ((width-1) | 7); x++) { + *p <<= 1; + if (x < width) + *p |= getint(fin) & 1; + if ((x & 7) == 7) + ++p; + } + break; + case '4': + /* PBM raw binary format */ + fread(next_line, bpl, 1, fin); + break; + default: + fprintf(stderr, "Unsupported PBM type P%c!\n", type); + exit(1); + } + if (ferror(fin)) { + fprintf(stderr, "Problem while reading input file '%s", fnin); + perror("'"); + exit(1); + } + if (feof(fin)) { + fprintf(stderr, "Unexpected end of input file '%s'!\n", fnin); + exit(1); + } + + /* JBIG compress another line and write out result via callback */ + jbg85_enc_lineout(&s, next_line, prev_line, prevprev_line); + prevprev_line = prev_line; + prev_line = next_line; + + /* adjust final image height via NEWLEN */ + if (yi && y == yr) + jbg85_enc_newlen(&s, height); + } + + /* check for file errors and close fout */ + if (ferror(fout) || fclose(fout)) { + fprintf(stderr, "Problem while writing output file '%s", fnout); + perror("'"); + exit(1); + } + + return 0; +} diff --git a/pbmtools/pgm.5 b/pbmtools/pgm.5 new file mode 100644 index 0000000..94a352a --- /dev/null +++ b/pbmtools/pgm.5 @@ -0,0 +1,90 @@ +.TH pgm 5 "12 November 1991" +.SH NAME +pgm - portable graymap file format +.SH DESCRIPTION +The portable graymap format is a lowest common denominator grayscale +file format. +.IX "PGM file format" +The definition is as follows: +.IP - 2 +A "magic number" for identifying the file type. +A pgm file's magic number is the two characters "P2". +.IX "magic numbers" +.IP - 2 +Whitespace (blanks, TABs, CRs, LFs). +.IP - 2 +A width, formatted as ASCII characters in decimal. +.IP - 2 +Whitespace. +.IP - 2 +A height, again in ASCII decimal. +.IP - 2 +Whitespace. +.IP - 2 +The maximum gray value, again in ASCII decimal. +.IP - 2 +Whitespace. +.IP - 2 +Width * height gray values, each in ASCII decimal, between 0 and the specified +maximum value, separated by whitespace, starting at the top-left +corner of the graymap, proceeding in normal English reading order. +A value of 0 means black, and the maximum value means white. +.IP - 2 +Characters from a "#" to the next end-of-line are ignored (comments). +.IP - 2 +No line should be longer than 70 characters. +.PP +Here is an example of a small graymap in this format: +.nf +P2 +# feep.pgm +24 7 +15 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0 +0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0 +0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0 +0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0 +0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +.fi +.PP +Programs that read this format should be as lenient as possible, +accepting anything that looks remotely like a graymap. +.PP +There is also a variant on the format, available +by setting the RAWBITS option at compile time. This variant is +different in the following ways: +.IX RAWBITS +.IP - 2 +The "magic number" is "P5" instead of "P2". +.IP - 2 +The gray values are stored as plain bytes, instead of ASCII decimal. +.IP - 2 +No whitespace is allowed in the grays section, and only a single character +of whitespace (typically a newline) is allowed after the maxval. +.IP - 2 +The files are smaller and many times faster to read and write. +.PP +Note that this raw format can only be used for maxvals less than +or equal to 255. +If you use the +.I pgm +library and try to write a file with a larger maxval, +it will automatically fall back on the slower but more general plain +format. +.SH "SEE ALSO" +fitstopgm(1), fstopgm(1), hipstopgm(1), lispmtopgm(1), psidtopgm(1), +rawtopgm(1), +pgmbentley(1), pgmcrater(1), pgmedge(1), pgmenhance(1), pgmhist(1), pgmnorm(1), +pgmoil(1), pgmramp(1), pgmtexture(1), +pgmtofits(1), pgmtofs(1), pgmtolispm(1), pgmtopbm(1), +pnm(5), pbm(5), ppm(5) +.SH AUTHOR +Copyright (C) 1989, 1991 by Jef Poskanzer. +.\" Permission to use, copy, modify, and distribute this software and its +.\" documentation for any purpose and without fee is hereby granted, provided +.\" that the above copyright notice appear in all copies and that both that +.\" copyright notice and this permission notice appear in supporting +.\" documentation. This software is provided "as is" without express or +.\" implied warranty. diff --git a/pbmtools/pgm.txt b/pbmtools/pgm.txt new file mode 100644 index 0000000..e3ec37a --- /dev/null +++ b/pbmtools/pgm.txt @@ -0,0 +1,85 @@ +pgm(5) pgm(5) + + + +NAME + pgm - portable graymap file format + +DESCRIPTION + The portable graymap format is a lowest common denominator grayscale + file format. The definition is as follows: + + - A "magic number" for identifying the file type. A pgm file's magic + number is the two characters "P2". + + - Whitespace (blanks, TABs, CRs, LFs). + + - A width, formatted as ASCII characters in decimal. + + - Whitespace. + + - A height, again in ASCII decimal. + + - Whitespace. + + - The maximum gray value, again in ASCII decimal. + + - Whitespace. + + - Width * height gray values, each in ASCII decimal, between 0 and the + specified maximum value, separated by whitespace, starting at the + top-left corner of the graymap, proceeding in normal English reading + order. A value of 0 means black, and the maximum value means white. + + - Characters from a "#" to the next end-of-line are ignored (comments). + + - No line should be longer than 70 characters. + + Here is an example of a small graymap in this format: + P2 + # feep.pgm + 24 7 + 15 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0 + 0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0 + 0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0 + 0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0 + 0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + + Programs that read this format should be as lenient as possible, + accepting anything that looks remotely like a graymap. + + There is also a variant on the format, available by setting the RAWBITS + option at compile time. This variant is different in the following + ways: + + - The "magic number" is "P5" instead of "P2". + + - The gray values are stored as plain bytes, instead of ASCII decimal. + + - No whitespace is allowed in the grays section, and only a single + character of whitespace (typically a newline) is allowed after the + maxval. + + - The files are smaller and many times faster to read and write. + + Note that this raw format can only be used for maxvals less than or + equal to 255. If you use the pgm library and try to write a file with + a larger maxval, it will automatically fall back on the slower but more + general plain format. + +SEE ALSO + fitstopgm(1), fstopgm(1), hipstopgm(1), lispmtopgm(1), psidtopgm(1), + rawtopgm(1), pgmbentley(1), pgmcrater(1), pgmedge(1), pgmenhance(1), + pgmhist(1), pgmnorm(1), pgmoil(1), pgmramp(1), pgmtexture(1), + pgmtofits(1), pgmtofs(1), pgmtolispm(1), pgmtopbm(1), pnm(5), pbm(5), + ppm(5) + +AUTHOR + Copyright (C) 1989, 1991 by Jef Poskanzer. + + + + 12 November 1991 pgm(5)