From 2cbeb8abd92d5ad8a1bd415b51b3816213b15f31 Mon Sep 17 00:00:00 2001 From: "Thomas G. Lane" Date: Mon, 7 Oct 1991 00:00:00 +0000 Subject: [PATCH] The Independent JPEG Group's JPEG software v1 --- README | 391 +++++++++++++++ ansi2knr.c | 477 ++++++++++++++++++ architecture | 1106 ++++++++++++++++++++++++++++++++++++++++ codingrules | 99 ++++ egetopt.c | 276 ++++++++++ jbsmooth.c | 120 +++++ jcarith.c | 42 ++ jccolor.c | 203 ++++++++ jcdeflts.c | 364 ++++++++++++++ jcexpand.c | 75 +++ jchuff.c | 689 +++++++++++++++++++++++++ jcmain.c | 272 ++++++++++ jcmaster.c | 127 +++++ jcmcu.c | 212 ++++++++ jconfig.h | 320 ++++++++++++ jcpipe.c | 715 ++++++++++++++++++++++++++ jcsample.c | 135 +++++ jdarith.c | 42 ++ jdcolor.c | 194 +++++++ jdhuff.c | 318 ++++++++++++ jdmain.c | 289 +++++++++++ jdmaster.c | 180 +++++++ jdmcu.c | 146 ++++++ jdpipe.c | 1309 ++++++++++++++++++++++++++++++++++++++++++++++++ jdsample.c | 133 +++++ jerror.c | 67 +++ jfwddct.c | 179 +++++++ jinclude.h | 73 +++ jpegdata.h | 812 ++++++++++++++++++++++++++++++ jquant1.c | 387 ++++++++++++++ jquant2.c | 122 +++++ jrdgif.c | 620 +++++++++++++++++++++++ jrdjfif.c | 733 +++++++++++++++++++++++++++ jrdppm.c | 124 +++++ jrevdct.c | 171 +++++++ jutils.c | 106 ++++ jvirtmem.c | 548 ++++++++++++++++++++ jwrgif.c | 497 ++++++++++++++++++ jwrjfif.c | 468 +++++++++++++++++ jwrppm.c | 167 ++++++ makcjpeg.cf | 5 + makcjpeg.lnk | 21 + makdjpeg.cf | 6 + makdjpeg.lnk | 22 + makefile.amiga | 143 ++++++ makefile.mc5 | 115 +++++ makefile.mc6 | 79 +++ makefile.pwc | 100 ++++ makefile.unix | 152 ++++++ makljpeg.cf | 5 + testimg.jpg | Bin 0 -> 3583 bytes testimg.ppm | 9 + testorig.jpg | Bin 0 -> 2899 bytes 53 files changed, 13965 insertions(+) create mode 100644 README create mode 100644 ansi2knr.c create mode 100644 architecture create mode 100644 codingrules create mode 100644 egetopt.c create mode 100644 jbsmooth.c create mode 100644 jcarith.c create mode 100644 jccolor.c create mode 100644 jcdeflts.c create mode 100644 jcexpand.c create mode 100644 jchuff.c create mode 100644 jcmain.c create mode 100644 jcmaster.c create mode 100644 jcmcu.c create mode 100644 jconfig.h create mode 100644 jcpipe.c create mode 100644 jcsample.c create mode 100644 jdarith.c create mode 100644 jdcolor.c create mode 100644 jdhuff.c create mode 100644 jdmain.c create mode 100644 jdmaster.c create mode 100644 jdmcu.c create mode 100644 jdpipe.c create mode 100644 jdsample.c create mode 100644 jerror.c create mode 100644 jfwddct.c create mode 100644 jinclude.h create mode 100644 jpegdata.h create mode 100644 jquant1.c create mode 100644 jquant2.c create mode 100644 jrdgif.c create mode 100644 jrdjfif.c create mode 100644 jrdppm.c create mode 100644 jrevdct.c create mode 100644 jutils.c create mode 100644 jvirtmem.c create mode 100644 jwrgif.c create mode 100644 jwrjfif.c create mode 100644 jwrppm.c create mode 100644 makcjpeg.cf create mode 100644 makcjpeg.lnk create mode 100644 makdjpeg.cf create mode 100644 makdjpeg.lnk create mode 100644 makefile.amiga create mode 100644 makefile.mc5 create mode 100644 makefile.mc6 create mode 100644 makefile.pwc create mode 100644 makefile.unix create mode 100644 makljpeg.cf create mode 100644 testimg.jpg create mode 100644 testimg.ppm create mode 100644 testorig.jpg diff --git a/README b/README new file mode 100644 index 0000000..9a2a1bb --- /dev/null +++ b/README @@ -0,0 +1,391 @@ +The Independent JPEG Group's JPEG software +========================================== + +README for release of 7-Oct-91 +=============================== + +This distribution contains the first public release of the Independent JPEG +Group's free JPEG software. You are welcome to redistribute this software and +to use it for any purpose, subject to the conditions under LEGAL ISSUES, below. + +This software is still undergoing revision. Updated versions may be obtained +by anonymous FTP to uunet.uu.net; look under directory /graphics/jpeg. This +particular version will be archived as jpegsrc.v1.tar.Z. If you don't have +access to Internet FTP, UUNET's archives are also available via UUCP; contact +postmaster@uunet.uu.net for information on retrieving files that way. + +Please report any problems with this software to jpeg-info@uunet.uu.net. + +If you intend to become a serious user of this software, please contact +jpeg-info@uunet to be added to our electronic mailing list. Then you'll be +notified of updates and have a chance to participate in discussions, etc. + +This software is the work of Tom Lane, Philip Gladstone, Luis Ortiz, and other +members of the independent JPEG group. + + +DISCLAIMER +========== + +THIS SOFTWARE IS NOT COMPLETE NOR FULLY DEBUGGED. It is not guaranteed to be +useful for anything, nor to be compatible with subsequent releases, nor to be +an accurate implementation of the JPEG standard. (See LEGAL ISSUES for even +more disclaimers.) + + +WHAT'S HERE +=========== + +This distribution contains software to implement JPEG image compression and +decompression. JPEG is a standardized compression method for full-color and +gray-scale images. JPEG is intended for "real-world" scenes; cartoons and +other non-realistic images are not its strong suit. JPEG is lossy, meaning +that the output image is not necessarily identical to the input image. Hence +you should not use JPEG if you have to have identical output bits. However, +on typical images of real-world scenes, very good compression levels can be +obtained with hardly any visible change, and amazingly high compression levels +can be obtained if you can tolerate a low-quality image. For more details, +see the references, or just experiment with various compression settings. + +The software implements JPEG baseline and extended-sequential compression +processes. Provision is made for supporting all variants of these processes, +although some uncommon parameter settings aren't implemented yet. For legal +reasons, we are not distributing code for the arithmetic-coding process; see +LEGAL ISSUES. At present we have made no provision for supporting the +progressive or lossless processes defined in the standard. + +The present software is still largely in the prototype stage. It does not +support all possible variants of the JPEG standard, and some functions have +rather slow and/or crude implementations. However, it is useful already. + +The emphasis in designing this software has been on achieving portability and +flexibility, while also making it fast enough to be useful. We have not yet +undertaken serious performance measurement or tuning; we intend to do so in +the future. + + +This software can be used on several levels: + +* As canned software for JPEG compression and decompression. Just edit the + Makefile and configuration files as needed (see SETUP), compile and go. + Members of the independent JPEG group will improve the out-of-the-box + functionality as time goes on. + +* As the basis for other JPEG programs. For example, you could incorporate + the decompressor into a general image viewing package by replacing the + output module with write-to-screen functions. For an implementation on + specific hardware, you might want to replace some of the inner loops with + assembly code. For a non-command-line-driven system, you might want a + different user interface. (Members of the group will be producing Macintosh + and Amiga versions with appropriate user interfaces, for example.) + +* As a toolkit for experimentation with JPEG and JPEG-like algorithms. Most + of the individual decisions you might want to mess with are packaged up into + separate modules. For example, the details of color-space conversion and + subsampling techniques are each localized in one compressor and one + decompressor module. You'd probably also want to extend the user interface + to give you more detailed control over the JPEG compression parameters. + +In particular, we welcome the use of this software as the basis for commercial +products; no royalty is required. + + +SETUP +===== + +The installation process is not very automatic; you will need at least some +familiarity with C programming and program build procedures for your system. +(Volunteers to work on improving this situation are welcome. Also, we will +probably start distributing pre-built binaries for popular systems at some +point.) + +First, select a makefile and copy it to "Makefile". "makefile.unix" +is appropriate for most Unix and Unix-like systems. Special makefiles are +included for various PC compilers. If you don't see a makefile for your +system, we recommend starting from makefile.unix. + +Look over the Makefile and adjust options as needed. In particular, you'll +need to change the CC= and CFLAGS= definitions if you don't have gcc +(makefile.unix only). If you have a function-prototype-less compiler, be sure +to uncomment the .c.o rule and say "make ansi2knr". This will cause the +source files to be preprocessed to change our ANSI-style function definitions +to old-style definitions. (Thanks to Peter Deutsch of Aladdin Enterprises for +ansi2knr.) + +Also look over jconfig.h and adjust #defines as necessary. If you have an +ANSI-compliant C compiler (gcc for instance), no changes should be necessary +except perhaps for RIGHT_SHIFT_IS_UNSIGNED and TWO_FILE_COMMANDLINE. For +older compilers other mods may be needed, depending on what ANSI features are +supported. If you prefer, you can usually leave jconfig.h unmodified and add +-D switches to the Makefile's CFLAGS= definition. + +Then say "make". + +If you have trouble with missing system include files or inclusion of the +wrong ones, you can fix it in jinclude.h. In particular, if you are using +gcc on a machine with non-ANSI system include files, you are likely to find +that jinclude.h tries to include the wrong files (because gcc defines +__STDC__). There's no good automatic solution to this, so you'll just have +to hand-edit jinclude.h. + +As a quick test of functionality we've included three sample files: + testorig.jpg same as blkint.jpg from JPEG validation floppy. + testimg.ppm output of djpeg testorig.jpg + testimg.jpg output of cjpeg testimg.ppm +The two .jpg files aren't identical due to different parameter choices (and +wouldn't be anyway, since JPEG is lossy). However, if you can generate +duplicates of testimg.ppm and testimg.jpg then you probably have a working +port. "make test" will perform the necessary comparisons (by generating +testout.ppm and testout.jpg and comparing these to testimg.*). NOTE: this +is far from an exhaustive test of the JPEG software; some modules, such as +color quantization and GIF I/O, are not exercised at all. It's just a quick +test to give you some confidence that you haven't missed something major. + +If you need to make a smaller version of the JPEG software, some optional +functions can be removed at compile time. See the xxx_SUPPORTED #defines +in jconfig.h. (Not a lot is actually removed right now, but as more optional +stuff gets added, this mechanism will start to make a difference.) + +If you want to incorporate the JPEG code as subroutines in a larger program, +we recommend that you make libjpeg.a. Then use the .h files and libjpeg.a as +your interface to the JPEG functions. Your surrounding program will have to +provide functionality similar to what's in jcmain.c or jdmain.c, and you may +want to replace jerror.c and possibly other modules depending on your needs. +See the "architecture" file for more info. If it seems to you that the system +structure doesn't accommodate what you want to do, please contact the authors. + +Special notes for Macintosh Think C users: If you have version 5.0 you should +be able to just turn on __STDC__ through the compiler switch that enables +that. With version 4.0 you must manually edit jconfig.h to define PROTO, +HAVE_UNSIGNED_CHAR, HAVE_UNSIGNED_SHORT, and const. (It seems to be safe to +just define __STDC__ to take care of the first three.) When setting up +project files, use the COBJECTS and DOBJECTS lists in makefile.unix as a guide +to which files need to be included, and add the ANSI and Unix C libraries in a +separate segment. You may need to divide the JPEG files into more than one +segment; you can do this pretty much as you please. + + +USAGE +===== + +The user interface is pretty minimal at this point. We haven't bothered to +generate manual-page files since the switches badly need redesign. At the +moment, things work like this: + +There are two programs, cjpeg to compress an image file into JPEG format, +and djpeg to decompress. + +On Unix systems, you say: + cjpeg [switches] [imagefile] >jpegfile + djpeg [switches] [jpegfile] >imagefile +The programs read the specified input file, or standard input if none is +named. They always write to standard output (with trace/error messages to +standard error). These conventions are handy for piping images between +programs. + +On PC, Macintosh, and Amiga systems, you say: + cjpeg [switches] imagefile jpegfile + djpeg [switches] jpegfile imagefile +i.e., both input and output files are named on the command line. This style +is a little more foolproof, and it loses no functionality if you don't have +pipes. You can get this style on Unix too, if you prefer, by defining +TWO_FILE_COMMANDLINE in jconfig.h or in the Makefile. You MUST use this style +on any system that doesn't cope well with binary data fed through +stdin/stdout. + +Currently supported image file formats include raw-format PPM, raw-format PGM +(for monochrome images), and GIF. cjpeg recognizes the input image format +automatically, but you have to tell djpeg which format to generate. + +The only JPEG file format currently supported is a raw JPEG data stream. +Unless modified, the programs use the JFIF conventions for variables left +unspecified by the JPEG standard. (In particular, cjpeg generates a JFIF APP0 +marker.) Support for the JPEG-in-TIFF format will probably be added at some +future date. + +The command line switches for cjpeg are: + + -I Generate noninterleaved JPEG file (not yet supported). + + -Q quality Scale quantization tables to adjust quality. + Quality is 0 (worst) to 100 (best); default is 75. + (See below for more info.) + + -a Use arithmetic coding rather than Huffman coding. + (Not currently supported, see LEGAL ISSUES.) + + -o Perform optimization of entropy encoding parameters. + Without this, default Huffman or arithmetic + parameters are used. -o makes the JPEG file a tad + smaller, but compression uses much more memory. + Image quality is unaffected by -o. + + -d Enable debug printout. More -d's give more printout. + +Typically you'd use -Q settings of 50 or 75 or so. -Q 100 will generate a +quantization table of all 1's, meaning no quantization loss; then any +differences between input and output images are due to subsampling or to +roundoff error in the DCT or colorspace-conversion steps. -Q values below 50 +may be useful for making real small, low-quality images. Try -Q 2 (or so) for +some amusing Cubist effects. (Note that -Q values below about 25 generate +2-byte quantization tables, which are not decodable by pure baseline JPEG +decoders. cjpeg emits a warning message when you give such a -Q value.) + +The command line switches for djpeg are: + + -G Select GIF output format (implies -q, with default + of 256 colors). + + -b Perform cross-block smoothing. This is quite + memory-intensive and only seems to improve the image + at very low quality settings (-Q 10 to 20 or so). + + -g Force gray-scale output even if input is color. + + -q N Quantize to N colors. + + -D Use Floyd-Steinberg dithering in color quantization. + + -2 Use two-pass color quantization (not yet supported). + + -d Enable debug printout. More -d's give more printout. + +Color quantization currently uses a rather shoddy algorithm (although it's not +so horrible when dithered). Because of this, the GIF output mode is not +recommended in the current release, except for gray-scale output. You can get +better results by applying ppmquant to the unquantized (PPM) output of djpeg, +then converting to GIF with ppmtogif. We expect to provide a considerably +better quantization algorithm in a future release. + +Note that djpeg *can* read noninterleaved JPEG files even though cjpeg can't +yet generate them. For most applications this is a nonissue, since hardly +anybody seems to be using noninterleaved format. + +On a non-virtual-memory machine, you may run out of memory if you use -I or -o +in cjpeg, or -q ... -2 in djpeg, or try to read an interlaced GIF file. This +will be addressed eventually by replacing jvirtmem.c with something that uses +temporary files for large images (see TO DO). + + +REFERENCES +========== + +The best and most readily available introduction to the JPEG compression +algorithm is Wallace's article in the April '91 CACM: + Wallace, Gregory K. "The JPEG Still Picture Compression Standard", + Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44. +(Adjacent articles in that issue discuss MPEG motion picture compression, +applications of JPEG, and related topics.) We highly recommend reading that +article before looking at any of the JPEG software. + +For more detail about the JPEG standard you pretty much have to go to the +draft standard, which is not nearly as intelligible as Wallace's article. +The current version is ISO/IEC Committee Draft CD 10918-1 dated 1991-03-15. +The standard is not presently available electronically; you must order a paper +copy through ISO. + +The JPEG standard does not specify all details of an interchangeable file +format. For the omitted details we follow the "JFIF" conventions, revision +1.01. A copy of the JFIF spec is available from: + Literature Department + C-Cube Microsystems, Inc. + 399A West Trimble Road + San Jose, CA 95131 + (408) 944-6300 +Requests can also be e-mailed to info@c3.pla.ca.us (this address good after +10/10/91). The same source can supply copies of the draft JPEG-in-TIFF specs. + +If you want to understand this implementation, start by reading the +"architecture" documentation file. Please read "codingrules" if you want to +contribute any code. + + +SUPPORTING SOFTWARE +=================== + +You will probably want Jef Poskanzer's PBMPLUS image software; this provides +many useful operations on PPM-format image files. In particular, it can +convert PPM images to and from a wide range of other formats. You can FTP +this free software from export.lcs.mit.edu (contrib/pbmplus*.tar.Z) or +ftp.ee.lbl.gov (pbmplus*.tar.Z). + +If you are using X Windows you might want to use the xv or xloadimage viewers +to save yourself the trouble of converting PPM to some other format. +Both of these can be found in the contrib directory at export.lcs.mit.edu. + + +LEGAL ISSUES +============ + +The authors make NO WARRANTY or representation, either express or implied, +with respect to this software, its quality, accuracy, merchantability, or +fitness for a particular purpose. This software is provided "AS IS", and you, +its user, assume the entire risk as to its quality and accuracy. + +This software is copyright (C) 1991, Thomas G. Lane. +All Rights Reserved except as specified below. + +Permission is hereby granted to use, copy, modify, and distribute this +software (or portions thereof) for any purpose, without fee, subject to these +conditions: +(1) If any part of the source code for this software is distributed, then this +README file must be included, with this copyright and no-warranty notice +unaltered; and any additions, deletions, or changes to the original files +must be clearly indicated in accompanying documentation. +(2) If only executable code is distributed, then the accompanying +documentation must state that "this software is based in part on the work of +the Independent JPEG Group". +(3) Permission for use of this software is granted only if the user accepts +full responsibility for any undesirable consequences; the authors accept +NO LIABILITY for damages of any kind. + +Permission is NOT granted for the use of any author's name or author's company +name in advertising or publicity relating to this software or products derived +from it. This software may be referred to only as "the Independent JPEG +Group's software". + +We specifically permit and encourage the use of this software as the basis of +commercial products, provided that all warranty or liability claims are +assumed by the product vendor. + + +ansi2knr.c is included in this distribution by permission of L. Peter Deutsch, +sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA. +ansi2knr.c is NOT covered by the above copyright and conditions, but instead +by the usual distribution terms of the Free Software Foundation; principally, +that you must include source code if you redistribute it. (See the file +ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part +of any product generated from the JPEG code, this does not limit you more than +the foregoing paragraphs do. + + +It appears that the arithmetic coding option of the JPEG spec is covered by +patents held by IBM, and possibly also patents of AT&T and Mitsubishi. Hence +arithmetic coding cannot legally be used without obtaining one or more +licenses. For this reason, support for arithmetic coding has been removed +from the free JPEG software. (Since arithmetic coding provides only a +marginal gain over the unpatented Huffman mode, it is unlikely that very many +people will choose to use it. If you do obtain such a license, contact +jpeg-info@uunet.uu.net for a copy of our arithmetic coding modules.) So far +as we are aware, there are no patent restrictions on the remaining code. + + +TO DO +===== + +Many of the modules need fleshing out to provide more complete +implementations, or to provide faster paths for common cases. The greatest +needs are for (a) decent color quantization, and (b) a memory manager +implementation that can work in limited memory by swapping "big" images to +temporary files. I (Tom Lane) am going to work on color quantization next. +Volunteers to write a PC memory manager, or to work on any other modules, are +welcome. + +We'd appreciate it if people would compile and check out the code on as wide a +variety of systems as possible, and report any portability problems +encountered (with solutions, if possible). Checks of file compatibility with +other JPEG implementations would also be of interest. Finally, we would +appreciate code profiles showing where the most time is spent, especially on +unusual systems. + +Please send bug reports, offers of help, etc. to jpeg-info@uunet.uu.net. diff --git a/ansi2knr.c b/ansi2knr.c new file mode 100644 index 0000000..77d3d81 --- /dev/null +++ b/ansi2knr.c @@ -0,0 +1,477 @@ +/* + * Received from Peter Deutsch (ghost@aladdin.com) + * Fri, 26 Apr 91 10:10:10 PDT + */ + +/* Copyright (C) 1989, 1991 Aladdin Enterprises. All rights reserved. + Distributed by Free Software Foundation, Inc. + +This file is part of Ghostscript. + +Ghostscript is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY. No author or distributor accepts responsibility +to anyone for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. Refer +to the Ghostscript General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute +Ghostscript, but only under the conditions described in the Ghostscript +General Public License. A copy of this license is supposed to have been +given to you along with Ghostscript so you can know your rights and +responsibilities. It should be in a file named COPYING. Among other +things, the copyright notice and this notice must be preserved on all +copies. */ + +/* +---------- Here is the GhostScript file COPYING, referred to above ---------- +----- These terms do NOT apply to the JPEG software itself; see README ------ + + GHOSTSCRIPT GENERAL PUBLIC LICENSE + (Clarified 11 Feb 1988) + + Copyright (C) 1988 Richard M. Stallman + Everyone is permitted to copy and distribute verbatim copies of this + license, but changing it is not allowed. You can also use this wording + to make the terms for other programs. + + The license agreements of most software companies keep you at the +mercy of those companies. By contrast, our general public license is +intended to give everyone the right to share Ghostscript. To make sure +that you get the rights we want you to have, we need to make +restrictions that forbid anyone to deny you these rights or to ask you +to surrender the rights. Hence this license agreement. + + Specifically, we want to make sure that you have the right to give +away copies of Ghostscript, that you receive source code or else can get +it if you want it, that you can change Ghostscript or use pieces of it +in new free programs, and that you know you can do these things. + + To make sure that everyone has such rights, we have to forbid you to +deprive anyone else of these rights. For example, if you distribute +copies of Ghostscript, 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 tell them their rights. + + Also, for our own protection, we must make certain that everyone finds +out that there is no warranty for Ghostscript. If Ghostscript is +modified by someone else and passed on, we want its recipients to know +that what they have is not what we distributed, so that any problems +introduced by others will not reflect on our reputation. + + Therefore we (Richard M. Stallman and the Free Software Foundation, +Inc.) make the following terms which say what you must do to be allowed +to distribute or change Ghostscript. + + + COPYING POLICIES + + 1. You may copy and distribute verbatim copies of Ghostscript source +code as you receive it, in any medium, provided that you conspicuously +and appropriately publish on each copy a valid copyright and license +notice "Copyright (C) 1989 Aladdin Enterprises. All rights reserved. +Distributed by Free Software Foundation, Inc." (or with whatever year is +appropriate); keep intact the notices on all files that refer to this +License Agreement and to the absence of any warranty; and give any other +recipients of the Ghostscript program a copy of this License Agreement +along with the program. You may charge a distribution fee for the +physical act of transferring a copy. + + 2. You may modify your copy or copies of Ghostscript or any portion of +it, and copy and distribute such modifications under the terms of +Paragraph 1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating + that you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, + that in whole or in part contains or is a derivative of Ghostscript + or any part thereof, to be licensed at no charge to all third + parties on terms identical to those contained in this License + Agreement (except that you may choose to grant more extensive + warranty protection to some or all third parties, at your option). + + c) You may charge a distribution fee for the physical act of + transferring a copy, and you may at your option offer warranty + protection in exchange for a fee. + +Mere aggregation of another unrelated program with this program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other program under the scope of these terms. + + 3. You may copy and distribute Ghostscript (or a portion or derivative +of it, under Paragraph 2) in object code or executable form under the +terms of Paragraphs 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 + Paragraphs 1 and 2 above; or, + + b) accompany it with a written offer, valid for at least three + years, to give any third party free (except for a nominal + shipping charge) a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Paragraphs 1 and 2 above; or, + + c) accompany it with the information you received as to where the + corresponding source code may be obtained. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form alone.) + +For an executable file, complete source code means all the source code for +all modules it contains; but, as a special exception, it need not include +source code for modules which are standard libraries that accompany the +operating system on which the executable file runs. + + 4. You may not copy, sublicense, distribute or transfer Ghostscript +except as expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer Ghostscript is +void and your rights to use the program under this License agreement +shall be automatically terminated. However, parties who have received +computer software programs from you with this License Agreement will not +have their licenses terminated so long as such parties remain in full +compliance. + + 5. If you wish to incorporate parts of Ghostscript into other free +programs whose distribution conditions are different, write to the Free +Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not +yet worked out a simple rule that can be stated here, but we will often +permit this. We 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. + +Your comments and suggestions about our licensing policies and our +software are welcome! Please contact the Free Software Foundation, +Inc., 675 Mass Ave, Cambridge, MA 02139, or call (617) 876-3296. + + NO WARRANTY + + BECAUSE GHOSTSCRIPT IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, RICHARD +M. STALLMAN, ALADDIN ENTERPRISES, L. PETER DEUTSCH, AND/OR OTHER PARTIES +PROVIDE GHOSTSCRIPT "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 GHOSTSCRIPT IS WITH +YOU. SHOULD GHOSTSCRIPT PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL +NECESSARY SERVICING, REPAIR OR CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., L. PETER DEUTSCH, ALADDIN +ENTERPRISES, AND/OR ANY OTHER PARTY WHO MAY MODIFY AND REDISTRIBUTE +GHOSTSCRIPT AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING +ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE +(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED +INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A FAILURE OF THE +PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) GHOSTSCRIPT, EVEN IF YOU +HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM +BY ANY OTHER PARTY. +-------------------- End of file COPYING ------------------------------ +*/ + + +/* ansi2knr.c */ +/* Convert ANSI function declarations to K&R syntax */ +#include +#include + +#ifdef BSD +# include +# define strchr index +#else +# ifdef VMS + extern char *strcat(), *strchr(), *strcpy(), *strupr(); + extern int strcmp(), strlen(), strncmp(); +# else +# include +# endif +#endif + +#ifdef MSDOS +# include +#else +# ifdef VMS + extern char *malloc(); + extern void free(); +# else +# ifdef BSD + extern char *malloc(); +# else +# include +# endif +# endif +#endif + +/* Usage: + ansi2knr input_file output_file + * If no output_file is supplied, output goes to stdout. + * There are no error messages. + * + * ansi2knr recognizes functions by seeing a non-keyword identifier + * at the left margin, followed by a left parenthesis, + * with a right parenthesis as the last character on the line. + * It will recognize a multi-line header if the last character + * on each line but the last is a left parenthesis or comma. + * These algorithms ignore whitespace and comments, except that + * the function name must be the first thing on the line. + * The following constructs will confuse it: + - Any other construct that starts at the left margin and + follows the above syntax (such as a macro or function call). + - Macros that tinker with the syntax of the function header. + */ + +/* Scanning macros */ +#define isidchar(ch) (isalnum(ch) || (ch) == '_') +#define isidfirstchar(ch) (isalpha(ch) || (ch) == '_') + +main(argc, argv) + int argc; + char *argv[]; +{ FILE *in, *out; +#define bufsize 500 /* arbitrary size */ + char buf[bufsize]; + char *line; + switch ( argc ) + { + default: + printf("Usage: ansi2knr input_file [output_file]\n"); + exit(0); + case 2: + out = stdout; break; + case 3: + out = fopen(argv[2], "w"); + if ( out == NULL ) + { fprintf(stderr, "Cannot open %s\n", argv[2]); + exit(1); + } + } + in = fopen(argv[1], "r"); + if ( in == NULL ) + { fprintf(stderr, "Cannot open %s\n", argv[1]); + exit(1); + } + fprintf(out, "#line 1 \"%s\"\n", argv[1]); + line = buf; + while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL ) + { switch ( test1(buf) ) + { + case 1: /* a function */ + convert1(buf, out); + break; + case -1: /* maybe the start of a function */ + line = buf + strlen(buf); + continue; + default: /* not a function */ + fputs(buf, out); + break; + } + line = buf; + } + if ( line != buf ) fputs(buf, out); + fclose(out); + fclose(in); + return 0; +} + +/* Skip over space and comments, in either direction. */ +char * +skipspace(p, dir) + register char *p; + register int dir; /* 1 for forward, -1 for backward */ +{ for ( ; ; ) + { while ( isspace(*p) ) p += dir; + if ( !(*p == '/' && p[dir] == '*') ) break; + p += dir; p += dir; + while ( !(*p == '*' && p[dir] == '/') ) + { if ( *p == 0 ) return p; /* multi-line comment?? */ + p += dir; + } + p += dir; p += dir; + } + return p; +} + +/* + * Write blanks over part of a string. + */ +void +writeblanks(start, end) + char *start; + char *end; +{ char *p; + for ( p = start; p < end; p++ ) *p = ' '; +} + +/* + * Test whether the string in buf is a function definition. + * The string may contain and/or end with a newline. + * Return as follows: + * 0 - definitely not a function definition; + * 1 - definitely a function definition; + * -1 - may be the beginning of a function definition, + * append another line and look again. + */ +test1(buf) + char *buf; +{ register char *p = buf; + char *bend; + char *endfn; + int contin; + if ( !isidfirstchar(*p) ) + return 0; /* no name at left margin */ + bend = skipspace(buf + strlen(buf) - 1, -1); + switch ( *bend ) + { + case ')': contin = 1; break; + case '(': + case ',': contin = -1; break; + default: return 0; /* not a function */ + } + while ( isidchar(*p) ) p++; + endfn = p; + p = skipspace(p, 1); + if ( *p++ != '(' ) + return 0; /* not a function */ + p = skipspace(p, 1); + if ( *p == ')' ) + return 0; /* no parameters */ + /* Check that the apparent function name isn't a keyword. */ + /* We only need to check for keywords that could be followed */ + /* by a left parenthesis (which, unfortunately, is most of them). */ + { static char *words[] = + { "asm", "auto", "case", "char", "const", "double", + "extern", "float", "for", "if", "int", "long", + "register", "return", "short", "signed", "sizeof", + "static", "switch", "typedef", "unsigned", + "void", "volatile", "while", 0 + }; + char **key = words; + char *kp; + int len = endfn - buf; + while ( (kp = *key) != 0 ) + { if ( strlen(kp) == len && !strncmp(kp, buf, len) ) + return 0; /* name is a keyword */ + key++; + } + } + return contin; +} + +convert1(buf, out) + char *buf; + FILE *out; +{ char *endfn = strchr(buf, '(') + 1; + register char *p; + char **breaks; + unsigned num_breaks = 2; /* for testing */ + char **btop; + char **bp; + char **ap; +top: p = endfn; + breaks = (char **)malloc(sizeof(char *) * num_breaks * 2); + if ( breaks == 0 ) + { /* Couldn't allocate break table, give up */ + fprintf(stderr, "Unable to allocate break table!\n"); + fputs(buf, out); + return -1; + } + btop = breaks + num_breaks * 2 - 2; + bp = breaks; + /* Parse the argument list */ + do + { int level = 0; + char *end = NULL; + if ( bp >= btop ) + { /* Filled up break table. */ + /* Allocate a bigger one and start over. */ + free((char *)breaks); + num_breaks <<= 1; + goto top; + } + *bp++ = p; + /* Find the end of the argument */ + for ( ; end == NULL; p++ ) + { switch(*p) + { + case ',': if ( !level ) end = p; break; + case '(': level++; break; + case ')': if ( --level < 0 ) end = p; break; + case '/': p = skipspace(p, 1) - 1; break; + default: ; + } + } + p--; /* back up over terminator */ + /* Find the name being declared. */ + /* This is complicated because of procedure and */ + /* array modifiers. */ + for ( ; ; ) + { p = skipspace(p - 1, -1); + switch ( *p ) + { + case ']': /* skip array dimension(s) */ + case ')': /* skip procedure args OR name */ + { int level = 1; + while ( level ) + switch ( *--p ) + { + case ']': case ')': level++; break; + case '[': case '(': level--; break; + case '/': p = skipspace(p, -1) + 1; break; + default: ; + } + } + if ( *p == '(' && *skipspace(p + 1, 1) == '*' ) + { /* We found the name being declared */ + while ( !isidfirstchar(*p) ) + p = skipspace(p, 1) + 1; + goto found; + } + break; + default: goto found; + } + } +found: if ( *p == '.' && p[-1] == '.' && p[-2] == '.' ) + { p++; + if ( bp == breaks + 1 ) /* sole argument */ + writeblanks(breaks[0], p); + else + writeblanks(bp[-1] - 1, p); + bp--; + } + else + { while ( isidchar(*p) ) p--; + *bp++ = p+1; + } + p = end; + } + while ( *p++ == ',' ); + *bp = p; + /* Make a special check for 'void' arglist */ + if ( bp == breaks+2 ) + { p = skipspace(breaks[0], 1); + if ( !strncmp(p, "void", 4) ) + { p = skipspace(p+4, 1); + if ( p == breaks[2] - 1 ) + { bp = breaks; /* yup, pretend arglist is empty */ + writeblanks(breaks[0], p + 1); + } + } + } + /* Put out the function name */ + p = buf; + while ( p != endfn ) putc(*p, out), p++; + /* Put out the declaration */ + for ( ap = breaks+1; ap < bp; ap += 2 ) + { p = *ap; + while ( isidchar(*p) ) putc(*p, out), p++; + if ( ap < bp - 1 ) fputs(", ", out); + } + fputs(") ", out); + /* Put out the argument declarations */ + for ( ap = breaks+2; ap <= bp; ap += 2 ) (*ap)[-1] = ';'; + fputs(breaks[0], out); + free((char *)breaks); + return 0; +} diff --git a/architecture b/architecture new file mode 100644 index 0000000..78587cd --- /dev/null +++ b/architecture @@ -0,0 +1,1106 @@ + + JPEG SYSTEM ARCHITECTURE 3-OCT-91 + + +This file provides an overview of the "architecture" of the portable JPEG +software; that is, the functions of the various modules in the system and the +interfaces between modules. For more precise details about any data structure +or calling convention, see the header files. + +Important note: when I say "module" I don't mean "a C function", which is what +some people seem to think the term means. A separate C source file is closer +to the mark. Also, it is frequently the case that several different modules +present a common interface to callers; the term "object" or "method" refers to +this common interface (see "Poor man's object-oriented programming", below). + +JPEG-specific terminology follows the JPEG R9 draft: + A "component" means a color channel, e.g., Red or Luminance. + A "sample" is a pixel component value (i.e., one number in the image data). + A "coefficient" is a frequency coefficient (a DCT transform output number). + The term "block" refers to an 8x8 group of samples or coefficients. + "MCU" (minimum coded unit) is the same as "MDU" of the R8 draft; i.e., an + interleaved set of blocks of size determined by the sampling factors, + or a single block in a noninterleaved scan. + + +*** System requirements *** + +We must support compression and decompression of both Huffman and +arithmetic-coded JPEG files. Any set of compression parameters allowed by the +JPEG spec should be readable for decompression. (We can be more restrictive +about what formats we can generate.) (Note: for legal reasons no arithmetic +coding implementation is currently included in the publicly available sources. +However, the architecture still supports it.) + +We need to be able to handle both raw JPEG files (more specifically, the JFIF +format) and JPEG-in-TIFF (C-cubed's format, and perhaps Kodak's). Even if we +don't implement TIFF ourselves, other people will want to use our code for +that. This means that generation and scanning of the file header has to be +separated out. + +Perhaps we should be prepared to support the JPEG lossless mode (also referred +to in the spec as spatial DPCM coding). A lot of people seem to believe they +need this... whether they really do is debatable, but the customer is always +right. On the other hand, there will not be much sharable code between the +lossless and lossy modes! At best, a lossless program could be derived from +parts of the lossy version. For now we will only worry about the lossy mode. + +I see no real value in supporting the JPEG progressive modes (note that +spectral selection and successive approximation are two different progressive +modes). These are only of interest when painting the decompressed image in +real-time, which nobody is going to do with a pure software implementation. + +There is some value in supporting the hierarchical mode, which allows for +successive frames of higher resolution. This could be of use for including +"thumbnail" representations. Also, Storm's JPEG++ files probably use the +hierarchical mode (I haven't looked). However, this appears to add a lot more +complexity than it is worth. + +A variety of uncompressed image file formats and user interfaces must be +supported. These aspects therefore have to be kept separate from the rest of +the system. A particularly important issue is whether color quantization of +the output is needed (i.e., whether a colormap is used). We should be able to +support both adaptive quantization (which requires two or more passes over the +image) and nonadaptive (quantization to a prespecified colormap, which can be +done in one pass). + +Memory usage is an important concern, since we will port this code to 80x86 +and other limited-memory machines. For large intermediate structures, we +should be able to use either virtual memory or temporary files. + +It should be possible to build programs that handle compression only, +decompression only, or both, without much duplicate or unused code in any +version. (In particular, a decompression-only version should have no extra +baggage.) + + +*** Compression overview *** + +The *logical* steps needed in (non-lossless) JPEG compression are: + +1. Conversion from incoming image format to a standardized internal form + (either RGB or greyscale). + +2. Color space conversion (e.g., RGB to YCbCr). This is a null step for + greyscale (unless we support mapping color inputs to greyscale, which + would most easily be done here). Gamma adjustment may also be needed here. + +3. Subsampling (reduction of number of samples in some color components). + This step operates independently on each color component. + +4. MCU extraction (creation of a single sequence of 8x8 sample blocks). + This step and the following ones are performed once for each scan + in the output JPEG file, i.e., once if making an interleaved file and more + than once for a noninterleaved file. + Note: both this step and the previous one must deal with edge conditions + for pictures that aren't a multiple of the MCU dimensions. Alternately, + we could expand the picture to a multiple of an MCU before doing these + two steps. (The latter seems better and has been adopted below.) + +5. DCT transformation of each 8x8 block. + +6. Quantization scaling and zigzag reordering of the elements in each 8x8 + block. + +7. Huffman or arithmetic encoding of the transformed block sequence. + +8. Output of the JPEG file with whatever headers/markers are wanted. + +Of course, the actual implementation will combine some of these logical steps +for efficiency. The trick is to keep these logical functions as separate as +possible without losing too much performance. + +In addition to these logical pipeline steps, we need various modules that +aren't part of the data pipeline. These are: + +A. Overall control (sequencing of other steps & management of data passing). + +B. User interface; this will determine the input and output files, and supply + values for some compression parameters. Note that this module is highly + platform-dependent. + +C. Compression parameter selection: some parameters should be chosen + automatically rather than requiring the user to find a good value. + The prototype only does this for the back-end (Huffman or arithmetic) + parameters, but further in the future, more might be done. A + straightforward approach to selection is to try several values; this + requires being able to repeatedly apply some portion of the pipeline and + inspect the results (without actually outputting them). Probably only + entropy encoding parameters can reasonably be done this way; optimizing + earlier steps would require too much data to be reprocessed (not to mention + the problem of interactions between parameters for different steps). + What other facilities do we need to support automatic parameter selection? + +D. A memory management module to deal with small-memory machines. This must + create the illusion of virtual memory for certain large data structures + (e.g., the subsampled image or the transformed coefficients). + The interface to this must be defined to minimize the overhead incurred, + especially on virtual-memory machines where the module won't do much. + +In many cases we can arrange things so that a data stream is produced in +segments by one module and consumed by another without the need to hold it all +in (virtual) memory. This is obviously not possible for any data that must be +scanned more than once, so it won't work everywhere. + +The major variable at this level of detail is whether the JPEG file is to be +interleaved or not; that affects the order of processing so fundamentally that +the central control module must know about it. Some of the other modules may +need to know it too. It would simplify life if we didn't need to support +noninterleaved images, but that is not reasonable. + +Many of these steps operate independently on each color component; the +knowledge of how many components there are, and how they are interleaved, +ought to be confined to the central control module. (Color space conversion +and MCU extraction probably have to know it too.) + + +*** Decompression overview *** + +Decompression is roughly the inverse process from compression, but there are +some additional steps needed to produce a good output image. + +The *logical* steps needed in (non-lossless) JPEG decompression are: + +1. Scanning of the JPEG file, decoding of headers/markers etc. + +2. Huffman or arithmetic decoding of the coefficient sequence. + +3. Quantization descaling and zigzag reordering of the elements in each 8x8 + block. + +4. MCU disassembly (conversion of a possibly interleaved sequence of 8x8 + blocks back to separate components in pixel map order). + +5. (Optional) Cross-block smoothing per JPEG section 13.10 or a similar + algorithm. (Steps 5-8 operate independently on each component.) + +6. Inverse DCT transformation of each 8x8 block. + +7. De-subsampling. At this point a pixel image of the original dimensions + has been recreated. + +8. Post-subsampling smoothing. This can be combined with de-subsampling, + by using a convolution-like calculation to generate each output pixel + directly from one or more input pixels. + +9. Cropping to the original pixel dimensions (throwing away duplicated + pixels at the edges). It is most convenient to do this now, as the + preceding steps are simplified by not having to worry about odd picture + sizes. + +10. Color space reconversion (e.g., YCbCr to RGB). This is a null step for + greyscale. (Note that if we support mapping color JPEG to greyscale, + it could be done as part of this step.) Gamma adjustment may also be + needed here. + +11. Color quantization (only if a colormapped output format is requested). + NOTE: it might be better to do this on the internal color space instead of + RGB? If so, it would need to be performed one step earlier. + +12. Writing of the desired image format. + +As before, some of these will be combined into single steps. When dealing +with a noninterleaved JPEG file, steps 2-9 will be performed once for each +scan; the resulting data will need to be buffered up so that step 10 can +process all the color components together. + +The same auxiliary modules are needed as before, except for compression +parameter selection. Note that rerunning a pipeline stage should never be +needed during decompression. This may allow a simpler control module. The +user interface might also be simpler since it need not supply any compression +parameters. + +As before, not all of these steps require the whole image to be stored. +Actually, two-pass color quantization is the only step that logically requires +this; everything else could be done a few raster lines at a time (at least for +interleaved images). We might want to make color quantization be a separate +program because of this fact. + +Again, many of the steps should be able to work on one color component in +ignorance of the other components. + + +*** Implications of noninterleaved formats *** + +Much of the work can be done in a single pass if an interleaved JPEG file +format is used. With a noninterleaved JPEG file, separating or recombining +the components will force use of virtual memory (on a small-memory machine, +we probably would want one temp file per color component). + +If any of the image formats we read or write are noninterleaved, the opposite +condition might apply: processing a noninterleaved JPEG file would be more +efficient. Offhand, though, I can't think of any popular image formats that +work that way; besides the win would only come if the same color space were +used in JPEG and non-JPEG files. It's not worth the complexity to make the +system design accommodate that case efficiently. + +An argument against interleaving is that it makes the decompressor need more +memory for cross-block smoothing (since the minimum processable chunk of the +image gets bigger). With images more than 1000 pixels across, 80x86 machines +are likely to have difficulty in handling this feature. + +Another argument against interleaving is that the noninterleaved format allows +a wider range of sampling factors, since the limit of ten blocks per MCU no +longer applies. We could get around this by blithely ignoring the spec's +limit of ten blocks, but that seems like a bad idea (especially since it makes +the above problem worse). + +The upshot is that we need to support both interleaved and noninterleaved JPEG +formats, since for any given machine and picture size one may be much more +efficient than the other. However, the non-JPEG format we convert to or from +will be assumed to be an interleaved format (i.e., it produces or stores all +the components of a pixel together). + +I do not think it is necessary for the compressor to be able to output +partially-interleaved formats (multiple scans, some of which interleave a +subset of the components). However, the decompressor must be able to read +such files to conform to the spec. + + +*** Data formats *** + +Pipeline steps that work on pixel sample values will use the following data +structure: + + typedef something JSAMPLE; a pixel component value, 0..MAXJSAMPLE + typedef JSAMPLE *JSAMPROW; ptr to a row of samples + typedef JSAMPROW *JSAMPARRAY; ptr to a list of rows + typedef JSAMPARRAY *JSAMPIMAGE; ptr to a list of color-component arrays + +The basic element type JSAMPLE will be one of unsigned char, (signed) char, or +unsigned short. Unsigned short will be used if samples wider than 8 bits are +to be supported (this is a compile-time option). Otherwise, unsigned char is +used if possible. If the compiler only supports signed chars, then it is +necessary to mask off the value when reading. Thus, all reads of sample +values should be coded as "GETJSAMPLE(value)", where the macro will be defined +as "((value)&0xFF)" on signed-char machines and "(value)" elsewhere. + +With these conventions, JSAMPLE values can be assumed to be >= 0. This should +simplify correct rounding during subsampling, etc. The JPEG draft's +specification that sample values run from -128..127 will be accommodated by +subtracting 128 just as the sample value is copied into the source array for +the DCT step (this will be an array of signed shorts or longs). Similarly, +during decompression the output of the IDCT step will be immediately shifted +back to 0..255. (NB: different values are required when 12-bit samples are in +use. The code should be written in terms of MAXJSAMPLE and CENTERJSAMPLE, +which will be #defined as 255 and 128 respectively in an 8-bit implementation, +and as 4095 and 2048 in a 12-bit implementation.) + +On compilers that don't support "unsigned short", signed short can be used for +a 12-bit implementation. To support lossless coding (which allows up to +16-bit data precision) masking with 0xFFFF in GETJSAMPLE might be necessary. +(But if "int" is 16 bits then using "unsigned int" is the best solution.) + +Notice that we use a pointer per row, rather than a two-dimensional JSAMPLE +array. This choice costs only a small amount of memory and has several +benefits: + +* Code using the data structure doesn't need to know the allocated width of +the rows. This will simplify edge expansion/compression, since we can work +in an array that's wider than the logical picture width. + +* The rows forming a component array may be allocated at different times +without extra copying. This will simplify working a few scanlines at a time, +especially in smoothing steps that need access to the previous and next rows. + +* Indexing doesn't require multiplication; this is a performance win on many +machines. + +Note that each color component is stored in a separate array; we don't use the +traditional structure in which the components of a pixel are stored together. +This simplifies coding of steps that work on each component independently, +because they don't need to know how many components there are. Furthermore, +we can read or write each component to a temp file independently, which is +helpful when dealing with noninterleaved JPEG files. + +A specific sample value will be accessed by code such as + GETJSAMPLE(image[colorcomponent][row][col]) +where col is measured from the image left edge, but row is measured from the +first sample row currently in memory. Either of the first two indexings can +be precomputed by copying the relevant pointer. + + +Pipeline steps that work on frequency-coefficient values will use the +following data structure: + + typedef short JCOEF; a 16-bit signed integer + typedef JCOEF JBLOCK[64]; an 8x8 block of coefficients + typedef JBLOCK *JBLOCKROW; ptr to one horizontal row of 8x8 blocks + typedef JBLOCKROW *JBLOCKARRAY; ptr to a list of such rows + typedef JBLOCKARRAY *JBLOCKIMAGE; ptr to a list of color component arrays + +The underlying type is always a 16-bit signed integer (this is "short" on all +machines of interest, but let's use the typedef name anyway). These are +grouped into 8x8 blocks (we should use #defines DCTSIZE and DCTSIZE2 rather +than "8" and "64"). The contents of a block may be either in "natural" or +zigzagged order, and may be true values or divided by the quantization +coefficients, depending on where the block is in the pipeline. + +Notice that the allocation unit is now a row of 8x8 blocks, corresponding to +eight rows of samples. Otherwise the structure is much the same as for +samples, and for the same reasons. + +On machines where malloc() can't handle a request bigger than 64Kb, this data +structure limits us to rows of less than 512 JBLOCKs, which would be a picture +width of 4000 pixels. This seems an acceptable restriction. + + +On 80x86 machines, the bottom-level pointer types (JSAMPROW and JBLOCKROW) +must be declared as "far" pointers, but the upper levels can be "near" +(implying that the pointer lists are allocated in the DS segment). +To simplify sharing code, we'll have a #define symbol FAR, which expands to +the "far" keyword when compiling on 80x86 machines and to nothing elsewhere. + + +The data arrays used as input and output of the DCT transform subroutine will +be declared using a separate typedef; they could be arrays of "short", "int" +or "long" independently of the above choices. This would depend on what is +needed to make the compiler generate correct and efficient multiply/add code +in the DCT inner loops. No significant speed or memory penalty will be paid +to have a different representation than is used in the main image storage +arrays, since some additional value-by-value processing is done at the time of +creation or extraction of the DCT data anyway (e.g., add/subtract 128). + + +*** Poor man's object-oriented programming *** + +It should be pretty clear by now that we have a lot of quasi-independent +steps, many of which have several possible behaviors. To avoid cluttering the +code with lots of switch statements, we'll use a simple form of object-style +programming to separate out the different possibilities. + +For example, Huffman and arithmetic coding will be implemented as two separate +modules that present the same external interface; at runtime, the calling code +will access the proper module indirectly through an "object". + +We can get the limited features we need while staying within portable C. The +basic tool is a function pointer. An "object" is just a struct containing one +or more function pointer fields, each of which corresponds to a method name in +real object-oriented languages. During initialization we fill in the function +pointers with references to whichever module we have determined we need to use +in this run. Then invocation of the module is done by indirecting through a +function pointer; on most architectures this is no more expensive (and +possibly cheaper) than a switch, which would be the only other way of making +the required run-time choice. The really significant benefit, of course, is +keeping the source code clean and well structured. + +For example, the interface for entropy decoding (Huffman or arithmetic +decoding) might look like this: + + struct function_ptr_struct { + ... + /* Entropy decoding methods */ + void (*prepare_for_scan) (); + void (*get_next_mcu) (); + ... + }; + + typedef struct function_ptr_struct * function_ptrs; + +The struct pointer is what will actually be passed around. A call site might +look like this: + + some_function (function_ptrs fptrs) + { + ... + (*fptrs->get_next_mcu) (...); + ... + } + +(It might be worth inventing some specialized macros to hide the rather ugly +syntax for method definition and call.) Note that the caller doesn't know how +many different get_next_mcu procedures there are, what their real names are, +nor how to choose which one to call. + +An important benefit of this scheme is that it is easy to provide multiple +versions of any method, each tuned to a particular case. While a lot of +precalculation might be done to select an optimal implementation of a method, +the cost per invocation is constant. For example, the MCU extraction step +might have a "generic" method, plus one or more "hardwired" methods for the +most popular sampling factors; the hardwired methods would be faster because +they'd use straight-line code instead of for-loops. The cost to determine +which method to use is paid only once, at startup, and the selection criteria +are hidden from the callers of the method. + +This plan differs a little bit from usual object-oriented structures, in that +only one instance of each object class will exist during execution. The +reason for having the class structure is that on different runs we may create +different instances (choose to execute different modules). + +To minimize the number of object pointers that have to be passed around, it +will be easiest to have just a few big structs containing all the method +pointers. We'll actually use two such structs, one for "globally" defined +methods (applicable to the whole file or to all components of the current +scan) and one for methods applicable to a single component. There'll be one +copy of the second kind of struct for each component of the current scan. +This is necessary so that preselection of an optimal method can be done based +on component-specific information (like sampling ratios...) + +Because of this choice, it's best not to think of an "object" as a specific +data structure. Rather, an "object" is just a group of related methods. +There would typically be one or more C modules (source files) providing +concrete implementations of those methods. You can think of the term +"method" as denoting the common interface presented by some set of functions, +and "object" as denoting a group of common method interfaces, or the total +shared interface behavior of a group of modules. + + +*** Data chunk sizes *** + +To make the cost of this object-oriented style really minimal, we should make +sure that each method call does a fair amount of computation. To do that we +should pass large chunks of data around; for example, the colorspace +conversion method should process much more than one pixel per call. + +For many steps, the most natural unit of data seems to be an "MCU row". +This consists of one complete horizontal strip of the image, as high as an +MCU. In a noninterleaved scan, an MCU row is always eight samples high (when +looking at samples) or one 8x8 block high (when looking at coefficients). In +an interleaved scan, an MCU row consists of all the data for one horizontal +row of MCUs; this may be from one to four blocks high (eight to thirty-two +samples) depending on the sampling factors. The height and width of an MCU +row may be different in each component. (Note that the height and width of an +MCU row changes at the subsampling and de-subsampling steps. An unsubsampled +image has the same size in each component. The preceding statements apply to +the subsampled dimensions.) + +For example, consider a 1024-pixel-wide image using (2h:2v)(1h:1v)(1h:1v) +subsampling. In the noninterleaved case, an MCU row of Y would contain 8x1024 +samples or the same number of frequency coefficients, so it would occupy +8K bytes (samples) or 16K bytes (coefficients). An MCU row of Cb or Cr would +contain 8x512 samples and occupy half as much space. In the interleaved case, +an MCU row would contain 16x1024 Y samples, 8x512 Cb and 8x512 Cr samples, so +a total of 24K (samples) or 48K (coefficients) would be needed. This is a +reasonable amount of data to expect to retain in memory at one time. (Bear in +mind that we'll usually need to have several MCU rows resident in memory at +once, at the inputs and outputs to various pipeline steps.) + +The worst case is probably (2h:4v)(1h:1v)(1h:1v) interleaving (this uses 10 +blocks per MCU, which is the maximum allowed by the spec). An MCU will then +contain 32 sample rows worth of Y, so it would occupy 40K or 80K bytes for a +1024-pixel-wide image. The most memory-intensive step is probably cross-block +smoothing, for which we'd need 3 MCU rows of coefficients as input and another +one as output; that would be 320K of working storage. Anything much larger +would not fit in an 80x86 machine. (To decompress wider pictures on an 80x86, +we'll have to skip cross-block smoothing or else use temporary files.) + +This unit is thus a reasonable-sized chunk for passing through the pipeline. +Of course, its major advantage is that it is a natural chunk size for the MCU +assembly and disassembly steps to work with. + +For the entropy (Huffman or arithmetic) encoding/decoding steps, the most +convenient chunk is a single MCU: one 8x8 block if not interleaved, three to +ten such blocks if interleaved. The advantage of this is that when handling +interleaved data, the blocks have the same sequence of component membership on +each call. (For example, Y,Y,Y,Y,Cb,Cr when using (2h:2v)(1h:1v)(1h:1v) +subsampling.) The code needs to know component membership so that it can +apply the right set of compression coefficients to each block. A prebuilt +array describing this membership can be used during each call. This chunk +size also makes it easy to handle restart intervals: just count off one MCU +per call and reinitialize when the count reaches zero (restart intervals are +specified in numbers of MCU). + +For similar reasons, one MCU is also the best chunk size for the frequency +coefficient quantization and dequantization steps. + +For subsampling and desubsampling, the best chunk size is to have each call +transform Vk sample rows from or to Vmax sample rows (Vk = this component's +vertical sampling factor, Vmax = largest vertical sampling factor). There are +eight such chunks in each MCU row. Using a whole MCU row as the chunk size +would reduce function call overhead a fraction, but would imply more buffering +to provide context for cross-pixel smoothing. + + +*** Compression object structure *** + +I propose the following set of objects for the compressor. Here an "object" +is the common interface for one or more modules having comparable functions. + +Most of these objects can be justified as information-hiding modules. +I've indicated what information is private to each object/module. + +Note that in all cases, the caller of a method is expected to have allocated +any storage needed for it to return its result. (Typically this storage can +be re-used in successive calls, so malloc'ing and free'ing once per call is +not reasonable.) Also, much of the context required (compression parameters, +image size, etc) will be passed around in large common data structures, which +aren't described here; see the header files. Notice that any object that +might need to allocate working storage receives an "init" and a "term" call; +"term" should be careful to free all allocated storage so that the JPEG system +can be used multiple times during a program run. (For the same reason, +depending on static initialization of variables is a no-no.) + +1. Input file conversion to standardized form. This provides these methods: + input_init: read the file header, report image size & component count. + get_input_row: read one pixel row, return it in our standard format. + input_term: finish up at the end. + In implementations that support multiple input formats, input_init could + set up an appropriate get_input_row method depending on the format it + finds. Note that in most applications, the selection and opening of the + input file will be under the control of the user interface module; and + indeed the user interface may have already read the input header, so that + all that input_init may have to do is return previously saved values. The + behind-the-scenes interaction between this object and the user interface is + not specified by this architecture. + (Hides format of input image and mechanism used to read it. This code is + likely to vary considerably from one implementation to another. Note that + the color space and number of color components of the source are not hidden; + but they are used only by the next object.) + +2. Gamma and color space conversion. This provides three methods: + colorin_init: initialization. + get_sample_rows: read, convert, and return a specified number of pixel + rows (not more than remain in the picture). + colorin_term: finish up at the end. + The most efficient approach seems to be for this object to call + get_input_row directly, rather than being passed the input data; that way, + any intermediate storage required can be local to this object. + (get_sample_rows might tell get_input_row to read directly into its own + output area and then convert in place; or it may do something different. + For example, conversion in place wouldn't work if it is changing the number + of color components.) The output of this step is in the standardized + sample array format shown previously. + (Hides all knowledge of color space semantics and conversion. Remaining + modules only need to know the number of JPEG components.) + +3. Edge expansion: needs only a single method. + edge_expand: Given an NxM sample array, expand to a desired size (a + multiple of the MCU dimensions) by duplicating the last + row or column. Repeat for each component. + Expansion will occur in place, so the caller must have pre-allocated enough + storage. (I'm assuming that it is easier and faster to do this expansion + than it is to worry about boundary conditions in the next two steps. + Notice that vertical expansion will occur only once, at the bottom of the + picture, so only horizontal expansion by a few pixels is speed-critical.) + (This doesn't really hide any information, so maybe it could be a simple + subroutine instead of a method. Depends on whether we want to be able to + use alternative, optimized methods.) + +4. Subsampling: this will be applied to one component at a time. + subsample_init: initialize (precalculate convolution factors, for + example). This will be called once per scan. + subsample: Given a sample array, reduce it to a smaller number of + samples using specified sampling factors. + subsample_term: clean up at the end of a scan. + If the current component has vertical sampling factor Vk and the largest + sampling factor is Vmax, then the input is always Vmax sample rows (whose + width is a multiple of Hmax) and the output is always Vk sample rows. + Vmax additional rows above and below the nominal input rows are also passed + for use by partial-pixel-averaging sampling methods. (Is this necessary?) + At the top and bottom of the image, these extra rows are copies of the + first or last actual input row. + (This hides whether and how cross-pixel averaging occurs.) + +5. MCU extraction (creation of a single sequence of 8x8 sample blocks). + extract_init: initialize as needed. This will be called once per scan. + extract_MCUs: convert a sample array to a sequence of MCUs. + extract_term: clean up at the end of a scan. + Given one or more MCU rows worth of image data, extract sample blocks in the + appropriate order; pass these off to subsequent steps one MCU at a time. + The input must be a multiple of the MCU dimensions. It will probably be + most convenient for the DCT transform, frequency quantization, and zigzag + reordering of each block to be done as simple subroutines of this step. + Once a transformed MCU has been completed, it'll be passed off to a + method call, which will be passed as a parameter to extract_MCUs. + That routine might either encode and output the MCU immediately, or buffer + it up for later output if we want to do global optimization of the entropy + encoding coefficients. Note: when outputting a noninterleaved file this + object will be called separately for each component. Direct output could + be done for the first component, but the others would have to be buffered. + (Again, an object mainly on the grounds that multiple instantiations might + be useful.) + +6. DCT transformation of each 8x8 block. This probably doesn't have to be a + full-fledged method, but just a plain subroutine that will be called by MCU + extraction. One 8x8 block will be processed per call. + +7. Quantization scaling and zigzag reordering of the elements in each 8x8 + block. (This can probably be a plain subroutine called once per block by + MCU extraction; hard to see a need for multiple instantiations here.) + +8. Entropy encoding (Huffman or arithmetic). + entropy_encoder_init: prepare for one scan. + entropy_encode: accepts an MCU's worth of quantized coefficients, + encodes and outputs them. + entropy_encoder_term: finish up at end of a scan (dump any buffered + bytes, for example). + The data output by this module will be sent to the entropy_output method + provided by the pipeline controller. (It will probably be worth using + buffering to pass multiple bytes per call of the output method.) The + output method could be just write_jpeg_data, but might also be a dummy + routine that counts output bytes (for use during cut-and-try coefficient + optimization). + (This hides which entropy encoding method is in use.) + +9. JPEG file header construction. This will provide these methods: + write_file_header: output the initial header. + write_scan_header: output scan header (called once per component + if noninterleaved mode). + write_jpeg_data: the actual data output method for the preceding step. + write_scan_trailer: finish up after one scan. + write_file_trailer: finish up at end of file. + Note that compressed data is passed to the write_jpeg_data method, in case + a simple fwrite isn't appropriate for some reason. + (This hides which variant JPEG file format is being written. Also, the + actual mechanism for writing the file is private to this object and the + user interface.) + +10. Pipeline control. This object will provide the "main loop" that invokes + all the pipeline objects. Note that we will need several different main + loops depending on the situation (interleaved output or not, global + optimization of encoding parameters or not, etc). This object will do + most of the memory allocation, since it will provide the working buffers + that are the inputs and outputs of the pipeline steps. + (An object mostly to support multiple instantiations; however, overall + memory management and sequencing of operations are known only here.) + +11. Overall control. This module will provide at least two routines: + jpeg_compress: the main entry point to the compressor. + per_scan_method_selection: called by pipeline controllers for + secondary method selection passes. + jpeg_compress is invoked from the user interface after the UI has selected + the input and output files and obtained values for all compression + parameters that aren't dynamically determined. jpeg_compress performs + basic initialization (e.g., calculating the size of MCUs), does the + "global" method selection pass, and finally calls the selected pipeline + control object. (Per-scan method selections will be invoked by the + pipeline controller.) + Note that jpeg_compress can't be a method since it is invoked prior to + method selection. + +12. User interface; this is the architecture's term for "the rest of the + application program", i.e., that which invokes the JPEG compressor. In a + standalone JPEG compression program the UI need be little more than a C + main() routine and argument parsing code; but we can expect that the JPEG + compressor may be incorporated into complex graphics applications, wherein + the UI is much more complex. Much of the UI will need to be written + afresh for each non-Unix-like platform the compressor is ported to. + The UI is expected to supply input and output files and values for all + non-automatically-chosen compression parameters. (Hence defaults are + determined by the UI; we should probably provide helpful routines to fill + in recommended defaults.) The UI must also supply error handling + routines and some mechanism for trace messages. + (This module hides the user interface provided --- command line, + interactive, etc. Except for error/message handling, the UI calls the + portable JPEG code, not the other way around.) + +13. (Optional) Compression parameter selection control. + entropy_optimize: given an array of MCUs ready to be fed to entropy + encoding, find optimal encoding parameters. + The actual optimization algorithm ought to be separated out as an object, + even though a special pipeline control method will be needed. (The + pipeline controller only has to understand that the output of extract_MCUs + must be built up as a virtual array rather than fed directly to entropy + encoding and output. This pipeline behavior may also be useful for future + implementation of hierarchical modes, etc.) + To minimize the amount of control logic in the optimization module, the + pipeline control doesn't actually hand over big-array pointers, but rather + an "iterator": a function which knows how to scan the stored image. + (This hides the details of the parameter optimization algorithm.) + + The present design doesn't allow for multiple passes at earlier points + in the pipeline, but allowing that would only require providing some + new pipeline control methods; nothing else need change. + +14. A memory management object. This will provide methods to allocate "small" + things and "big" things. Small things have to fit in memory and you get + back direct pointers (this could be handled by direct calls to malloc, but + it's cleaner not to assume malloc is the right routine). "Big" things + mean buffered images for multiple passes, noninterleaved output, etc. + In this case the memory management object will give you room for a few MCU + rows and you have to ask for access to the next few; dumping and reloading + in a temporary file will go on behind the scenes. (All big objects are + image arrays containing either samples or coefficients, and will be + scanned top-to-bottom some number of times, so we can apply this access + model easily.) On a platform with virtual memory, the memory manager can + treat small and big things alike: just malloc up enough virtual memory for + the whole image, and let the operating system worry about swapping the + image to disk. + + Most of the actual calls on the memory manager will be made from pipeline + control objects; changing any data item from "small" to "big" status would + require a new pipeline control object, since it will contain the logic to + ask for a new chunk of a big thing. Thus, one way in which pipeline + controllers will vary is in which structures they treat as big. + + The memory manager will need to be told roughly how much space is going to + be requested overall, so that it can figure out how big a buffer is safe + to allocate for a "big" object. (If it happens that you are dealing with + a small image, you'd like to decide to keep it all in memory!) The most + flexible way of doing this is to divide allocation of "big" objects into + two steps. First, there will be one or more "request" calls that indicate + the desired object sizes; then an "instantiate" call causes the memory + manager to actually construct the objects. The instantiation must occur + before the contents of any big object can be accessed. + + For 80x86 CPUs, we would like the code to be compilable under small or + medium model, meaning that pointers are 16 bits unless explicitly declared + FAR. Hence space allocated by the "small" allocator must fit into the + 64Kb default data segment, along with stack space and global/static data. + For normal JPEG operations we seem to need only about 32Kb of such space, + so we are within the target (and have a reasonable slop for the needs of + a surrounding application program). However, some color quantization + algorithms need 64Kb or more of all-in-memory space in order to create + color histograms. For this purpose, we will also support "medium" size + things. These are semantically the same as "small" things but are + referenced through FAR pointers. + + The following methods will be needed: + alloc_small: allocate an object of given size; use for any random + data that's not an image array. + free_small: release same. + alloc_medium: like alloc_small, but returns a FAR pointer. + free_medium: release same. + alloc_small_sarray: construct an all-in-memory image sample array. + free_small_sarray: release same. + alloc_small_barray, + free_small_barray: ditto for block (coefficient) arrays. + request_big_sarray: request a virtual image sample array. The size + of the in-memory buffer will be determined by the + memory manager, but it will always be a multiple + of the passed-in MCU height. + request_big_barray: ditto for block (coefficient) arrays. + alloc_big_arrays: instantiate all the big arrays previously requested. + This call will also pass some info about future + memory demands, so that the memory manager can + figure out how much space to leave unallocated. + access_big_sarray: obtain access to a specified portion of a virtual + image sample array. + access_big_barray: ditto for block (coefficient) arrays. + free_big_sarray: release a virtual sample array. + free_big_barray: ditto for block (coefficient) arrays. + + alloc_big_arrays will be called by the pipeline controller, which does + most of the memory allocation anyway. The only reason for having separate + request calls is to allow some of the other modules to get big arrays. + The pipeline controller is required to give an upper bound on total future + small-array requests, so that this space can be discounted. (A fairly + conservative estimate will be adequate.) Future small-object requests + aren't counted; the memory manager has to use a slop factor for those. + 10K or so seems to be sufficient. (In an 80x86, small objects aren't an + issue anyway, since they don't compete for far-heap space. "Medium"-size + objects will have to be counted separately.) + + The distinction between sample and coefficient array routines is annoying, + but it has to be maintained for machines in which "char *" is represented + differently from "int *"... on byte-addressable machines some of these + methods could point to the same code. + + The array routines will operate on only 2-D arrays (one component at a + time), since different components may require different-size arrays. + + (This object hides the knowledge of whether virtual memory is available, + as well as the actual interface to OS and library support routines.) + +Note that any given implementation will presumably contain only one +instantiation of input file header reading, overall control, user interface, +and memory management. Thus these could be called as simple subroutines, +without bothering with an object indirection. This is essential for overall +control (which has to initialize the object structure); I'm undecided whether +to impose objectness on the other three. + + +*** Decompression object structure *** + +I propose the following set of objects for decompression. The general +comments at the top of the compression object section also apply here. + +1. JPEG file scanning. This will provide these methods: + read_file_header: read the file header, determine which variant + JPEG format is in use, read everything through SOF. + read_scan_header: read scan header (up through SOS). This is called + after read_file_header and again after each scan; + it returns TRUE if it finds SOS, FALSE if EOI. + read_jpeg_data: fetch data for entropy decoder. + read_scan_trailer: finish up after one scan, prepare for another call + of read_scan_header (may be a no-op). + read_file_trailer: finish up at end of file (probably a no-op). + The entropy decoder must deal with restart markers, but all other JPEG + marker types will be handled in this object; useful data from the markers + will be extracted into data structures available to subsequent routines. + Note that on exit from read_file_header, only the SOF-marker data should be + assumed valid (image size, component IDs, sampling factors); other data + such as Huffman tables may not appear until after the SOF. The overall + image size and colorspace can be determined after read_file_header, but not + whether or how the data is interleaved. (This hides which variant JPEG + file format is being read. In particular, for JPEG-in-TIFF the read_header + routines might not be scanning standard JPEG markers at all; they could + extract the data from TIFF tags. The user interface will already have + opened the input file and possibly read part of the header before + read_file_header is called.) + + NOTE: for JFIF/raw-JPEG file format, the read_jpeg_data routine is actually + supplied by the user interface; the jrdjfif module uses read_jpeg_data + internally to scan the input stream. This makes it possible for the user + interface module to single-handedly implement special applications like + reading from a non-stdio source. For JPEG-in-TIFF format, the need for + random access will make it impossible for this to work; hence the TIFF + header module will probably override the UI read_jpeg_data routine. + Non-stdio input from a TIFF file will require extensive surgery to the TIFF + header module, if indeed it is practical at all. + +2. Entropy (Huffman or arithmetic) decoding of the coefficient sequence. + entropy_decoder_init: prepare for one scan. + entropy_decode: decodes and returns an MCU's worth of quantized + coefficients per call. + entropy_decoder_term: finish up after a scan (may be a no-op). + This will read raw data by calling the read_jpeg_data method (I don't see + any reason to provide a further level of indirection). + (This hides which entropy encoding method is in use.) + +3. Quantization descaling and zigzag reordering of the elements in each 8x8 + block. (This can probably be a plain subroutine called once per block; + hard to see a need for multiple instantiations here.) + +4. MCU disassembly (conversion of a possibly interleaved sequence of 8x8 + blocks back to separate components in pixel map order). + disassemble_init: initialize. This will be called once per scan. + disassemble_MCU: Given an MCU's worth of dequantized blocks, + distribute them into the proper locations in a + coefficient image array. + disassemble_term: clean up at the end of a scan. + Probably this should be called once per MCU row and should call the + preceding two objects repeatedly to obtain the row's data. The output is + always a multiple of an MCU's dimensions. + (An object on the grounds that multiple instantiations might be useful.) + +5. Cross-block smoothing per JPEG section 13.10 or a similar algorithm. + smooth_coefficients: Given three block rows' worth of a single + component, emit a smoothed equivalent of the + middle row. The "above" and "below" pointers + may be NULL if at top/bottom of image. + The pipeline controller will do the necessary buffering to provide the + above/below context. Smoothing will be optional since a good deal of + extra memory is needed to buffer the additional block rows. + (This object hides the details of the smoothing algorithm.) + +6. Inverse DCT transformation of each 8x8 block. (This can be a plain + subroutine processing one block per call.) + +7. De-subsampling and smoothing: this will be applied to one component at a + time. Note that cross-pixel smoothing, which was a separate step in the + prototype code, will now be performed simultaneously with expansion. + unsubsample_init: initialize (precalculate convolution factors, for + example). This will be called once per scan. + unsubsample: Given a sample array, enlarge it by specified sampling + factors. + unsubsample_term: clean up at the end of a scan. + If the current component has vertical sampling factor Vk and the largest + sampling factor is Vmax, then the input is always Vk sample rows (whose + width is a multiple of Hk) and the output is always Vmax sample rows. + Vk additional rows above and below the nominal input rows are also passed + for use in cross-pixel smoothing. At the top and bottom of the image, + these extra rows are copies of the first or last actual input row. + (This hides whether and how cross-pixel smoothing occurs.) + +8. Cropping to the original pixel dimensions (throwing away duplicated + pixels at the edges). This won't be a separate object, just an + adjustment of the nominal image size in the pipeline controller. + +9. Color space reconversion and gamma adjustment. + colorout_init: initialization. This will be passed the component + data from read_file_header, and will determine the + number of output components. + color_convert: convert a specified number of pixel rows. Input and + output are image arrays of same size but possibly + different numbers of components. + colorout_term: cleanup (probably a no-op except for memory dealloc). + In practice will always be given an MCU row's worth of pixel rows, except + at the bottom where a smaller number of rows may be left over. Note that + this object works on all the components at once. + (Hides all knowledge of color space semantics and conversion. Remaining + modules only need to know the number of JPEG and output components.) + +10. Color quantization (used only if a colormapped output format is requested). + We use two different strategies depending on whether one-pass (on-the-fly) + or two-pass quantization is requested. Note that the two-pass interface + is actually designed to let the quantizer make any number of passes. + color_quant_init: initialization, allocate working memory. In 1-pass + quantization, should call put_color_map. + color_quantize: convert a specified number of pixel rows. Input + and output are image arrays of same size, but input + is N coefficients and output is only one. (Used only + in 1-pass quantization.) + color_quant_prescan: prescan a specified number of pixel rows in + 2-pass quantization. + color_quant_doit: perform multi-pass color quantization. Input is a + "big" sample image, output is via put_color_map and + put_pixel_rows. (Used only in 2-pass quantization.) + color_quant_term: cleanup (probably a no-op except for memory dealloc). + For one-pass quantization the image is simply processed by color_quantize, + a few rows at a time. For two-pass quantization, the pipeline controller + accumulates the output of color_convert into a "big" sample image. The + color_quant_prescan method is invoked during this process so that the + quantizer can accumulate statistics. At the end of the image, + color_quant_doit is called; it must rescan the "big" image and pass + converted data to the output module. Additional scans of the image could + be made before the output pass is done (in fact, prescan could be a no-op). + As with entropy parameter optimization, the pipeline controller actually + passes an iterator function rather than direct access to the big image. + NOTE: it might be better to do this on the internal color space instead of + RGB? If so, it would need to be performed one step earlier. + (Hides color quantization algorithm.) + +11. Writing of the desired image format. + output_init: produce the file header given data from read_file_header. + put_color_map: output colormap, if any (called by color quantizer). + put_pixel_rows: output image data in desired format. + output_term: finish up at the end. + Note that whether colormapping is needed will be determined by the user + interface object prior to method selection. In implementations that + support multiple output formats, the actual output format will also be + determined by the user interface. + (Hides format of output image and mechanism used to write it. Note that + several other objects know the color model used by the output format. The + actual mechanism for writing the file is private to this object and the + user interface.) + +12. Pipeline control. This object will provide the "main loop" that invokes + all the pipeline objects. Note that we will need several different main + loops depending on the situation (interleaved input or not, whether to + apply cross-block smoothing or not, etc). We may want to divvy up the + pipeline controllers into two levels, one that retains control over the + whole file and one that is invoked per scan. + This object will do most of the memory allocation, since it will provide + the working buffers that are the inputs and outputs of the pipeline steps. + (An object mostly to support multiple instantiations; however, overall + memory management and sequencing of operations are known only here.) + +13. Overall control. This module will provide at least two routines: + jpeg_decompress: the main entry point to the decompressor. + per_scan_method_selection: called by pipeline controllers for + secondary method selection passes. + jpeg_decompress is invoked from the user interface after the UI has + selected the input and output files and obtained values for all + user-specified options (e.g., output file format, whether to do block + smoothing). jpeg_decompress calls read_file_header, performs basic + initialization (e.g., calculating the size of MCUs), does the "global" + method selection pass, and finally calls the selected pipeline control + object. (Per-scan method selections will be invoked by the pipeline + controller.) + Note that jpeg_decompress can't be a method since it is invoked prior to + method selection. + +14. User interface; this is the architecture's term for "the rest of the + application program", i.e., that which invokes the JPEG decompressor. + The UI is expected to supply input and output files and values for all + operational parameters. The UI must also supply error handling routines. + At the moment I can't think of any nonfatal errors the JPEG code is likely + to report, so a single report-this-error-and-exit method should be + sufficient. + (This module hides the user interface provided --- command line, + interactive, etc. Except for error handling, the UI calls the portable + JPEG code, not the other way around.) + +15. A memory management object. This will be identical to the memory + management for compression (and will be the same code, in combined + programs). See above for details. + + +*** Initial method selection *** + +The main ugliness in this design is the portion of startup that will select +which of several instantiations should be used for each of the objects. (For +example, Huffman or arithmetic for entropy encoding; one of several pipeline +controllers depending on interleaving, the size of the image, etc.) It's not +really desirable to have a single chunk of code that knows the names of all +the possible instantiations and the conditions under which to select each one. + +The best approach seems to be to provide a selector function for each object +(group of related method calls). This function knows about each possible +instantiation of its object and how to choose the right one; but it doesn't +know about any other objects. + +Note that there will be several rounds of method selection: at initial startup, +after overall compression parameters are determined (after the file header is +read, if decompressing), and one in preparation for each scan (this occurs +more than once if the file is noninterleaved). Each object method will need +to be clearly identified as to which round sets it up. + + +*** Implications of DNL marker *** + +Some JPEG files may use a DNL marker to postpone definition of the image +height (this would be useful for a fax-like scanner's output, for instance). +In these files the SOF marker claims the image height is 0, and you only +find out the true image height at the end of the first scan. + +We could handle these files as follows: +1. Upon seeing zero image height, replace it by 65535 (the maximum allowed). +2. When the DNL is found, update the image height in the global image + descriptor. +This implies that pipeline control objects must avoid making copies of the +image height, and must re-test for termination after each MCU row. This is +no big deal. + +In situations where image-size data structures are allocated, this approach +will result in very inefficient use of virtual memory or +much-larger-than-necessary temporary files. This seems acceptable for +something that probably won't be a mainstream usage. People might have to +forgo use of memory-hogging options (such as two-pass color quantization or +noninterleaved JPEG files) if they want efficient conversion of such files. +(One could improve efficiency by demanding a user-supplied upper bound for the +height, less than 65536; in most cases it could be much less.) + +Alternately, we could insist that DNL-using files be preprocessed by a +separate program that reads ahead to the DNL, then goes back and fixes the SOF +marker. This is a much simpler solution and is probably far more efficient. +Even if one wants piped input, buffering the first scan of the JPEG file +needs a lot smaller temp file than is implied by the maximum-height method. +For this approach we'd simply treat DNL as a no-op in the decompressor (at +most, check that it matches the SOF image height). + +We will not worry about making the compressor capable of outputting DNL. Note +that something similar to the first scheme above could be applied if anyone +ever wants to make that work. + + +*** Notes for MS-DOS implementors *** + +The standalone cjpeg and djpeg applications can be compiled in "small" memory +model, at least at the moment; as the code grows we may be forced to switch to +"medium" model. (Small = both code and data pointers are near by default; +medium = far code pointers, near data pointers.) Medium model will slow down +calls through method pointers, but I don't think this will amount to any +significant speed penalty. + +When integrating the JPEG code into a larger application, it's a good idea to +stay with a small-data-space model if possible. An 8K stack is much more than +sufficient for the JPEG code, and its static data requirements are less than +1K. When executed, it will typically malloc about 10K worth of near heap +space (and lots of far heap, but that doesn't count in this calculation). +This figure will vary depending on image size and other factors, but figuring +20K should be more than sufficient. Thus you have about 35K available for +other modules' static data and near heap requirements before you need to go to +a larger memory model. The C library's static data will account for several K +of this, but that still leaves a good deal for your needs. (If you are tight +on space, you could reduce JPEG_BUF_SIZE from 4K to 1K to save 3K of near heap +space.) + +As the code is improved, we will endeavor to hold the near data requirements +to the range given above. This does imply that certain data structures will +be allocated as FAR although they would fit in near space if we assumed the +JPEG code is stand-alone. (The LZW tables in jrdgif/jwrgif are examples.) +To make an optimal implementation, you might want to move these structures +back to near heap if you know there is sufficient space. + + +*** Potential optimizations *** + +For colormapped input formats it might be worthwhile to merge the input file +reading and the colorspace conversion steps; in other words, do the colorspace +conversion by hacking up the colormap before inputting the image body, rather +than doing the conversion on each pixel independently. Not clear if this is +worth the uglification involved. In the above design for the compressor, only +the colorspace conversion step ever sees the output of get_input_row, so this +sort of thing could be done via private agreement between those two modules. + +Level shift from 0..255 to -128..127 may be done either during colorspace +conversion, or at the moment of converting an 8x8 sample block into the format +used by the DCT step (which will be signed short or long int). This could be +selectable by a compile-time flag, so that the intermediate steps can work on +either signed or unsigned chars as samples, whichever is most easily handled +by the platform. However, making sure that rounding is done right will be a +lot easier if we can assume positive values. At the moment I think that +benefit is worth the overhead of "& 0xFF" when reading out sample values on +signed-char-only machines. diff --git a/codingrules b/codingrules new file mode 100644 index 0000000..fd6f700 --- /dev/null +++ b/codingrules @@ -0,0 +1,99 @@ + + JPEG SYSTEM CODING RULES 27-SEP-91 + +Since numerous people will be contributing code and bug fixes, it's important +to establish a common coding style. The goal of using similar coding styles +is much more important than the details of just what that style is. + +I suggest we follow the recommendations of "Recommended C Style and Coding +Standards" revision 6.1 (Cannon et al. as modified by Spencer, Keppel and +Brader). I have placed a copy of this document in the jpeg FTP archive (see +jpeg/doc/cstyle.ms.tbl.Z, or cstyle.txt.Z for those without nroff/tbl). + +Unless someone has a real strong objection, let's do block comments thusly: + +/* + * Block comments in this style. + */ + +and indent statements in K&R style, e.g., + + if (test) { + then-part; + } else { + else-part; + } + +I suggest that multi-word names be written in the style multi_word_name +rather than multiWordName, but I am open to argument on this. + + +I would like to use function prototypes everywhere, and rely on automatic +source code transformation to feed non-ANSI C compilers. The best tool +I have so far found for this is 'ansi2knr.c', which is part of Ghostscript. +ansi2knr is not very bright, so it imposes a format requirement on function +declarations: the function name MUST BEGIN IN COLUMN 1. Thus all functions +should be written in the following style: + +static int * +function_name (int a, char *b) +{ + code... +} + +ansi2knr won't help with method declarations (function pointers in structs). +I suggest we use a macro to declare method pointers, something like this: + +#ifdef PROTO +#define METHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define METHOD(type,methodname,arglist) type (*methodname) () +#endif + +which is used like this: + +struct function_pointers { + METHOD(void, init_entropy_encoder, (functptrs fptrs, jparms *jp)); + METHOD(void, term_entropy_encoder, (void)); +}; + +Note the set of parentheses surrounding the parameter list. + +A similar solution is used for external function declarations (see the PP +macro in jpegdata.h). + +If the code is to work on non-ANSI compilers, you cannot rely on a prototype +declaration to coerce actual parameters into the right types. Therefore, use +explicit casts on actual parameters whenever the actual parameter type is not +identical to the formal parameter. Beware of implicit conversions to "int". + +It seems there are some non-ANSI compilers in which the sizeof() operator +is defined to return int, while size_t is defined as long. Needless to say, +this is brain-damaged. Always use the SIZEOF() macro in place of sizeof(), +so that the result is guaranteed to be of type size_t. + + +We can expect that the JPEG compressor and decompressor will be incorporated +into larger programs. Therefore, the following rules are important: + +1. Avoid direct use of any file I/O, "malloc", error report printouts, etc; +pass these through the common routines provided. + +2. Assume that the JPEG code may be invoked more than once per program run; +therefore, do not rely on static initialization of variables, and be careful +to release all allocated storage at the end of processing. + +3. Minimize global namespace pollution. Functions should be declared static +wherever possible. (Note that our method-based calling conventions help this +a lot: in many modules only the method-selector function will ever need to be +called directly, so only that function need be externally visible.) All +global function names should begin with "j", and should be unique in the first +six characters for portability reasons. +Don't use global variables at all; anything that must be used in another +module should be put into parameters (there'll be some large structs passed +around for this purpose). + +4. Source file names should also begin with "j"; remember to keep them to +eight characters (plus ".c" or ".h", etc) to make life easy for MS-DOSers. +Do not put code for both compression and decompression into the same source +file. diff --git a/egetopt.c b/egetopt.c new file mode 100644 index 0000000..8183d35 --- /dev/null +++ b/egetopt.c @@ -0,0 +1,276 @@ +/* + * egetopt.c -- Extended 'getopt'. + * + * A while back, a public-domain version of getopt() was posted to the + * net. A bit later, a gentleman by the name of Keith Bostic made some + * enhancements and reposted it. + * + * In recent weeks (i.e., early-to-mid 1988) there's been some + * heated discussion in comp.lang.c about the merits and drawbacks + * of getopt(), especially with regard to its handling of '?'. + * + * In light of this, I have taken Mr. Bostic's public-domain getopt() + * and have made some changes that I hope will be considered to be + * improvements. I call this routine 'egetopt' ("Extended getopt"). + * The default behavior of this routine is the same as that of getopt(), + * but it has some optional features that make it more useful. These + * options are controlled by the settings of some global variables. + * By not setting any of these extra global variables, you will have + * the same functionality as getopt(), which should satisfy those + * purists who believe getopt() is perfect and can never be improved. + * If, on the other hand, you are someone who isn't satisfied with the + * status quo, egetopt() may very well give you the added capabilities + * you want. + * + * Look at the enclosed README file for a description of egetopt()'s + * new features. + * + * The code was originally posted to the net as getopt.c by ... + * + * Keith Bostic + * ARPA: keith@seismo + * UUCP: seismo!keith + * + * Current version: added enhancements and comments, reformatted code. + * + * Lloyd Zusman + * Master Byte Software + * Los Gatos, California + * Internet: ljz@fx.com + * UUCP: ...!ames!fxgrp!ljz + * + * May, 1988 + */ + +/* + * If you want, include stdio.h or something where EOF and NULL are defined. + * However, egetopt() is written so as not to need stdio.h, which should + * make it significantly smaller on some systems. + */ + +#ifndef EOF +# define EOF (-1) +#endif /* ! EOF */ + +#ifndef NULL +# define NULL (char *)0 +#endif /* ! NULL */ + +/* + * None of these constants are referenced in the executable portion of + * the code ... their sole purpose is to initialize global variables. + */ +#define BADCH (int)'?' +#define NEEDSEP (int)':' +#define MAYBESEP (int)'\0' +#define ERRFD 2 +#define EMSG "" +#define START "-" + +/* + * Here are all the pertinent global variables. + */ +int opterr = 1; /* if true, output error message */ +int optind = 1; /* index into parent argv vector */ +int optopt; /* character checked for validity */ +int optbad = BADCH; /* character returned on error */ +int optchar = 0; /* character that begins returned option */ +int optneed = NEEDSEP; /* flag for mandatory argument */ +int optmaybe = MAYBESEP;/* flag for optional argument */ +int opterrfd = ERRFD; /* file descriptor for error text */ +char *optarg; /* argument associated with option */ +char *optstart = START; /* list of characters that start options */ + + +/* + * Macros. + */ + +/* + * Conditionally print out an error message and return (depends on the + * setting of 'opterr' and 'opterrfd'). Note that this version of + * TELL() doesn't require the existence of stdio.h. + */ +#define TELL(S) { \ + if (opterr && opterrfd >= 0) { \ + char option = optopt; \ + write(opterrfd, *nargv, strlen(*nargv)); \ + write(opterrfd, (S), strlen(S)); \ + write(opterrfd, &option, 1); \ + write(opterrfd, "\n", 1); \ + } \ + return (optbad); \ +} + +/* + * This works similarly to index() and strchr(). I include it so that you + * don't need to be concerned as to which one your system has. + */ +static char * +_sindex(string, ch) +char *string; +int ch; +{ + if (string != NULL) { + for (; *string != '\0'; ++string) { + if (*string == (char)ch) { + return (string); + } + } + } + + return (NULL); +} + +/* + * Here it is: + */ +int +egetopt(nargc, nargv, ostr) +int nargc; +char **nargv; +char *ostr; +{ + static char *place = EMSG; /* option letter processing */ + register char *oli; /* option letter list index */ + register char *osi = NULL; /* option start list index */ + + if (nargv == (char **)NULL) { + return (EOF); + } + + if (nargc <= optind || nargv[optind] == NULL) { + return (EOF); + } + + if (place == NULL) { + place = EMSG; + } + + /* + * Update scanning pointer. + */ + if (*place == '\0') { + place = nargv[optind]; + if (place == NULL) { + return (EOF); + } + osi = _sindex(optstart, *place); + if (osi != NULL) { + optchar = (int)*osi; + } + if (optind >= nargc || osi == NULL || *++place == '\0') { + return (EOF); + } + + /* + * Two adjacent, identical flag characters were found. + * This takes care of "--", for example. + */ + if (*place == place[-1]) { + ++optind; + return (EOF); + } + } + + /* + * If the option is a separator or the option isn't in the list, + * we've got an error. + */ + optopt = (int)*place++; + oli = _sindex(ostr, optopt); + if (optopt == optneed || optopt == optmaybe || oli == NULL) { + /* + * If we're at the end of the current argument, bump the + * argument index. + */ + if (*place == '\0') { + ++optind; + } + TELL(": illegal option -- "); /* byebye */ + } + + /* + * If there is no argument indicator, then we don't even try to + * return an argument. + */ + ++oli; + if (*oli == '\0' || (*oli != optneed && *oli != optmaybe)) { + /* + * If we're at the end of the current argument, bump the + * argument index. + */ + if (*place == '\0') { + ++optind; + } + optarg = NULL; + } + /* + * If we're here, there's an argument indicator. It's handled + * differently depending on whether it's a mandatory or an + * optional argument. + */ + else { + /* + * If there's no white space, use the rest of the + * string as the argument. In this case, it doesn't + * matter if the argument is mandatory or optional. + */ + if (*place != '\0') { + optarg = place; + } + /* + * If we're here, there's whitespace after the option. + * + * Is it a mandatory argument? If so, return the + * next command-line argument if there is one. + */ + else if (*oli == optneed) { + /* + * If we're at the end of the argument list, there + * isn't an argument and hence we have an error. + * Otherwise, make 'optarg' point to the argument. + */ + if (nargc <= ++optind) { + place = EMSG; + TELL(": option requires an argument -- "); + } + else { + optarg = nargv[optind]; + } + } + /* + * If we're here it must have been an optional argument. + */ + else { + if (nargc <= ++optind) { + place = EMSG; + optarg = NULL; + } + else { + optarg = nargv[optind]; + if (optarg == NULL) { + place = EMSG; + } + /* + * If the next item begins with a flag + * character, we treat it like a new + * argument. This is accomplished by + * decrementing 'optind' and returning + * a null argument. + */ + else if (_sindex(optstart, *optarg) != NULL) { + --optind; + optarg = NULL; + } + } + } + place = EMSG; + ++optind; + } + + /* + * Return option letter. + */ + return (optopt); +} diff --git a/jbsmooth.c b/jbsmooth.c new file mode 100644 index 0000000..ad2138d --- /dev/null +++ b/jbsmooth.c @@ -0,0 +1,120 @@ +/* + * jbsmooth.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains cross-block smoothing routines. + * These routines are invoked via the smooth_coefficients method. + */ + +#include "jinclude.h" + +#ifdef BLOCK_SMOOTHING_SUPPORTED + + +/* + * Cross-block coefficient smoothing. + */ + +METHODDEF void +smooth_coefficients (decompress_info_ptr cinfo, + jpeg_component_info *compptr, + JBLOCKROW above, + JBLOCKROW currow, + JBLOCKROW below, + JBLOCKROW output) +{ + QUANT_TBL_PTR Qptr = cinfo->quant_tbl_ptrs[compptr->quant_tbl_no]; + long blocks_in_row = compptr->subsampled_width / DCTSIZE; + long col; + + /* First, copy the block row as-is. + * This takes care of the first & last blocks in the row, the top/bottom + * special cases, and the higher-order coefficients in each block. + */ + jcopy_block_row(currow, output, blocks_in_row); + + /* Now apply the smoothing calculation, but not to any blocks on the + * edges of the image. + */ + + if (above != NULL && below != NULL) { + for (col = 1; col < blocks_in_row-1; col++) { + + /* See section 13.10 of JPEG-8-R8, or K.8 of JPEG-9-R6. + * + * As I understand it, this produces approximations + * for the low frequency AC components, based on the + * DC values of the block and its eight neighboring blocks. + * (Thus it can't be used for blocks on the image edges.) + */ + + /* The layout of these variables corresponds to + * the text in 13.10 + */ + + JCOEF DC1, DC2, DC3; + JCOEF DC4, DC5, DC6; + JCOEF DC7, DC8, DC9; + + long AC01, AC02; + long AC10, AC11; + long AC20; + + DC1 = above [col-1][0]; + DC2 = above [col ][0]; + DC3 = above [col+1][0]; + DC4 = currow[col-1][0]; + DC5 = currow[col ][0]; + DC6 = currow[col+1][0]; + DC7 = below [col-1][0]; + DC8 = below [col ][0]; + DC9 = below [col+1][0]; + +#define DIVIDE_256(x) x = ( (x) < 0 ? -((128-(x))/256) : ((x)+128)/256 ) + + AC01 = (36 * (DC4 - DC6)); + DIVIDE_256(AC01); + AC10 = (36 * (DC2 - DC8)); + DIVIDE_256(AC10); + AC20 = (9 * (DC2 + DC8 - 2*DC5)); + DIVIDE_256(AC20); + AC11 = (5 * ((DC1 - DC3) - (DC7 - DC9))); + DIVIDE_256(AC11); + AC02 = (9 * (DC4 + DC6 - 2*DC5)); + DIVIDE_256(AC02); + + /* I think that this checks to see if the quantisation + * on the transmitting side would have produced this + * answer. If so, then we use our (hopefully better) + * estimate. + */ + +#define ABS(x) ((x) < 0 ? -(x) : (x)) + +#define COND_ASSIGN(_ac,_n,_z) if ((ABS(output[col][_n] - (_ac))<<1) <= Qptr[_z]) output[col][_n] = (_ac) + + COND_ASSIGN(AC01, 1, 1); + COND_ASSIGN(AC02, 2, 5); + COND_ASSIGN(AC10, 8, 2); + COND_ASSIGN(AC11, 9, 4); + COND_ASSIGN(AC20, 16, 3); + } + } +} + + +/* + * The method selection routine for cross-block smoothing. + */ + +GLOBAL void +jselbsmooth (decompress_info_ptr cinfo) +{ + /* just one implementation for now */ + cinfo->methods->smooth_coefficients = smooth_coefficients; +} + +#endif /* BLOCK_SMOOTHING_SUPPORTED */ diff --git a/jcarith.c b/jcarith.c new file mode 100644 index 0000000..1949459 --- /dev/null +++ b/jcarith.c @@ -0,0 +1,42 @@ +/* + * jcarith.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains arithmetic entropy encoding routines. + * These routines are invoked via the methods entropy_encode, + * entropy_encoder_init/term, and entropy_optimize. + */ + +#include "jinclude.h" + +#ifdef ARITH_CODING_SUPPORTED + + +/* + * The arithmetic coding option of the JPEG standard specifies Q-coding, + * which is covered by patents held by IBM (and possibly AT&T and Mitsubishi). + * At this time it does not appear to be legal for the Independent JPEG + * Group to distribute software that implements arithmetic coding. + * We have therefore removed arithmetic coding support from the + * distributed source code. + * + * We're not happy about it either. + */ + + +/* + * The method selection routine for arithmetic entropy encoding. + */ + +GLOBAL void +jselcarithmetic (compress_info_ptr cinfo) +{ + if (cinfo->arith_code) { + ERREXIT(cinfo->emethods, "Sorry, there are legal restrictions on arithmetic coding"); + } +} + +#endif /* ARITH_CODING_SUPPORTED */ diff --git a/jccolor.c b/jccolor.c new file mode 100644 index 0000000..7fd198c --- /dev/null +++ b/jccolor.c @@ -0,0 +1,203 @@ +/* + * jccolor.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains input colorspace conversion routines. + * These routines are invoked via the methods get_sample_rows + * and colorin_init/term. + */ + +#include "jinclude.h" + + +static JSAMPARRAY pixel_row; /* Workspace for a pixel row in input format */ + + +/* + * Initialize for colorspace conversion. + */ + +METHODDEF void +colorin_init (compress_info_ptr cinfo) +{ + /* Allocate a workspace for the result of get_input_row. */ + pixel_row = (*cinfo->emethods->alloc_small_sarray) + (cinfo->image_width, (long) cinfo->input_components); +} + + +/* + * Fetch some rows of pixels from get_input_row and convert to the + * JPEG colorspace. + * This version handles RGB -> YCbCr conversion. + * YCbCr is defined per CCIR 601-1, except that Cb and Cr are + * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + */ + +METHODDEF void +get_rgb_ycc_rows (compress_info_ptr cinfo, + int rows_to_read, JSAMPIMAGE image_data) +{ + register INT32 r, g, b; + register JSAMPROW inptr0, inptr1, inptr2; + register JSAMPROW outptr0, outptr1, outptr2; + register long col; + long width = cinfo->image_width; + int row; + + for (row = 0; row < rows_to_read; row++) { + /* Read one row from the source file */ + (*cinfo->methods->get_input_row) (cinfo, pixel_row); + /* Convert colorspace */ + inptr0 = pixel_row[0]; + inptr1 = pixel_row[1]; + inptr2 = pixel_row[2]; + outptr0 = image_data[0][row]; + outptr1 = image_data[1][row]; + outptr2 = image_data[2][row]; + for (col = width; col > 0; col--) { + r = GETJSAMPLE(*inptr0++); + g = GETJSAMPLE(*inptr1++); + b = GETJSAMPLE(*inptr2++); + /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations + * must be too; do not need an explicit range-limiting operation. + */ + /* Y */ + *outptr0++ = ( 306*r + 601*g + 117*b + (INT32) 512) >> 10; + /* Cb */ + *outptr1++ = ((-173)*r - 339*g + 512*b + (INT32) 512*(MAXJSAMPLE+1)) >> 10; + /* Cr */ + *outptr2++ = ( 512*r - 429*g - 83*b + (INT32) 512*(MAXJSAMPLE+1)) >> 10; + } + } +} + + +/* + * Fetch some rows of pixels from get_input_row and convert to the + * JPEG colorspace. + * This version handles grayscale (no conversion). + */ + +METHODDEF void +get_grayscale_rows (compress_info_ptr cinfo, + int rows_to_read, JSAMPIMAGE image_data) +{ + int row; + + for (row = 0; row < rows_to_read; row++) { + /* Read one row from the source file */ + (*cinfo->methods->get_input_row) (cinfo, pixel_row); + /* Convert colorspace (gamma mapping needed here) */ + jcopy_sample_rows(pixel_row, 0, image_data[0], row, + 1, cinfo->image_width); + } +} + + +/* + * Fetch some rows of pixels from get_input_row and convert to the + * JPEG colorspace. + * This version handles multi-component colorspaces without conversion. + */ + +METHODDEF void +get_noconvert_rows (compress_info_ptr cinfo, + int rows_to_read, JSAMPIMAGE image_data) +{ + int row, ci; + + for (row = 0; row < rows_to_read; row++) { + /* Read one row from the source file */ + (*cinfo->methods->get_input_row) (cinfo, pixel_row); + /* Convert colorspace (gamma mapping needed here) */ + for (ci = 0; ci < cinfo->input_components; ci++) { + jcopy_sample_rows(pixel_row, ci, image_data[ci], row, + 1, cinfo->image_width); + } + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +colorin_term (compress_info_ptr cinfo) +{ + /* Release the workspace. */ + (*cinfo->emethods->free_small_sarray) + (pixel_row, (long) cinfo->input_components); +} + + +/* + * The method selection routine for input colorspace conversion. + */ + +GLOBAL void +jselccolor (compress_info_ptr cinfo) +{ + /* Make sure input_components agrees with in_color_space */ + switch (cinfo->in_color_space) { + case CS_GRAYSCALE: + if (cinfo->input_components != 1) + ERREXIT(cinfo->emethods, "Bogus input colorspace"); + break; + + case CS_RGB: + if (cinfo->input_components != 3) + ERREXIT(cinfo->emethods, "Bogus input colorspace"); + break; + + case CS_CMYK: + if (cinfo->input_components != 4) + ERREXIT(cinfo->emethods, "Bogus input colorspace"); + break; + + default: + ERREXIT(cinfo->emethods, "Unsupported input colorspace"); + break; + } + + /* Check num_components, set conversion method based on requested space */ + switch (cinfo->jpeg_color_space) { + case CS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo->emethods, "Bogus JPEG colorspace"); + if (cinfo->in_color_space == CS_GRAYSCALE) + cinfo->methods->get_sample_rows = get_grayscale_rows; + else + ERREXIT(cinfo->emethods, "Unsupported color conversion request"); + break; + + case CS_YCbCr: + if (cinfo->num_components != 3) + ERREXIT(cinfo->emethods, "Bogus JPEG colorspace"); + if (cinfo->in_color_space == CS_RGB) + cinfo->methods->get_sample_rows = get_rgb_ycc_rows; + else + ERREXIT(cinfo->emethods, "Unsupported color conversion request"); + break; + + case CS_CMYK: + if (cinfo->num_components != 4) + ERREXIT(cinfo->emethods, "Bogus JPEG colorspace"); + if (cinfo->in_color_space == CS_CMYK) + cinfo->methods->get_sample_rows = get_noconvert_rows; + else + ERREXIT(cinfo->emethods, "Unsupported color conversion request"); + break; + + default: + ERREXIT(cinfo->emethods, "Unsupported JPEG colorspace"); + break; + } + + cinfo->methods->colorin_init = colorin_init; + cinfo->methods->colorin_term = colorin_term; +} diff --git a/jcdeflts.c b/jcdeflts.c new file mode 100644 index 0000000..cd1624a --- /dev/null +++ b/jcdeflts.c @@ -0,0 +1,364 @@ +/* + * jcdeflts.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains optional default-setting code for the JPEG compressor. + */ + +#include "jinclude.h" + + +LOCAL void +add_huff_table (compress_info_ptr cinfo, + HUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val) +/* Define a Huffman table */ +{ + if (*htblptr == NULL) + *htblptr = (*cinfo->emethods->alloc_small) (SIZEOF(HUFF_TBL)); + + memcpy((void *) (*htblptr)->bits, (void *) bits, + SIZEOF((*htblptr)->bits)); + memcpy((void *) (*htblptr)->huffval, (void *) val, + SIZEOF((*htblptr)->huffval)); + + /* Initialize sent_table FALSE so table will be written to JPEG file. + * In an application where we are writing non-interchange JPEG files, + * it might be desirable to save space by leaving default Huffman tables + * out of the file. To do that, just initialize sent_table = TRUE... + */ + + (*htblptr)->sent_table = FALSE; +} + + +LOCAL void +std_huff_tables (compress_info_ptr cinfo) +/* Set up the standard Huffman tables (cf. JPEG-8-R8 section 13.3) */ +{ + static const UINT8 dc_luminance_bits[17] = + { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }; + static const UINT8 dc_luminance_val[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 dc_chrominance_bits[17] = + { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }; + static const UINT8 dc_chrominance_val[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 ac_luminance_bits[17] = + { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d }; + static const UINT8 ac_luminance_val[] = + { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + static const UINT8 ac_chrominance_bits[17] = + { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 }; + static const UINT8 ac_chrominance_val[] = + { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[0], + dc_luminance_bits, dc_luminance_val); + add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[0], + ac_luminance_bits, ac_luminance_val); + add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[1], + dc_chrominance_bits, dc_chrominance_val); + add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[1], + ac_chrominance_bits, ac_chrominance_val); +} + + +/* This is the sample quantization table given in JPEG-8-R8 sec 13.1, + * but expressed in zigzag order (as are all of our quant. tables). + * The spec says that the values given produce "good" quality, and + * when divided by 2, "very good" quality. (These two settings are + * selected by quality=50 and quality=75 in j_set_quality, below.) + */ + + +static const QUANT_VAL std_luminance_quant_tbl[DCTSIZE2] = { + 16, 11, 12, 14, 12, 10, 16, 14, + 13, 14, 18, 17, 16, 19, 24, 40, + 26, 24, 22, 22, 24, 49, 35, 37, + 29, 40, 58, 51, 61, 60, 57, 51, + 56, 55, 64, 72, 92, 78, 64, 68, + 87, 69, 55, 56, 80, 109, 81, 87, + 95, 98, 103, 104, 103, 62, 77, 113, + 121, 112, 100, 120, 92, 101, 103, 99 +}; + +static const QUANT_VAL std_chrominance_quant_tbl[DCTSIZE2] = { + 17, 18, 18, 24, 21, 24, 47, 26, + 26, 47, 99, 66, 56, 66, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 +}; + + +LOCAL void +add_quant_table (compress_info_ptr cinfo, int which_tbl, + const QUANT_VAL *basic_table, int scale_factor, + boolean force_baseline) +/* Define a quantization table equal to the basic_table times */ +/* a scale factor (given as a percentage) */ +{ + QUANT_TBL_PTR * qtblptr = & cinfo->quant_tbl_ptrs[which_tbl]; + int i; + long temp; + + if (*qtblptr == NULL) + *qtblptr = (*cinfo->emethods->alloc_small) (SIZEOF(QUANT_TBL)); + + for (i = 0; i < DCTSIZE2; i++) { + temp = ((long) basic_table[i] * scale_factor + 50L) / 100L; + /* limit the values to the valid range */ + if (temp <= 0L) temp = 1L; +#ifdef EIGHT_BIT_SAMPLES + if (temp > 32767L) temp = 32767L; /* QUANT_VALs are 'short' */ +#else + if (temp > 65535L) temp = 65535L; /* QUANT_VALs are 'UINT16' */ +#endif + if (force_baseline && temp > 255L) + temp = 255L; /* limit to baseline range if requested */ + (*qtblptr)[i] = (QUANT_VAL) temp; + } +} + + +GLOBAL void +j_set_quality (compress_info_ptr cinfo, int quality, boolean force_baseline) +/* Set or change the 'quality' (quantization) setting. */ +/* The 'quality' factor should be 0 (terrible) to 100 (very good). */ +/* Quality 50 corresponds to the JPEG basic tables given above; */ +/* quality 100 results in no quantization scaling at all. */ +/* If force_baseline is TRUE, quantization table entries are limited */ +/* to 0..255 for JPEG baseline compatibility; this is only an issue */ +/* for quality settings below 24. */ +{ + /* Safety limit on quality factor. Convert 0 to 1 to avoid zero divide. */ + if (quality <= 0) quality = 1; + if (quality > 100) quality = 100; + + /* Convert quality rating to a percentage scaling of the basic tables. + * The basic table is used as-is (scaling 100) for a quality of 50. + * Qualities 50..100 are converted to scaling percentage 200 - 2*Q; + * note that at Q=100 the scaling is 0, which will cause add_quant_table + * to make all the table entries 1 (hence, no quantization loss). + * Qualities 1..50 are converted to scaling percentage 5000/Q. + */ + if (quality < 50) + quality = 5000 / quality; + else + quality = 200 - quality*2; + + /* Set up two quantization tables using the specified quality scaling */ + add_quant_table(cinfo, 0, std_luminance_quant_tbl, quality, force_baseline); + add_quant_table(cinfo, 1, std_chrominance_quant_tbl, quality, force_baseline); +} + + + +/* Default parameter setup for compression. + * + * User interfaces that don't choose to use this routine must do their + * own setup of all these parameters. Alternately, you can call this + * to establish defaults and then alter parameters selectively. + * + * See above for the meaning of the 'quality' parameter. Typically, + * the application's default quality setting will be passed to this + * routine. A later call on j_set_quality() can be used to change to + * a user-specified quality setting. + * + * This sets up for a color image; to output a grayscale image, + * do this first and call j_monochrome_default() afterwards. + * (The latter can be called within c_ui_method_selection, so the + * choice can depend on the input file header.) + * Note that if you want a JPEG colorspace other than GRAYSCALE or YCbCr, + * you should also change the component ID codes, and you should NOT emit + * a JFIF header (set write_JFIF_header = FALSE). + * + * CAUTION: if you want to compress multiple images per run, it's safest + * to call j_default_compression before *each* call to jpeg_compress (and + * j_free_defaults afterwards). If this isn't practical, you'll have to + * be careful to reset any individual parameters that may change during + * the compression run. The main thing you need to worry about as this + * is written is that the sent_table boolean in each Huffman table must + * be reset to FALSE before each compression; otherwise, Huffman tables + * won't get emitted for the second and subsequent images. + */ + +GLOBAL void +j_default_compression (compress_info_ptr cinfo, int quality) +/* NB: the external methods must already be set up. */ +{ + short i; + jpeg_component_info * compptr; + + /* Initialize pointers as needed to mark stuff unallocated. */ + cinfo->comp_info = NULL; + for (i = 0; i < NUM_QUANT_TBLS; i++) + cinfo->quant_tbl_ptrs[i] = NULL; + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + cinfo->data_precision = 8; /* default; can be overridden by input_init */ + cinfo->density_unit = 0; /* Pixel size is unknown by default */ + cinfo->X_density = 1; /* Pixel aspect ratio is square by default */ + cinfo->Y_density = 1; + + cinfo->input_gamma = 1.0; /* no gamma correction by default */ + + /* Prepare three color components; first is luminance which is also usable */ + /* for grayscale. The others are assumed to be UV or similar chrominance. */ + cinfo->write_JFIF_header = TRUE; + cinfo->jpeg_color_space = CS_YCbCr; + cinfo->num_components = 3; + cinfo->comp_info = (*cinfo->emethods->alloc_small) + (4 * SIZEOF(jpeg_component_info)); + /* Note: we allocate a 4-entry comp_info array so that user interface can + * easily change over to CMYK color space if desired. + */ + + compptr = &cinfo->comp_info[0]; + compptr->component_index = 0; + compptr->component_id = 1; /* JFIF specifies IDs 1,2,3 */ + compptr->h_samp_factor = 2; /* default to 2x2 subsamples of chrominance */ + compptr->v_samp_factor = 2; + compptr->quant_tbl_no = 0; /* use tables 0 for luminance */ + compptr->dc_tbl_no = 0; + compptr->ac_tbl_no = 0; + + compptr = &cinfo->comp_info[1]; + compptr->component_index = 1; + compptr->component_id = 2; + compptr->h_samp_factor = 1; + compptr->v_samp_factor = 1; + compptr->quant_tbl_no = 1; /* use tables 1 for chrominance */ + compptr->dc_tbl_no = 1; + compptr->ac_tbl_no = 1; + + compptr = &cinfo->comp_info[2]; + compptr->component_index = 2; + compptr->component_id = 3; + compptr->h_samp_factor = 1; + compptr->v_samp_factor = 1; + compptr->quant_tbl_no = 1; /* use tables 1 for chrominance */ + compptr->dc_tbl_no = 1; + compptr->ac_tbl_no = 1; + + /* Set up two quantization tables using the specified quality scaling */ + /* Baseline compatibility is forced (a nonissue for reasonable defaults) */ + j_set_quality(cinfo, quality, TRUE); + + /* Set up two Huffman tables in case user interface wants Huffman coding */ + std_huff_tables(cinfo); + + /* Initialize default arithmetic coding conditioning */ + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + + /* Use Huffman coding, not arithmetic coding, by default */ + cinfo->arith_code = FALSE; + + /* Color images are interleaved by default */ + cinfo->interleave = TRUE; + + /* By default, don't do extra passes to optimize entropy coding */ + cinfo->optimize_coding = FALSE; + + /* By default, use the simpler non-cosited sampling alignment */ + cinfo->CCIR601_sampling = FALSE; + + /* No restart markers */ + cinfo->restart_interval = 0; +} + + + +GLOBAL void +j_monochrome_default (compress_info_ptr cinfo) +/* Change the j_default_compression() values to emit a monochrome JPEG file. */ +{ + jpeg_component_info * compptr; + + cinfo->jpeg_color_space = CS_GRAYSCALE; + cinfo->num_components = 1; + /* Set single component to 1x1 subsampling */ + compptr = &cinfo->comp_info[0]; + compptr->h_samp_factor = 1; + compptr->v_samp_factor = 1; +} + + + +/* This routine releases storage allocated by j_default_compression. + * Note that freeing the method pointer structs and the compress_info_struct + * itself are the responsibility of the user interface. + */ + +GLOBAL void +j_free_defaults (compress_info_ptr cinfo) +{ + short i; + +#define FREE(ptr) if ((ptr) != NULL) \ + (*cinfo->emethods->free_small) ((void *) ptr) + + FREE(cinfo->comp_info); + for (i = 0; i < NUM_QUANT_TBLS; i++) + FREE(cinfo->quant_tbl_ptrs[i]); + for (i = 0; i < NUM_HUFF_TBLS; i++) { + FREE(cinfo->dc_huff_tbl_ptrs[i]); + FREE(cinfo->ac_huff_tbl_ptrs[i]); + } +} diff --git a/jcexpand.c b/jcexpand.c new file mode 100644 index 0000000..94878bd --- /dev/null +++ b/jcexpand.c @@ -0,0 +1,75 @@ +/* + * jcexpand.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains image edge-expansion routines. + * These routines are invoked via the edge_expand method. + */ + +#include "jinclude.h" + + +/* + * Expand an image so that it is a multiple of the MCU dimensions. + * This is to be accomplished by duplicating the rightmost column + * and/or bottommost row of pixels. The image has not yet been + * subsampled, so all components have the same dimensions. + */ + +METHODDEF void +edge_expand (compress_info_ptr cinfo, + long input_cols, int input_rows, + long output_cols, int output_rows, + JSAMPIMAGE image_data) +{ + /* Expand horizontally */ + if (input_cols < output_cols) { + register JSAMPROW ptr; + register JSAMPLE pixval; + register long count; + register int row; + short ci; + long numcols = output_cols - input_cols; + + for (ci = 0; ci < cinfo->num_components; ci++) { + for (row = 0; row < input_rows; row++) { + ptr = image_data[ci][row] + (input_cols-1); + pixval = GETJSAMPLE(*ptr++); + for (count = numcols; count > 0; count--) + *ptr++ = pixval; + } + } + } + + /* Expand vertically */ + /* This happens only once at the bottom of the image, */ + /* so it needn't be super-efficient */ + if (input_rows < output_rows) { + register int row; + short ci; + JSAMPARRAY this_component; + + for (ci = 0; ci < cinfo->num_components; ci++) { + this_component = image_data[ci]; + for (row = input_rows; row < output_rows; row++) { + jcopy_sample_rows(this_component, input_rows-1, this_component, row, + 1, output_cols); + } + } + } +} + + +/* + * The method selection routine for edge expansion. + */ + +GLOBAL void +jselexpand (compress_info_ptr cinfo) +{ + /* just one implementation for now */ + cinfo->methods->edge_expand = edge_expand; +} diff --git a/jchuff.c b/jchuff.c new file mode 100644 index 0000000..531bc75 --- /dev/null +++ b/jchuff.c @@ -0,0 +1,689 @@ +/* + * jchuff.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy encoding routines. + * These routines are invoked via the methods entropy_encode, + * entropy_encoder_init/term, and entropy_optimize. + */ + +#include "jinclude.h" + + +/* Static variables to avoid passing 'round extra parameters */ + +static compress_info_ptr cinfo; + +static INT32 huff_put_buffer; /* current bit-accumulation buffer */ +static int huff_put_bits; /* # of bits now in it */ + +static char * output_buffer; /* output buffer */ +static int bytes_in_buffer; + + + +LOCAL void +fix_huff_tbl (HUFF_TBL * htbl) +/* Compute derived values for a Huffman table */ +{ + int p, i, l, lastp, si; + char huffsize[257]; + UINT16 huffcode[257]; + UINT16 code; + + /* Figure 7.3.5.4.2.1: make table of Huffman code length for each symbol */ + /* Note that this is in code-length order. */ + + p = 0; + for (l = 1; l <= 16; l++) { + for (i = 1; i <= htbl->bits[l]; i++) + huffsize[p++] = l; + } + huffsize[p] = 0; + lastp = p; + + /* Figure 7.3.5.4.2.2: generate the codes themselves */ + /* Note that this is in code-length order. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (huffsize[p] == si) { + huffcode[p++] = code; + code++; + } + code <<= 1; + si++; + } + + /* Figure 7.3.5.4.2.3: generate encoding tables */ + /* These are code and size indexed by symbol value */ + + for (p = 0; p < lastp; p++) { + htbl->ehufco[htbl->huffval[p]] = huffcode[p]; + htbl->ehufsi[htbl->huffval[p]] = huffsize[p]; + } + + /* Figure 13.4.2.3.1: generate decoding tables */ + + p = 0; + for (l = 1; l <= 16; l++) { + if (htbl->bits[l]) { + htbl->valptr[l] = p; /* huffval[] index of 1st sym of code len l */ + htbl->mincode[l] = huffcode[p]; /* minimum code of length l */ + p += htbl->bits[l]; + htbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */ + } else { + htbl->maxcode[l] = -1; + } + } +} + + +/* Outputting bytes to the file */ + +LOCAL void +flush_bytes (void) +{ + if (bytes_in_buffer) + (*cinfo->methods->entropy_output) (cinfo, output_buffer, bytes_in_buffer); + bytes_in_buffer = 0; +} + + +#define emit_byte(val) ((bytes_in_buffer >= JPEG_BUF_SIZE ? \ + (flush_bytes(), 0) : 0), \ + output_buffer[bytes_in_buffer] = (val), \ + bytes_in_buffer++) + + + +/* Outputting bits to the file */ + +/* Only the right 24 bits of huff_put_buffer are used; the valid bits are + * left-justified in this part. At most 16 bits can be passed to emit_bits + * in one call, and we never retain more than 7 bits in huff_put_buffer + * between calls, so 24 bits are sufficient. + */ + +LOCAL void +emit_bits (UINT16 code, int size) +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer = code; + register int put_bits = huff_put_bits; + + put_buffer &= (((INT32) 1) << size) - 1; /* Mask off any excess bits in code */ + + put_bits += size; /* new number of bits in buffer */ + + put_buffer <<= 24 - put_bits; /* align incoming bits */ + + put_buffer |= huff_put_buffer; /* and merge with old buffer contents */ + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte(c); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte(0); + } + put_buffer <<= 8; + put_bits -= 8; + } + + huff_put_buffer = put_buffer; /* Update global variables */ + huff_put_bits = put_bits; +} + + +LOCAL void +flush_bits (void) +{ + emit_bits((UINT16) 0x7F, 7); /* fill any partial byte with ones */ + huff_put_buffer = 0; /* and reset bit-buffer to empty */ + huff_put_bits = 0; +} + + + +/* Encode a single block's worth of coefficients */ +/* Note that the DC coefficient has already been converted to a difference */ + +LOCAL void +encode_one_block (JBLOCK block, HUFF_TBL *dctbl, HUFF_TBL *actbl) +{ + register INT32 temp; + register int nbits; + register int k, r, i; + + /* Encode the DC coefficient difference per section 7.3.5.1 */ + + /* Find the number of bits needed for the magnitude of the coefficient */ + temp = block[0]; + if (temp < 0) temp = -temp; + + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + + /* Emit the Huffman-coded symbol for the number of bits */ + emit_bits(dctbl->ehufco[nbits], dctbl->ehufsi[nbits]); + + /* If positive, emit nbits low order bits; */ + /* if negative, emit nbits low order bits of value-1 */ + if ((temp = block[0]) < 0) + temp--; + + emit_bits((UINT16) temp, nbits); + + /* Encode the AC coefficients per section 7.3.5.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k < DCTSIZE2; k++) { + if ((temp = block[k]) == 0) { + r++; + } else { + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + emit_bits(actbl->ehufco[0xF0], actbl->ehufsi[0xF0]); + r -= 16; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + if (temp < 0) temp = -temp; + + nbits = 1; /* there must be at least one 1 bit */ + while (temp >>= 1) + nbits++; + + /* Emit Huffman symbol for run length / number of bits */ + i = (r << 4) + nbits; + emit_bits(actbl->ehufco[i], actbl->ehufsi[i]); + + /* If positive, emit nbits low order bits; */ + /* if negative, emit nbits low order bits of value-1 */ + if ((temp = block[k]) < 0) + temp--; + + emit_bits((UINT16) temp, nbits); + + r = 0; + } + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + emit_bits(actbl->ehufco[0], actbl->ehufsi[0]); +} + + + +/* + * Initialize for a Huffman-compressed scan. + * This is invoked after writing the SOS marker. + * The pipeline controller must establish the entropy_output method pointer + * before calling this routine. + */ + +METHODDEF void +huff_init (compress_info_ptr xinfo) +{ + short ci; + jpeg_component_info * compptr; + + /* Initialize static variables */ + cinfo = xinfo; + huff_put_buffer = 0; + huff_put_bits = 0; + + /* Initialize the output buffer */ + output_buffer = (char *) (*cinfo->emethods->alloc_small) + ((size_t) JPEG_BUF_SIZE); + bytes_in_buffer = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Make sure requested tables are present */ + if (cinfo->dc_huff_tbl_ptrs[compptr->dc_tbl_no] == NULL || + cinfo->ac_huff_tbl_ptrs[compptr->ac_tbl_no] == NULL) + ERREXIT(cinfo->emethods, "Use of undefined Huffman table"); + /* Compute derived values for Huffman tables */ + /* We may do this more than once for same table, but it's not a big deal */ + fix_huff_tbl(cinfo->dc_huff_tbl_ptrs[compptr->dc_tbl_no]); + fix_huff_tbl(cinfo->ac_huff_tbl_ptrs[compptr->ac_tbl_no]); + /* Initialize DC predictions to 0 */ + cinfo->last_dc_val[ci] = 0; + } + + /* Initialize restart stuff */ + cinfo->restarts_to_go = cinfo->restart_interval; + cinfo->next_restart_num = 0; +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL void +emit_restart (compress_info_ptr cinfo) +{ + short ci; + + flush_bits(); + + emit_byte(0xFF); + emit_byte(RST0 + cinfo->next_restart_num); + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + cinfo->last_dc_val[ci] = 0; + + /* Update restart state */ + cinfo->restarts_to_go = cinfo->restart_interval; + cinfo->next_restart_num++; + cinfo->next_restart_num &= 7; +} + + +/* + * Encode and output one MCU's worth of Huffman-compressed coefficients. + */ + +METHODDEF void +huff_encode (compress_info_ptr cinfo, JBLOCK *MCU_data) +{ + short blkn, ci; + jpeg_component_info * compptr; + JCOEF temp; + + /* Account for restart interval, emit restart marker if needed */ + if (cinfo->restart_interval) { + if (cinfo->restarts_to_go == 0) + emit_restart(cinfo); + cinfo->restarts_to_go--; + } + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + /* Convert DC value to difference, update last_dc_val */ + temp = MCU_data[blkn][0]; + MCU_data[blkn][0] -= cinfo->last_dc_val[ci]; + cinfo->last_dc_val[ci] = temp; + encode_one_block(MCU_data[blkn], + cinfo->dc_huff_tbl_ptrs[compptr->dc_tbl_no], + cinfo->ac_huff_tbl_ptrs[compptr->ac_tbl_no]); + } +} + + +/* + * Finish up at the end of a Huffman-compressed scan. + */ + +METHODDEF void +huff_term (compress_info_ptr cinfo) +{ + /* Flush out the last data */ + flush_bits(); + flush_bytes(); + /* Release the I/O buffer */ + (*cinfo->emethods->free_small) ((void *) output_buffer); +} + + + + +/* + * Huffman coding optimization. + * + * This actually is optimization, in the sense that we find the best possible + * Huffman table(s) for the given data. We first scan the supplied data and + * count the number of uses of each symbol that is to be Huffman-coded. + * (This process must agree with the code above.) Then we build an + * optimal Huffman coding tree for the observed counts. + */ + +#ifdef ENTROPY_OPT_SUPPORTED + + +/* These are static so htest_one_block can find 'em */ +static long * dc_count_ptrs[NUM_HUFF_TBLS]; +static long * ac_count_ptrs[NUM_HUFF_TBLS]; + + +LOCAL void +gen_huff_coding (compress_info_ptr cinfo, HUFF_TBL *htbl, long freq[]) +/* Generate the optimal coding for the given counts */ +{ +#define MAX_CLEN 32 /* assumed maximum initial code length */ + UINT8 bits[MAX_CLEN+1]; /* bits[k] = # of symbols with code length k */ + short codesize[257]; /* codesize[k] = code length of symbol k */ + short others[257]; /* next symbol in current branch of tree */ + int c1, c2; + int p, i, j; + long v; + + /* This algorithm is explained in section 13.2 of JPEG-8-R8 */ + + MEMZERO((void *) bits, SIZEOF(bits)); + MEMZERO((void *) codesize, SIZEOF(codesize)); + for (i = 0; i < 257; i++) + others[i] = -1; /* init links to empty */ + + freq[256] = 1; /* make sure there is a nonzero count */ + /* including the pseudo-symbol 256 in the Huffman procedure guarantees + * that no real symbol is given code-value of all ones, because 256 + * will be placed in the largest codeword category. + */ + + /* Huffman's basic algorithm to assign optimal code lengths to symbols */ + + for (;;) { + /* Find the smallest nonzero frequency, set c1 = its symbol */ + /* In case of ties, take the larger symbol number */ + c1 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v) { + v = freq[i]; + c1 = i; + } + } + + /* Find the next smallest nonzero frequency, set c2 = its symbol */ + /* In case of ties, take the larger symbol number */ + c2 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v && i != c1) { + v = freq[i]; + c2 = i; + } + } + + /* Done if we've merged everything into one frequency */ + if (c2 < 0) + break; + + /* Else merge the two counts/trees */ + freq[c1] += freq[c2]; + freq[c2] = 0; + + /* Increment the codesize of everything in c1's tree branch */ + codesize[c1]++; + while (others[c1] >= 0) { + c1 = others[c1]; + codesize[c1]++; + } + + others[c1] = c2; /* chain c2 onto c1's tree branch */ + + /* Increment the codesize of everything in c2's tree branch */ + codesize[c2]++; + while (others[c2] >= 0) { + c2 = others[c2]; + codesize[c2]++; + } + } + + /* Now count the number of symbols of each code length */ + for (i = 0; i <= 256; i++) { + if (codesize[i]) { + /* The JPEG standard seems to think that this can't happen, */ + /* but I'm paranoid... */ + if (codesize[i] > MAX_CLEN) + ERREXIT(cinfo->emethods, "Huffman code size table overflow"); + + bits[codesize[i]]++; + } + } + + /* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure + * Huffman procedure assigned any such lengths, we must adjust the coding. + * Here is what the JPEG spec says about how this next bit works: + * Since symbols are paired for the longest Huffman code, the symbols are + * removed from this length category two at a time. The prefix for the pair + * (which is one bit shorter) is allocated to one of the pair; then, + * skipping the BITS entry for that prefix length, a code word from the next + * shortest nonzero BITS entry is converted into a prefix for two code words + * one bit longer. + */ + + for (i = MAX_CLEN; i > 16; i--) { + while (bits[i] > 0) { + j = i - 2; /* find length of new prefix to be used */ + while (bits[j] == 0) + j--; + + bits[i] -= 2; /* remove two symbols */ + bits[i-1]++; /* one goes in this length */ + bits[j+1] += 2; /* two new symbols in this length */ + bits[j]--; /* symbol of this length is now a prefix */ + } + } + + /* Remove the count for the pseudo-symbol 256 from the largest codelength */ + while (bits[i] == 0) /* find largest codelength still in use */ + i--; + bits[i]--; + + /* Return final symbol counts (only for lengths 0..16) */ + memcpy((void *) htbl->bits, (void *) bits, SIZEOF(htbl->bits)); + + /* Return a list of the symbols sorted by code length */ + /* It's not real clear to me why we don't need to consider the codelength + * changes made above, but the JPEG spec seems to think this works. + */ + p = 0; + for (i = 1; i <= MAX_CLEN; i++) { + for (j = 0; j <= 255; j++) { + if (codesize[j] == i) { + htbl->huffval[p] = j; + p++; + } + } + } +} + + +/* Process a single block's worth of coefficients */ +/* Note that the DC coefficient has already been converted to a difference */ + +LOCAL void +htest_one_block (JBLOCK block, JCOEF block0, + long dc_counts[], long ac_counts[]) +{ + register INT32 temp; + register int nbits; + register int k, r; + + /* Encode the DC coefficient difference per section 7.3.5.1 */ + + /* Find the number of bits needed for the magnitude of the coefficient */ + temp = block0; + if (temp < 0) temp = -temp; + + for (nbits = 0; temp; nbits++) + temp >>= 1; + + /* Count the Huffman symbol for the number of bits */ + dc_counts[nbits]++; + + /* Encode the AC coefficients per section 7.3.5.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k < DCTSIZE2; k++) { + if ((temp = block[k]) == 0) { + r++; + } else { + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + ac_counts[0xF0]++; + r -= 16; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + if (temp < 0) temp = -temp; + + for (nbits = 0; temp; nbits++) + temp >>= 1; + + /* Count Huffman symbol for run length / number of bits */ + ac_counts[(r << 4) + nbits]++; + + r = 0; + } + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + ac_counts[0]++; +} + + + +/* + * Trial-encode one MCU's worth of Huffman-compressed coefficients. + */ + +LOCAL void +htest_encode (compress_info_ptr cinfo, JBLOCK *MCU_data) +{ + short blkn, ci; + jpeg_component_info * compptr; + + /* Take care of restart intervals if needed */ + if (cinfo->restart_interval) { + if (cinfo->restarts_to_go == 0) { + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + cinfo->last_dc_val[ci] = 0; + /* Update restart state */ + cinfo->restarts_to_go = cinfo->restart_interval; + } + cinfo->restarts_to_go--; + } + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + /* NB: unlike the real entropy encoder, we may not change the input data */ + htest_one_block(MCU_data[blkn], + (JCOEF) (MCU_data[blkn][0] - cinfo->last_dc_val[ci]), + dc_count_ptrs[compptr->dc_tbl_no], + ac_count_ptrs[compptr->ac_tbl_no]); + cinfo->last_dc_val[ci] = MCU_data[blkn][0]; + } +} + + + +/* + * Find the best coding parameters for a Huffman-coded scan. + * When called, the scan data has already been converted to a sequence of + * MCU groups of quantized coefficients, which are stored in a "big" array. + * The source_method knows how to iterate through that array. + * On return, the MCU data is unmodified, but the Huffman tables referenced + * by the scan components may have been altered. + */ + +METHODDEF void +huff_optimize (compress_info_ptr cinfo, MCU_output_caller_ptr source_method) +/* Optimize Huffman-coding parameters (Huffman symbol table) */ +{ + int i, tbl; + HUFF_TBL **htblptr; + + /* Allocate and zero the count tables */ + /* Note that gen_huff_coding expects 257 entries in each table! */ + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + dc_count_ptrs[i] = NULL; + ac_count_ptrs[i] = NULL; + } + + for (i = 0; i < cinfo->comps_in_scan; i++) { + /* Create DC table */ + tbl = cinfo->cur_comp_info[i]->dc_tbl_no; + if (dc_count_ptrs[tbl] == NULL) { + dc_count_ptrs[tbl] = (long *) (*cinfo->emethods->alloc_small) + (257 * SIZEOF(long)); + MEMZERO((void *) dc_count_ptrs[tbl], 257 * SIZEOF(long)); + } + /* Create AC table */ + tbl = cinfo->cur_comp_info[i]->ac_tbl_no; + if (ac_count_ptrs[tbl] == NULL) { + ac_count_ptrs[tbl] = (long *) (*cinfo->emethods->alloc_small) + (257 * SIZEOF(long)); + MEMZERO((void *) ac_count_ptrs[tbl], 257 * SIZEOF(long)); + } + } + + /* Initialize DC predictions to 0 */ + for (i = 0; i < cinfo->comps_in_scan; i++) { + cinfo->last_dc_val[i] = 0; + } + /* Initialize restart stuff */ + cinfo->restarts_to_go = cinfo->restart_interval; + + /* Scan the MCU data, count symbol uses */ + (*source_method) (cinfo, htest_encode); + + /* Now generate optimal Huffman tables */ + for (tbl = 0; tbl < NUM_HUFF_TBLS; tbl++) { + if (dc_count_ptrs[tbl] != NULL) { + htblptr = & cinfo->dc_huff_tbl_ptrs[tbl]; + if (*htblptr == NULL) + *htblptr = (*cinfo->emethods->alloc_small) (SIZEOF(HUFF_TBL)); + /* Set sent_table FALSE so updated table will be written to JPEG file. */ + (*htblptr)->sent_table = FALSE; + /* Compute the optimal Huffman encoding */ + gen_huff_coding(cinfo, *htblptr, dc_count_ptrs[tbl]); + /* Release the count table */ + (*cinfo->emethods->free_small) ((void *) dc_count_ptrs[tbl]); + } + if (ac_count_ptrs[tbl] != NULL) { + htblptr = & cinfo->ac_huff_tbl_ptrs[tbl]; + if (*htblptr == NULL) + *htblptr = (*cinfo->emethods->alloc_small) (SIZEOF(HUFF_TBL)); + /* Set sent_table FALSE so updated table will be written to JPEG file. */ + (*htblptr)->sent_table = FALSE; + /* Compute the optimal Huffman encoding */ + gen_huff_coding(cinfo, *htblptr, ac_count_ptrs[tbl]); + /* Release the count table */ + (*cinfo->emethods->free_small) ((void *) ac_count_ptrs[tbl]); + } + } +} + + +#endif /* ENTROPY_OPT_SUPPORTED */ + + +/* + * The method selection routine for Huffman entropy encoding. + */ + +GLOBAL void +jselchuffman (compress_info_ptr cinfo) +{ + if (! cinfo->arith_code) { + cinfo->methods->entropy_encoder_init = huff_init; + cinfo->methods->entropy_encode = huff_encode; + cinfo->methods->entropy_encoder_term = huff_term; +#ifdef ENTROPY_OPT_SUPPORTED + cinfo->methods->entropy_optimize = huff_optimize; +#endif + } +} diff --git a/jcmain.c b/jcmain.c new file mode 100644 index 0000000..f71d5ad --- /dev/null +++ b/jcmain.c @@ -0,0 +1,272 @@ +/* + * jcmain.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a trivial test user interface for the JPEG compressor. + * It should work on any system with Unix- or MS-DOS-style command lines. + * + * Two different command line styles are permitted, depending on the + * compile-time switch TWO_FILE_COMMANDLINE: + * cjpeg [options] inputfile outputfile + * cjpeg [options] [inputfile] + * In the second style, output is always to standard output, which you'd + * normally redirect to a file or pipe to some other program. Input is + * either from a named file or from standard input (typically redirected). + * The second style is convenient on Unix but is unhelpful on systems that + * don't support pipes. Also, you MUST use the first style if your system + * doesn't do binary I/O to stdin/stdout. + */ + +#include "jinclude.h" +#ifdef __STDC__ +#include /* to declare exit() */ +#endif + +#ifdef THINK_C +#include /* command-line reader for Macintosh */ +#endif + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define WRITE_BINARY "w" +#else +#define READ_BINARY "rb" +#define WRITE_BINARY "wb" +#endif + + +/* + * If your system has getopt(3), you can use your library version by + * defining HAVE_GETOPT. By default, we use the PD 'egetopt'. + */ + +#ifdef HAVE_GETOPT +extern int getopt PP((int argc, char **argv, char *optstring)); +extern char * optarg; +extern int optind; +#else +#include "egetopt.c" +#define getopt(argc,argv,opt) egetopt(argc,argv,opt) +#endif + + +/* + * This routine determines what format the input file is, + * and selects the appropriate input-reading module. + * + * To determine which family of input formats the file belongs to, + * we look only at the first byte of the file, since C does not + * guarantee that more than one character can be pushed back with ungetc. + * This is sufficient for the currently envisioned set of input formats. + * + * If you need to look at more than one character to select an input module, + * you can either + * 1) assume you can fseek() the input file (may fail for piped input); + * 2) assume you can push back more than one character (works in + * some C implementations, but unportable); + * or 3) don't put back the data, and modify the various input_init + * methods to assume they start reading after the start of file. + */ + +LOCAL void +select_file_type (compress_info_ptr cinfo) +{ + int c; + + if ((c = getc(cinfo->input_file)) == EOF) + ERREXIT(cinfo->emethods, "Empty input file"); + + switch (c) { +#ifdef GIF_SUPPORTED + case 'G': + jselrgif(cinfo); + break; +#endif +#ifdef PPM_SUPPORTED + case 'P': + jselrppm(cinfo); + break; +#endif + default: + ERREXIT(cinfo->emethods, "Unsupported input file format"); + break; + } + + if (ungetc(c, cinfo->input_file) == EOF) + ERREXIT(cinfo->emethods, "ungetc failed"); +} + + +/* + * This routine gets control after the input file header has been read. + * It must determine what output JPEG file format is to be written, + * and make any other compression parameter changes that are desirable. + */ + +METHODDEF void +c_ui_method_selection (compress_info_ptr cinfo) +{ + /* If the input is gray scale, generate a monochrome JPEG file. */ + if (cinfo->in_color_space == CS_GRAYSCALE) + j_monochrome_default(cinfo); + /* For now, always select JFIF output format. */ +#ifdef JFIF_SUPPORTED + jselwjfif(cinfo); +#else + You shoulda defined JFIF_SUPPORTED. /* deliberate syntax error */ +#endif +} + + +LOCAL void +usage (char * progname) +/* complain about bad command line */ +{ + fprintf(stderr, "usage: %s ", progname); + fprintf(stderr, "[-I] [-Q quality 0..100] [-a] [-o] [-d]"); +#ifdef TWO_FILE_COMMANDLINE + fprintf(stderr, " inputfile outputfile\n"); +#else + fprintf(stderr, " [inputfile]\n"); +#endif + exit(2); +} + + +/* + * The main program. + */ + +GLOBAL void +main (int argc, char **argv) +{ + struct compress_info_struct cinfo; + struct compress_methods_struct c_methods; + struct external_methods_struct e_methods; + int c; + + /* On Mac, fetch a command line. */ +#ifdef THINK_C + argc = ccommand(&argv); +#endif + + /* Initialize the system-dependent method pointers. */ + cinfo.methods = &c_methods; + cinfo.emethods = &e_methods; + jselerror(&e_methods); /* error/trace message routines */ + jselvirtmem(&e_methods); /* memory allocation routines */ + c_methods.c_ui_method_selection = c_ui_method_selection; + + /* Set up default input and output file references. */ + /* (These may be overridden below.) */ + cinfo.input_file = stdin; + cinfo.output_file = stdout; + + /* Set up default parameters. */ + e_methods.trace_level = 0; + j_default_compression(&cinfo, 75); /* default quality level */ + + /* Scan parameters */ + + while ((c = getopt(argc, argv, "IQ:aod")) != EOF) + switch (c) { + case 'I': /* Create noninterleaved file. */ +#ifdef MULTISCAN_FILES_SUPPORTED + cinfo.interleave = FALSE; +#else + fprintf(stderr, "%s: sorry, multiple-scan support was not compiled\n", + argv[0]); + exit(2); +#endif + break; + case 'Q': /* Quality factor. */ + { int val; + if (optarg == NULL) + usage(argv[0]); + if (sscanf(optarg, "%d", &val) != 1) + usage(argv[0]); + /* Note: for now, we leave force_baseline FALSE. + * In a production user interface, probably should make it TRUE + * unless overridden by a separate switch. + */ + j_set_quality(&cinfo, val, FALSE); + } + break; + case 'a': /* Use arithmetic coding. */ +#ifdef ARITH_CODING_SUPPORTED + cinfo.arith_code = TRUE; +#else + fprintf(stderr, "%s: sorry, arithmetic coding not supported\n", + argv[0]); + exit(2); +#endif + break; + case 'o': /* Enable entropy parm optimization. */ +#ifdef ENTROPY_OPT_SUPPORTED + cinfo.optimize_coding = TRUE; +#else + fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n", + argv[0]); + exit(2); +#endif + break; + case 'd': /* Debugging. */ + e_methods.trace_level++; + break; + case '?': + default: + usage(argv[0]); + break; + } + + /* Select the input and output files */ + +#ifdef TWO_FILE_COMMANDLINE + + if (optind != argc-2) { + fprintf(stderr, "%s: must name one input and one output file\n", argv[0]); + usage(argv[0]); + } + if ((cinfo.input_file = fopen(argv[optind], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", argv[0], argv[optind]); + exit(2); + } + if ((cinfo.output_file = fopen(argv[optind+1], WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", argv[0], argv[optind+1]); + exit(2); + } + +#else /* not TWO_FILE_COMMANDLINE -- use Unix style */ + + if (optind < argc-1) { + fprintf(stderr, "%s: only one input file\n", argv[0]); + usage(argv[0]); + } + if (optind < argc) { + if ((cinfo.input_file = fopen(argv[optind], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", argv[0], argv[optind]); + exit(2); + } + } + +#endif /* TWO_FILE_COMMANDLINE */ + + /* Figure out the input file format, and set up to read it. */ + select_file_type(&cinfo); + + /* Do it to it! */ + jpeg_compress(&cinfo); + + /* Release memory. */ + j_free_defaults(&cinfo); +#ifdef MEM_STATS + if (e_methods.trace_level > 0) + j_mem_stats(); +#endif + + /* All done. */ + exit(0); +} diff --git a/jcmaster.c b/jcmaster.c new file mode 100644 index 0000000..b15217a --- /dev/null +++ b/jcmaster.c @@ -0,0 +1,127 @@ +/* + * jcmaster.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main control for the JPEG compressor. + * The system-dependent (user interface) code should call jpeg_compress() + * after doing appropriate setup of the compress_info_struct parameter. + */ + +#include "jinclude.h" + + +METHODDEF void +c_per_scan_method_selection (compress_info_ptr cinfo) +/* Central point for per-scan method selection */ +{ + /* Edge expansion */ + jselexpand(cinfo); + /* Subsampling of pixels */ + jselsubsample(cinfo); + /* MCU extraction */ + jselcmcu(cinfo); +} + + +LOCAL void +c_initial_method_selection (compress_info_ptr cinfo) +/* Central point for initial method selection */ +{ + /* Input image reading method selection is already done. */ + /* So is output file header formatting (both are done by user interface). */ + + /* Gamma and color space conversion */ + jselccolor(cinfo); + /* Entropy encoding: either Huffman or arithmetic coding. */ +#ifdef ARITH_CODING_SUPPORTED + jselcarithmetic(cinfo); +#else + cinfo->arith_code = FALSE; /* force Huffman mode */ +#endif + jselchuffman(cinfo); + /* Pipeline control */ + jselcpipeline(cinfo); + /* Overall control (that's me!) */ + cinfo->methods->c_per_scan_method_selection = c_per_scan_method_selection; +} + + +LOCAL void +initial_setup (compress_info_ptr cinfo) +/* Do computations that are needed before initial method selection */ +{ + short ci; + jpeg_component_info *compptr; + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0; ci < cinfo->num_components; ci++) { + compptr = &cinfo->comp_info[ci]; + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo->emethods, "Bogus sampling factors"); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + + } + + /* Compute logical subsampled dimensions of components */ + for (ci = 0; ci < cinfo->num_components; ci++) { + compptr = &cinfo->comp_info[ci]; + compptr->true_comp_width = (cinfo->image_width * compptr->h_samp_factor + + cinfo->max_h_samp_factor - 1) + / cinfo->max_h_samp_factor; + compptr->true_comp_height = (cinfo->image_height * compptr->v_samp_factor + + cinfo->max_v_samp_factor - 1) + / cinfo->max_v_samp_factor; + } +} + + +/* + * This is the main entry point to the JPEG compressor. + */ + + +GLOBAL void +jpeg_compress (compress_info_ptr cinfo) +{ + /* Read the input file header: determine image size & component count. + * NOTE: the user interface must have initialized the input_init method + * pointer (eg, by calling jselrppm) before calling me. + * The other file reading methods (get_input_row etc.) were probably + * set at the same time, but could be set up by input_init itself, + * or by c_ui_method_selection. + */ + (*cinfo->methods->input_init) (cinfo); + + /* Give UI a chance to adjust compression parameters and select */ + /* output file format based on results of input_init. */ + (*cinfo->methods->c_ui_method_selection) (cinfo); + + /* Now select methods for compression steps. */ + initial_setup(cinfo); + c_initial_method_selection(cinfo); + + /* Initialize the output file & other modules as needed */ + /* (entropy_encoder is inited by pipeline controller) */ + + (*cinfo->methods->colorin_init) (cinfo); + (*cinfo->methods->write_file_header) (cinfo); + + /* And let the pipeline controller do the rest. */ + (*cinfo->methods->c_pipeline_controller) (cinfo); + + /* Finish output file, release working storage, etc */ + (*cinfo->methods->write_file_trailer) (cinfo); + (*cinfo->methods->colorin_term) (cinfo); + (*cinfo->methods->input_term) (cinfo); + + /* My, that was easy, wasn't it? */ +} diff --git a/jcmcu.c b/jcmcu.c new file mode 100644 index 0000000..1400eab --- /dev/null +++ b/jcmcu.c @@ -0,0 +1,212 @@ +/* + * jcmcu.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains MCU extraction routines and quantization scaling. + * These routines are invoked via the extract_MCUs and + * extract_init/term methods. + */ + +#include "jinclude.h" + + +/* + * If this file is compiled with -DDCT_ERR_STATS, it will reverse-DCT each + * block and sum the total errors across the whole picture. This provides + * a convenient method of using real picture data to test the roundoff error + * of a DCT algorithm. DCT_ERR_STATS should *not* be defined for a production + * compression program, since compression is much slower with it defined. + * Also note that jrevdct.o must be linked into the compressor when this + * switch is defined. + */ + +#ifdef DCT_ERR_STATS +static int dcterrorsum; /* these hold the error statistics */ +static int dcterrormax; +static int dctcoefcount; /* This will probably overflow on a 16-bit-int machine */ +#endif + + +/* ZAG[i] is the natural-order position of the i'th element of zigzag order. */ + +static const short ZAG[DCTSIZE2] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + + +LOCAL void +extract_block (JSAMPARRAY input_data, int start_row, long start_col, + JBLOCK output_data, QUANT_TBL_PTR quanttbl) +/* Extract one 8x8 block from the specified location in the sample array; */ +/* perform forward DCT, quantization scaling, and zigzag reordering on it. */ +{ + /* This routine is heavily used, so it's worth coding it tightly. */ + DCTBLOCK block; +#ifdef DCT_ERR_STATS + DCTBLOCK svblock; /* saves input data for comparison */ +#endif + + { register JSAMPROW elemptr; + register DCTELEM *localblkptr = block; +#if DCTSIZE != 8 + register short elemc; +#endif + register short elemr; + + for (elemr = DCTSIZE; elemr > 0; elemr--) { + elemptr = input_data[start_row++] + start_col; +#if DCTSIZE == 8 /* unroll the inner loop */ + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; +#else + for (elemc = DCTSIZE; elemc > 0; elemc--) { + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + } +#endif + } + } + +#ifdef DCT_ERR_STATS + memcpy((void *) svblock, (void *) block, SIZEOF(DCTBLOCK)); +#endif + + j_fwd_dct(block); + + { register JCOEF temp; + register short i; + + for (i = 0; i < DCTSIZE2; i++) { + temp = (JCOEF) block[ZAG[i]]; + /* divide by *quanttbl, ensuring proper rounding */ + if (temp < 0) { + temp = -temp; + temp += *quanttbl>>1; + temp /= *quanttbl; + temp = -temp; + } else { + temp += *quanttbl>>1; + temp /= *quanttbl; + } + *output_data++ = temp; + quanttbl++; + } + } + +#ifdef DCT_ERR_STATS + j_rev_dct(block); + + { register int diff; + register short i; + + for (i = 0; i < DCTSIZE2; i++) { + diff = block[i] - svblock[i]; + if (diff < 0) diff = -diff; + dcterrorsum += diff; + if (dcterrormax < diff) dcterrormax = diff; + } + dctcoefcount += DCTSIZE2; + } +#endif +} + + +/* + * Extract samples in MCU order, process & hand off to output_method. + * The input is always exactly N MCU rows worth of data. + */ + +METHODDEF void +extract_MCUs (compress_info_ptr cinfo, + JSAMPIMAGE image_data, + int num_mcu_rows, + MCU_output_method_ptr output_method) +{ + JBLOCK MCU_data[MAX_BLOCKS_IN_MCU]; + int mcurow; + long mcuindex; + short blkn, ci, xpos, ypos; + jpeg_component_info * compptr; + QUANT_TBL_PTR quant_ptr; + + for (mcurow = 0; mcurow < num_mcu_rows; mcurow++) { + for (mcuindex = 0; mcuindex < cinfo->MCUs_per_row; mcuindex++) { + /* Extract data from the image array, DCT it, and quantize it */ + blkn = 0; + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + quant_ptr = cinfo->quant_tbl_ptrs[compptr->quant_tbl_no]; + for (ypos = 0; ypos < compptr->MCU_height; ypos++) { + for (xpos = 0; xpos < compptr->MCU_width; xpos++) { + extract_block(image_data[ci], + (mcurow * compptr->MCU_height + ypos)*DCTSIZE, + (mcuindex * compptr->MCU_width + xpos)*DCTSIZE, + MCU_data[blkn], quant_ptr); + blkn++; + } + } + } + /* Send the MCU whereever the pipeline controller wants it to go */ + (*output_method) (cinfo, MCU_data); + } + } +} + + +/* + * Initialize for processing a scan. + */ + +METHODDEF void +extract_init (compress_info_ptr cinfo) +{ + /* no work for now */ +#ifdef DCT_ERR_STATS + dcterrorsum = dcterrormax = dctcoefcount = 0; +#endif +} + + +/* + * Clean up after a scan. + */ + +METHODDEF void +extract_term (compress_info_ptr cinfo) +{ + /* no work for now */ +#ifdef DCT_ERR_STATS + TRACEMS3(cinfo->emethods, 0, "DCT roundoff errors = %d/%d, max = %d", + dcterrorsum, dctcoefcount, dcterrormax); +#endif +} + + + +/* + * The method selection routine for MCU extraction. + */ + +GLOBAL void +jselcmcu (compress_info_ptr cinfo) +{ + /* just one implementation for now */ + cinfo->methods->extract_init = extract_init; + cinfo->methods->extract_MCUs = extract_MCUs; + cinfo->methods->extract_term = extract_term; +} diff --git a/jconfig.h b/jconfig.h new file mode 100644 index 0000000..3b22acb --- /dev/null +++ b/jconfig.h @@ -0,0 +1,320 @@ +/* + * jconfig.h + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains preprocessor declarations that help customize + * the JPEG software for a particular application, machine, or compiler. + * Edit these declarations as needed (or add -D flags to the Makefile). + */ + + +/* + * These symbols indicate the properties of your machine or compiler. + * The conditional definitions given may do the right thing already, + * but you'd best look them over closely, especially if your compiler + * does not handle full ANSI C. An ANSI-compliant C compiler should + * provide all the necessary features; __STDC__ is supposed to be + * predefined by such compilers. + */ + +/* Does your compiler support function prototypes? */ +/* (If not, you also need to use ansi2knr, see README) */ + +#ifdef __STDC__ /* ANSI C compilers always have prototypes */ +#define PROTO +#else +#ifdef __cplusplus /* So do C++ compilers */ +#define PROTO +#endif +#endif + +/* Does your compiler support the declaration "unsigned char" ? */ +/* How about "unsigned short" ? */ + +#ifdef __STDC__ /* ANSI C compilers must support both */ +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +#endif + +/* Define this if an ordinary "char" type is unsigned. + * If you're not sure, leaving it undefined will work at some cost in speed. + * If you defined HAVE_UNSIGNED_CHAR then it doesn't matter very much. + */ + +/* #define CHAR_IS_UNSIGNED */ + +/* Define this if your compiler implements ">>" on signed values as a logical + * (unsigned) shift; leave it undefined if ">>" is a signed (arithmetic) shift, + * which is the normal and rational definition. + * The DCT and IDCT routines will compute wrong values if you get this wrong! + */ + +/* #define RIGHT_SHIFT_IS_UNSIGNED */ + +/* Define "void" as "char" if your compiler doesn't know about type void. + * NOTE: be sure to define void such that "void *" represents the most general + * pointer type, e.g., that returned by malloc(). + */ + +/* #define void char */ + +/* Define const as empty if your compiler doesn't know the "const" keyword. */ +/* (Even if it does, defining const as empty won't break anything.) */ + +#ifndef __STDC__ /* ANSI C and C++ compilers should know it. */ +#ifndef __cplusplus +#define const +#endif +#endif + +/* For 80x86 machines, you need to define NEED_FAR_POINTERS, + * unless you are using a large-data memory model or 80386 flat-memory mode. + * On less brain-damaged CPUs this symbol must not be defined. + * (Defining this symbol causes large data structures to be referenced through + * "far" pointers and to be allocated with a special version of malloc.) + */ + +#ifdef MSDOS /* Microsoft C and compatibles */ +#define NEED_FAR_POINTERS +#else +#ifdef __TURBOC__ /* Turbo C doesn't define MSDOS */ +#define NEED_FAR_POINTERS +#endif +#endif + + +/* The next couple of symbols only affect the system-dependent user interface + * modules (jcmain.c, jdmain.c). You can ignore these if you are supplying + * your own user interface code. + */ + +/* Define this if you want to name both input and output files on the command + * line, rather than using stdout and optionally stdin. You MUST do this if + * your system can't cope with binary I/O to stdin/stdout. See comments at + * head of jcmain.c or jdmain.c. + */ + +#ifdef MSDOS /* two-file style is needed for PCs */ +#define TWO_FILE_COMMANDLINE +#else +#ifdef __TURBOC__ /* Turbo C doesn't define MSDOS */ +#define TWO_FILE_COMMANDLINE +#endif +#endif +#ifdef THINK_C /* needed for Macintosh too */ +#define TWO_FILE_COMMANDLINE +#endif + +/* By default, we open image files with fopen(...,"rb") or fopen(...,"wb"). + * This is necessary on systems that distinguish text files from binary files, + * and is harmless on most systems that don't. If you have one of the rare + * systems that complains about the "b" spec, define this symbol. + */ + +/* #define DONT_USE_B_MODE */ + + +/* If you're getting bored, that's the end of the symbols you HAVE to + * worry about. Go fix the makefile and compile. + */ + + +/* If your compiler supports inline functions, define INLINE as + * the inline keyword; otherwise define it as empty. + */ + +#ifdef __GNUC__ /* GNU C has inline... */ +#define INLINE inline +#else /* ...but I don't think anyone else does. */ +#define INLINE +#endif + +/* On a few systems, type boolean and/or macros FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * In that case you need only comment out these definitions. + */ + +typedef int boolean; +#define FALSE 0 /* values of boolean */ +#define TRUE 1 + +/* This defines the size of the I/O buffers for entropy compression + * and decompression; you could reduce it if memory is tight. + */ + +#define JPEG_BUF_SIZE 4096 /* bytes */ + + + +/* These symbols determine the JPEG functionality supported. */ + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * program file. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */ +#undef ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing during decoding? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#undef QUANT_2PASS_SUPPORTED /* 2-pass color quantization? (not yet impl.) */ +/* these defines indicate which JPEG file formats are allowed */ +#define JFIF_SUPPORTED /* JFIF or "raw JPEG" files */ +#undef JTIFF_SUPPORTED /* JPEG-in-TIFF (not yet implemented) */ +/* these defines indicate which image (non-JPEG) file formats are allowed */ +#define PPM_SUPPORTED /* PPM/PGM image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#undef TIFF_SUPPORTED /* TIFF image file format (not yet impl.) */ + +/* more capability options later, no doubt */ + + +/* + * Define exactly one of these three symbols to indicate whether you want + * 8-bit, 12-bit, or 16-bit sample (pixel component) values. 8-bit is the + * default and is nearly always the right thing to use. You can use 12-bit if + * you need to support image formats with more than 8 bits of resolution in a + * color value. 16-bit should only be used for the lossless JPEG mode (not + * currently supported). Note that 12- and 16-bit values take up twice as + * much memory as 8-bit! + */ + +#define EIGHT_BIT_SAMPLES +#undef TWELVE_BIT_SAMPLES +#undef SIXTEEN_BIT_SAMPLES + + + +/* + * The remaining definitions don't need to be hand-edited in most cases. + * You may need to change these if you have a machine with unusual data + * types; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* First define the representation of a single pixel element value. */ + +#ifdef EIGHT_BIT_SAMPLES +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + * If you have only signed chars, and you are more worried about speed than + * memory usage, it might be a win to make JSAMPLE be short. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED + +typedef char JSAMPLE; +#define GETJSAMPLE(value) (value) + +#else /* not CHAR_IS_UNSIGNED */ + +typedef char JSAMPLE; +#define GETJSAMPLE(value) ((value) & 0xFF) + +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* EIGHT_BIT_SAMPLES */ + + +#ifdef TWELVE_BIT_SAMPLES +/* JSAMPLE should be the smallest type that will hold the values 0..4095. */ +/* On nearly all machines "short" will do nicely. */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) (value) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* TWELVE_BIT_SAMPLES */ + + +#ifdef SIXTEEN_BIT_SAMPLES +/* JSAMPLE should be the smallest type that will hold the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT + +typedef unsigned short JSAMPLE; +#define GETJSAMPLE(value) (value) + +#else /* not HAVE_UNSIGNED_SHORT */ + +/* If int is 32 bits this'll be horrendously inefficient storage-wise. + * But since we don't actually support 16-bit samples (ie lossless coding) yet, + * I'm not going to worry about making a smarter definition ... + */ +typedef unsigned int JSAMPLE; +#define GETJSAMPLE(value) (value) + +#endif /* HAVE_UNSIGNED_SHORT */ + +#define MAXJSAMPLE 65535 +#define CENTERJSAMPLE 32768 + +#endif /* SIXTEEN_BIT_SAMPLES */ + + +/* Here we define the representation of a DCT frequency coefficient. + * This should be a signed 16-bit value; "short" is usually right. + * It's important that this be exactly 16 bits, no more and no less; + * more will cost you a BIG hit of memory, less will give wrong answers. + */ + +typedef short JCOEF; + + +/* The remaining typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char UINT8; +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char UINT8; +#else /* not CHAR_IS_UNSIGNED */ +typedef short UINT8; +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +/* UINT16 must hold at least the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT +typedef unsigned short UINT16; +#else /* not HAVE_UNSIGNED_SHORT */ +typedef unsigned int UINT16; +#endif /* HAVE_UNSIGNED_SHORT */ + +/* INT16 must hold at least the values -32768..32767. */ + +typedef short INT16; + +/* INT32 must hold signed 32-bit values; if your machine happens */ +/* to have 64-bit longs, you might want to change this. */ + +typedef long INT32; diff --git a/jcpipe.c b/jcpipe.c new file mode 100644 index 0000000..f58e7db --- /dev/null +++ b/jcpipe.c @@ -0,0 +1,715 @@ +/* + * jcpipe.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains compression pipeline controllers. + * These routines are invoked via the c_pipeline_controller method. + * + * There are four basic pipeline controllers, one for each combination of: + * single-scan JPEG file (single component or fully interleaved) + * vs. multiple-scan JPEG file (noninterleaved or partially interleaved). + * + * optimization of entropy encoding parameters + * vs. usage of default encoding parameters. + * + * Note that these conditions determine the needs for "big" arrays: + * multiple scans imply a big array for splitting the color components; + * entropy encoding optimization needs a big array for the MCU data. + * + * All but the simplest controller (single-scan, no optimization) can be + * compiled out through configuration options, if you need to make a minimal + * implementation. + */ + +#include "jinclude.h" + + +/* + * About the data structures: + * + * The processing chunk size for subsampling is referred to in this file as + * a "row group": a row group is defined as Vk (v_samp_factor) sample rows of + * any component after subsampling, or Vmax (max_v_samp_factor) unsubsampled + * rows. In an interleaved scan each MCU row contains exactly DCTSIZE row + * groups of each component in the scan. In a noninterleaved scan an MCU row + * is one row of blocks, which might not be an integral number of row groups; + * for convenience we use a buffer of the same size as in interleaved scans, + * and process Vk MCU rows in each burst of subsampling. + * To provide context for the subsampling step, we have to retain the last + * two row groups of the previous MCU row while reading in the next MCU row + * (or set of Vk MCU rows). To do this without copying data about, we create + * a rather strange data structure. Exactly DCTSIZE+2 row groups of samples + * are allocated, but we create two different sets of pointers to this array. + * The second set swaps the last two pairs of row groups. By working + * alternately with the two sets of pointers, we can access the data in the + * desired order. + */ + + + +/* + * Utility routines: common code for pipeline controllers + */ + +LOCAL void +interleaved_scan_setup (compress_info_ptr cinfo) +/* Compute all derived info for an interleaved (multi-component) scan */ +/* On entry, cinfo->comps_in_scan and cinfo->cur_comp_info[] are set up */ +{ + short ci, mcublks; + jpeg_component_info *compptr; + + if (cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT(cinfo->emethods, "Too many components for interleaved scan"); + + cinfo->MCUs_per_row = (cinfo->image_width + + cinfo->max_h_samp_factor*DCTSIZE - 1) + / (cinfo->max_h_samp_factor*DCTSIZE); + + cinfo->MCU_rows_in_scan = (cinfo->image_height + + cinfo->max_v_samp_factor*DCTSIZE - 1) + / (cinfo->max_v_samp_factor*DCTSIZE); + + cinfo->blocks_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* for interleaved scan, sampling factors give # of blocks per component */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; + /* compute physical dimensions of component */ + compptr->subsampled_width = jround_up(compptr->true_comp_width, + (long) (compptr->MCU_width*DCTSIZE)); + compptr->subsampled_height = jround_up(compptr->true_comp_height, + (long) (compptr->MCU_height*DCTSIZE)); + /* Sanity check */ + if (compptr->subsampled_width != + (cinfo->MCUs_per_row * (compptr->MCU_width*DCTSIZE))) + ERREXIT(cinfo->emethods, "I'm confused about the image width"); + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_blocks; + if (cinfo->blocks_in_MCU + mcublks > MAX_BLOCKS_IN_MCU) + ERREXIT(cinfo->emethods, "Sampling factors too large for interleaved scan"); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; + } + } + + (*cinfo->methods->c_per_scan_method_selection) (cinfo); +} + + +LOCAL void +noninterleaved_scan_setup (compress_info_ptr cinfo) +/* Compute all derived info for a noninterleaved (single-component) scan */ +/* On entry, cinfo->comps_in_scan = 1 and cinfo->cur_comp_info[0] is set up */ +{ + jpeg_component_info *compptr = cinfo->cur_comp_info[0]; + + /* for noninterleaved scan, always one block per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_blocks = 1; + /* compute physical dimensions of component */ + compptr->subsampled_width = jround_up(compptr->true_comp_width, + (long) DCTSIZE); + compptr->subsampled_height = jround_up(compptr->true_comp_height, + (long) DCTSIZE); + + cinfo->MCUs_per_row = compptr->subsampled_width / DCTSIZE; + cinfo->MCU_rows_in_scan = compptr->subsampled_height / DCTSIZE; + + /* Prepare array describing MCU composition */ + cinfo->blocks_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + (*cinfo->methods->c_per_scan_method_selection) (cinfo); +} + + + +LOCAL void +alloc_sampling_buffer (compress_info_ptr cinfo, JSAMPIMAGE fullsize_data[2], + long fullsize_width) +/* Create a pre-subsampling data buffer having the desired structure */ +/* (see comments at head of file) */ +{ + short ci, vs, i; + + vs = cinfo->max_v_samp_factor; /* row group height */ + + /* Get top-level space for array pointers */ + fullsize_data[0] = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(JSAMPARRAY)); + fullsize_data[1] = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(JSAMPARRAY)); + + for (ci = 0; ci < cinfo->num_components; ci++) { + /* Allocate the real storage */ + fullsize_data[0][ci] = (*cinfo->emethods->alloc_small_sarray) + (fullsize_width, + (long) (vs * (DCTSIZE+2))); + /* Create space for the scrambled-order pointers */ + fullsize_data[1][ci] = (JSAMPARRAY) (*cinfo->emethods->alloc_small) + (vs * (DCTSIZE+2) * SIZEOF(JSAMPROW)); + /* Duplicate the first DCTSIZE-2 row groups */ + for (i = 0; i < vs * (DCTSIZE-2); i++) { + fullsize_data[1][ci][i] = fullsize_data[0][ci][i]; + } + /* Copy the last four row groups in swapped order */ + for (i = 0; i < vs * 2; i++) { + fullsize_data[1][ci][vs*DCTSIZE + i] = fullsize_data[0][ci][vs*(DCTSIZE-2) + i]; + fullsize_data[1][ci][vs*(DCTSIZE-2) + i] = fullsize_data[0][ci][vs*DCTSIZE + i]; + } + } +} + + +LOCAL void +free_sampling_buffer (compress_info_ptr cinfo, JSAMPIMAGE fullsize_data[2]) +/* Release a sampling buffer created by alloc_sampling_buffer */ +{ + short ci, vs; + + vs = cinfo->max_v_samp_factor; /* row group height */ + + for (ci = 0; ci < cinfo->num_components; ci++) { + /* Free the real storage */ + (*cinfo->emethods->free_small_sarray) + (fullsize_data[0][ci], (long) (vs * (DCTSIZE+2))); + /* Free the scrambled-order pointers */ + (*cinfo->emethods->free_small) ((void *) fullsize_data[1][ci]); + } + + /* Free the top-level space */ + (*cinfo->emethods->free_small) ((void *) fullsize_data[0]); + (*cinfo->emethods->free_small) ((void *) fullsize_data[1]); +} + + +LOCAL void +subsample (compress_info_ptr cinfo, + JSAMPIMAGE fullsize_data, JSAMPIMAGE subsampled_data, + long fullsize_width, + short above, short current, short below, short out) +/* Do subsampling of a single row group (of each component). */ +/* above, current, below are indexes of row groups in fullsize_data; */ +/* out is the index of the target row group in subsampled_data. */ +/* Special case: above, below can be -1 to indicate top, bottom of image. */ +{ + jpeg_component_info *compptr; + JSAMPARRAY above_ptr, below_ptr; + JSAMPROW dummy[MAX_SAMP_FACTOR]; /* for subsample expansion at top/bottom */ + short ci, vs, i; + + vs = cinfo->max_v_samp_factor; /* row group height */ + + for (ci = 0; ci < cinfo->num_components; ci++) { + compptr = & cinfo->comp_info[ci]; + + if (above >= 0) + above_ptr = fullsize_data[ci] + above * vs; + else { + /* Top of image: make a dummy above-context with copies of 1st row */ + /* We assume current=0 in this case */ + for (i = 0; i < vs; i++) + dummy[i] = fullsize_data[ci][0]; + above_ptr = (JSAMPARRAY) dummy; /* possible near->far pointer conv */ + } + + if (below >= 0) + below_ptr = fullsize_data[ci] + below * vs; + else { + /* Bot of image: make a dummy below-context with copies of last row */ + for (i = 0; i < vs; i++) + dummy[i] = fullsize_data[ci][(current+1)*vs-1]; + below_ptr = (JSAMPARRAY) dummy; /* possible near->far pointer conv */ + } + + (*cinfo->methods->subsample[ci]) + (cinfo, (int) ci, + fullsize_width, (int) vs, + compptr->subsampled_width, (int) compptr->v_samp_factor, + above_ptr, + fullsize_data[ci] + current * vs, + below_ptr, + subsampled_data[ci] + out * compptr->v_samp_factor); + } +} + + +/* These vars are initialized by the pipeline controller for use by + * MCU_output_catcher. + * To avoid a lot of row-pointer overhead, we cram as many MCUs into each + * row of whole_scan_MCUs as we can get without exceeding 64KB per row. + */ + +#define MAX_WHOLE_ROW_BLOCKS (65500 / SIZEOF(JBLOCK)) /* max blocks/row */ + +static big_barray_ptr whole_scan_MCUs; /* Big array for saving the MCUs */ +static int MCUs_in_big_row; /* # of MCUs in each row of whole_scan_MCUs */ +static long next_whole_row; /* next row to access in whole_scan_MCUs */ +static int next_MCU_index; /* next MCU in current row */ + + +METHODDEF void +MCU_output_catcher (compress_info_ptr cinfo, JBLOCK *MCU_data) +/* Output method for siphoning off extract_MCUs output into a big array */ +{ + static JBLOCKARRAY rowptr; + + if (next_MCU_index >= MCUs_in_big_row) { + rowptr = (*cinfo->emethods->access_big_barray) (whole_scan_MCUs, + next_whole_row, TRUE); + next_whole_row++; + next_MCU_index = 0; + } + + /* + * note that on 80x86, the cast applied to MCU_data implies + * near to far pointer conversion. + */ + jcopy_block_row((JBLOCKROW) MCU_data, + rowptr[0] + next_MCU_index * cinfo->blocks_in_MCU, + (long) cinfo->blocks_in_MCU); + next_MCU_index++; +} + + +METHODDEF void +dump_scan_MCUs (compress_info_ptr cinfo, MCU_output_method_ptr output_method) +/* Dump the MCUs saved in whole_scan_MCUs to the output method. */ +/* The method may be either the entropy encoder or some routine supplied */ +/* by the entropy optimizer. */ +{ + /* On an 80x86 machine, the entropy encoder expects the passed data block + * to be in NEAR memory (for performance reasons), so we have to copy it + * back from the big array to a local array. On less brain-damaged CPUs + * we needn't do that. + */ +#ifdef NEED_FAR_POINTERS + JBLOCK MCU_data[MAX_BLOCKS_IN_MCU]; +#endif + long mcurow, mcuindex, next_row; + int next_index; + JBLOCKARRAY rowptr = NULL; /* init only to suppress compiler complaint */ + + next_row = 0; + next_index = MCUs_in_big_row; + + for (mcurow = 0; mcurow < cinfo->MCU_rows_in_scan; mcurow++) { + for (mcuindex = 0; mcuindex < cinfo->MCUs_per_row; mcuindex++) { + if (next_index >= MCUs_in_big_row) { + rowptr = (*cinfo->emethods->access_big_barray) (whole_scan_MCUs, + next_row, FALSE); + next_row++; + next_index = 0; + } +#ifdef NEED_FAR_POINTERS + jcopy_block_row(rowptr[0] + next_index * cinfo->blocks_in_MCU, + (JBLOCKROW) MCU_data, /* note cast */ + (long) cinfo->blocks_in_MCU); + (*output_method) (cinfo, MCU_data); +#else + (*output_method) (cinfo, rowptr[0] + next_index * cinfo->blocks_in_MCU); +#endif + next_index++; + } + } +} + + + +/* + * Compression pipeline controller used for single-scan files + * with no optimization of entropy parameters. + */ + +METHODDEF void +single_ccontroller (compress_info_ptr cinfo) +{ + int rows_in_mem; /* # of sample rows in full-size buffers */ + long fullsize_width; /* # of samples per row in full-size buffers */ + long cur_pixel_row; /* counts # of pixel rows processed */ + long mcu_rows_output; /* # of MCU rows actually emitted */ + int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */ + /* Work buffer for pre-subsampling data (see comments at head of file) */ + JSAMPIMAGE fullsize_data[2]; + /* Work buffer for subsampled data */ + JSAMPIMAGE subsampled_data; + int rows_this_time; + short ci, whichss, i; + + /* Prepare for single scan containing all components */ + if (cinfo->num_components > MAX_COMPS_IN_SCAN) + ERREXIT(cinfo->emethods, "Too many components for interleaved scan"); + cinfo->comps_in_scan = cinfo->num_components; + for (ci = 0; ci < cinfo->num_components; ci++) { + cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci]; + } + if (cinfo->comps_in_scan == 1) { + noninterleaved_scan_setup(cinfo); + /* Vk block rows constitute the same number of MCU rows */ + mcu_rows_per_loop = cinfo->cur_comp_info[0]->v_samp_factor; + } else { + interleaved_scan_setup(cinfo); + /* in an interleaved scan, one MCU row contains Vk block rows */ + mcu_rows_per_loop = 1; + } + + /* Compute dimensions of full-size pixel buffers */ + /* Note these are the same whether interleaved or not. */ + rows_in_mem = cinfo->max_v_samp_factor * DCTSIZE; + fullsize_width = jround_up(cinfo->image_width, + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + + /* Allocate working memory: */ + /* fullsize_data is sample data before subsampling */ + alloc_sampling_buffer(cinfo, fullsize_data, fullsize_width); + /* subsampled_data is sample data after subsampling */ + subsampled_data = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(JSAMPARRAY)); + for (ci = 0; ci < cinfo->num_components; ci++) { + subsampled_data[ci] = (*cinfo->emethods->alloc_small_sarray) + (cinfo->comp_info[ci].subsampled_width, + (long) (cinfo->comp_info[ci].v_samp_factor * DCTSIZE)); + } + + /* Tell the memory manager to instantiate big arrays. + * We don't need any big arrays in this controller, + * but some other module (like the input file reader) may need one. + */ + (*cinfo->emethods->alloc_big_arrays) + ((long) 0, /* no more small sarrays */ + (long) 0, /* no more small barrays */ + (long) 0); /* no more "medium" objects */ + + /* Initialize output file & do per-scan object init */ + + (*cinfo->methods->write_scan_header) (cinfo); + cinfo->methods->entropy_output = cinfo->methods->write_jpeg_data; + (*cinfo->methods->entropy_encoder_init) (cinfo); + (*cinfo->methods->subsample_init) (cinfo); + (*cinfo->methods->extract_init) (cinfo); + + /* Loop over input image: rows_in_mem pixel rows are processed per loop */ + + mcu_rows_output = 0; + whichss = 1; /* arrange to start with fullsize_data[0] */ + + for (cur_pixel_row = 0; cur_pixel_row < cinfo->image_height; + cur_pixel_row += rows_in_mem) { + whichss ^= 1; /* switch to other fullsize_data buffer */ + + /* Obtain rows_this_time pixel rows and expand to rows_in_mem rows. */ + /* Then we have exactly DCTSIZE row groups for subsampling. */ + rows_this_time = MIN(rows_in_mem, cinfo->image_height - cur_pixel_row); + + (*cinfo->methods->get_sample_rows) (cinfo, rows_this_time, + fullsize_data[whichss]); + (*cinfo->methods->edge_expand) (cinfo, + cinfo->image_width, rows_this_time, + fullsize_width, rows_in_mem, + fullsize_data[whichss]); + + /* Subsample the data (all components) */ + /* First time through is a special case */ + + if (cur_pixel_row) { + /* Subsample last row group of previous set */ + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) DCTSIZE, (short) (DCTSIZE+1), (short) 0, + (short) (DCTSIZE-1)); + /* and dump the previous set's subsampled data */ + (*cinfo->methods->extract_MCUs) (cinfo, subsampled_data, + mcu_rows_per_loop, + cinfo->methods->entropy_encode); + mcu_rows_output += mcu_rows_per_loop; + /* Subsample first row group of this set */ + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) (DCTSIZE+1), (short) 0, (short) 1, + (short) 0); + } else { + /* Subsample first row group with dummy above-context */ + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) (-1), (short) 0, (short) 1, + (short) 0); + } + /* Subsample second through next-to-last row groups of this set */ + for (i = 1; i <= DCTSIZE-2; i++) { + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) (i-1), (short) i, (short) (i+1), + (short) i); + } + } /* end of outer loop */ + + /* Subsample the last row group with dummy below-context */ + /* Note whichss points to last buffer side used */ + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1), + (short) (DCTSIZE-1)); + /* Dump the remaining data (may be less than full height if uninterleaved) */ + (*cinfo->methods->extract_MCUs) (cinfo, subsampled_data, + (int) (cinfo->MCU_rows_in_scan - mcu_rows_output), + cinfo->methods->entropy_encode); + + /* Finish output file */ + (*cinfo->methods->extract_term) (cinfo); + (*cinfo->methods->subsample_term) (cinfo); + (*cinfo->methods->entropy_encoder_term) (cinfo); + (*cinfo->methods->write_scan_trailer) (cinfo); + + /* Release working memory */ + free_sampling_buffer(cinfo, fullsize_data); + for (ci = 0; ci < cinfo->num_components; ci++) { + (*cinfo->emethods->free_small_sarray) + (subsampled_data[ci], + (long) (cinfo->comp_info[ci].v_samp_factor * DCTSIZE)); + } + (*cinfo->emethods->free_small) ((void *) subsampled_data); +} + + +/* + * Compression pipeline controller used for single-scan files + * with optimization of entropy parameters. + */ + +#ifdef ENTROPY_OPT_SUPPORTED + +METHODDEF void +single_eopt_ccontroller (compress_info_ptr cinfo) +{ + int rows_in_mem; /* # of sample rows in full-size buffers */ + long fullsize_width; /* # of samples per row in full-size buffers */ + long cur_pixel_row; /* counts # of pixel rows processed */ + long mcu_rows_output; /* # of MCU rows actually emitted */ + int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */ + /* Work buffer for pre-subsampling data (see comments at head of file) */ + JSAMPIMAGE fullsize_data[2]; + /* Work buffer for subsampled data */ + JSAMPIMAGE subsampled_data; + int rows_this_time; + int blocks_in_big_row; + short ci, whichss, i; + + /* Prepare for single scan containing all components */ + if (cinfo->num_components > MAX_COMPS_IN_SCAN) + ERREXIT(cinfo->emethods, "Too many components for interleaved scan"); + cinfo->comps_in_scan = cinfo->num_components; + for (ci = 0; ci < cinfo->num_components; ci++) { + cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci]; + } + if (cinfo->comps_in_scan == 1) { + noninterleaved_scan_setup(cinfo); + /* Vk block rows constitute the same number of MCU rows */ + mcu_rows_per_loop = cinfo->cur_comp_info[0]->v_samp_factor; + } else { + interleaved_scan_setup(cinfo); + /* in an interleaved scan, one MCU row contains Vk block rows */ + mcu_rows_per_loop = 1; + } + + /* Compute dimensions of full-size pixel buffers */ + /* Note these are the same whether interleaved or not. */ + rows_in_mem = cinfo->max_v_samp_factor * DCTSIZE; + fullsize_width = jround_up(cinfo->image_width, + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + + /* Allocate working memory: */ + /* fullsize_data is sample data before subsampling */ + alloc_sampling_buffer(cinfo, fullsize_data, fullsize_width); + /* subsampled_data is sample data after subsampling */ + subsampled_data = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(JSAMPARRAY)); + for (ci = 0; ci < cinfo->num_components; ci++) { + subsampled_data[ci] = (*cinfo->emethods->alloc_small_sarray) + (cinfo->comp_info[ci].subsampled_width, + (long) (cinfo->comp_info[ci].v_samp_factor * DCTSIZE)); + } + + /* Figure # of MCUs to be packed in a row of whole_scan_MCUs */ + MCUs_in_big_row = MAX_WHOLE_ROW_BLOCKS / cinfo->blocks_in_MCU; + blocks_in_big_row = MCUs_in_big_row * cinfo->blocks_in_MCU; + + /* Request a big array: whole_scan_MCUs saves the MCU data for the scan */ + whole_scan_MCUs = (*cinfo->emethods->request_big_barray) + ((long) blocks_in_big_row, + (long) (cinfo->MCUs_per_row * cinfo->MCU_rows_in_scan + + MCUs_in_big_row-1) / MCUs_in_big_row, + 1L); /* unit height is 1 row */ + + next_whole_row = 0; /* init output ptr for MCU_output_catcher */ + next_MCU_index = MCUs_in_big_row; /* forces access on first call! */ + + /* Tell the memory manager to instantiate big arrays */ + (*cinfo->emethods->alloc_big_arrays) + ((long) 0, /* no more small sarrays */ + (long) 0, /* no more small barrays */ + (long) 0); /* no more "medium" objects */ + + /* Do per-scan object init */ + + (*cinfo->methods->subsample_init) (cinfo); + (*cinfo->methods->extract_init) (cinfo); + + /* Loop over input image: rows_in_mem pixel rows are processed per loop */ + /* MCU data goes into whole_scan_MCUs, not to the entropy encoder */ + + mcu_rows_output = 0; + whichss = 1; /* arrange to start with fullsize_data[0] */ + + for (cur_pixel_row = 0; cur_pixel_row < cinfo->image_height; + cur_pixel_row += rows_in_mem) { + whichss ^= 1; /* switch to other fullsize_data buffer */ + + /* Obtain rows_this_time pixel rows and expand to rows_in_mem rows. */ + /* Then we have exactly DCTSIZE row groups for subsampling. */ + rows_this_time = MIN(rows_in_mem, cinfo->image_height - cur_pixel_row); + + (*cinfo->methods->get_sample_rows) (cinfo, rows_this_time, + fullsize_data[whichss]); + (*cinfo->methods->edge_expand) (cinfo, + cinfo->image_width, rows_this_time, + fullsize_width, rows_in_mem, + fullsize_data[whichss]); + + /* Subsample the data (all components) */ + /* First time through is a special case */ + + if (cur_pixel_row) { + /* Subsample last row group of previous set */ + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) DCTSIZE, (short) (DCTSIZE+1), (short) 0, + (short) (DCTSIZE-1)); + /* and dump the previous set's subsampled data */ + (*cinfo->methods->extract_MCUs) (cinfo, subsampled_data, + mcu_rows_per_loop, + MCU_output_catcher); + mcu_rows_output += mcu_rows_per_loop; + /* Subsample first row group of this set */ + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) (DCTSIZE+1), (short) 0, (short) 1, + (short) 0); + } else { + /* Subsample first row group with dummy above-context */ + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) (-1), (short) 0, (short) 1, + (short) 0); + } + /* Subsample second through next-to-last row groups of this set */ + for (i = 1; i <= DCTSIZE-2; i++) { + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) (i-1), (short) i, (short) (i+1), + (short) i); + } + } /* end of outer loop */ + + /* Subsample the last row group with dummy below-context */ + /* Note whichss points to last buffer side used */ + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1), + (short) (DCTSIZE-1)); + /* Dump the remaining data (may be less than full height if uninterleaved) */ + (*cinfo->methods->extract_MCUs) (cinfo, subsampled_data, + (int) (cinfo->MCU_rows_in_scan - mcu_rows_output), + MCU_output_catcher); + + /* Clean up after that stuff, then find the optimal entropy parameters */ + + (*cinfo->methods->extract_term) (cinfo); + (*cinfo->methods->subsample_term) (cinfo); + + (*cinfo->methods->entropy_optimize) (cinfo, dump_scan_MCUs); + + /* Emit scan to output file */ + /* Note: we can't do write_scan_header until entropy parameters are set! */ + + (*cinfo->methods->write_scan_header) (cinfo); + cinfo->methods->entropy_output = cinfo->methods->write_jpeg_data; + (*cinfo->methods->entropy_encoder_init) (cinfo); + dump_scan_MCUs(cinfo, cinfo->methods->entropy_encode); + (*cinfo->methods->entropy_encoder_term) (cinfo); + (*cinfo->methods->write_scan_trailer) (cinfo); + + /* Release working memory */ + free_sampling_buffer(cinfo, fullsize_data); + for (ci = 0; ci < cinfo->num_components; ci++) { + (*cinfo->emethods->free_small_sarray) + (subsampled_data[ci], + (long) (cinfo->comp_info[ci].v_samp_factor * DCTSIZE)); + } + (*cinfo->emethods->free_small) ((void *) subsampled_data); + (*cinfo->emethods->free_big_barray) (whole_scan_MCUs); +} + +#endif /* ENTROPY_OPT_SUPPORTED */ + + +/* + * Compression pipeline controller used for multiple-scan files + * with no optimization of entropy parameters. + */ + +#ifdef MULTISCAN_FILES_SUPPORTED + +METHODDEF void +multi_ccontroller (compress_info_ptr cinfo) +{ + ERREXIT(cinfo->emethods, "Not implemented yet"); +} + +#endif /* MULTISCAN_FILES_SUPPORTED */ + + +/* + * Compression pipeline controller used for multiple-scan files + * with optimization of entropy parameters. + */ + +#ifdef MULTISCAN_FILES_SUPPORTED +#ifdef ENTROPY_OPT_SUPPORTED + +METHODDEF void +multi_eopt_ccontroller (compress_info_ptr cinfo) +{ + ERREXIT(cinfo->emethods, "Not implemented yet"); +} + +#endif /* ENTROPY_OPT_SUPPORTED */ +#endif /* MULTISCAN_FILES_SUPPORTED */ + + +/* + * The method selection routine for compression pipeline controllers. + */ + +GLOBAL void +jselcpipeline (compress_info_ptr cinfo) +{ + if (cinfo->interleave || cinfo->num_components == 1) { + /* single scan needed */ +#ifdef ENTROPY_OPT_SUPPORTED + if (cinfo->optimize_coding) + cinfo->methods->c_pipeline_controller = single_eopt_ccontroller; + else +#endif + cinfo->methods->c_pipeline_controller = single_ccontroller; + } else { + /* multiple scans needed */ +#ifdef MULTISCAN_FILES_SUPPORTED +#ifdef ENTROPY_OPT_SUPPORTED + if (cinfo->optimize_coding) + cinfo->methods->c_pipeline_controller = multi_eopt_ccontroller; + else +#endif + cinfo->methods->c_pipeline_controller = multi_ccontroller; +#else + ERREXIT(cinfo->emethods, "Multiple-scan support was not compiled"); +#endif + } +} diff --git a/jcsample.c b/jcsample.c new file mode 100644 index 0000000..d23e23a --- /dev/null +++ b/jcsample.c @@ -0,0 +1,135 @@ +/* + * jcsample.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains subsampling routines. + * These routines are invoked via the subsample and + * subsample_init/term methods. + */ + +#include "jinclude.h" + + +/* + * Initialize for subsampling a scan. + */ + +METHODDEF void +subsample_init (compress_info_ptr cinfo) +{ + /* no work for now */ +} + + +/* + * Subsample pixel values of a single component. + * This version only handles integral sampling ratios. + */ + +METHODDEF void +subsample (compress_info_ptr cinfo, int which_component, + long input_cols, int input_rows, + long output_cols, int output_rows, + JSAMPARRAY above, JSAMPARRAY input_data, JSAMPARRAY below, + JSAMPARRAY output_data) +{ + jpeg_component_info * compptr = cinfo->cur_comp_info[which_component]; + int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v; + long outcol; + JSAMPROW inptr, outptr; + INT32 outvalue; + + /* TEMP FOR DEBUGGING PIPELINE CONTROLLER */ + if (output_rows != compptr->v_samp_factor || + input_rows != cinfo->max_v_samp_factor || + (output_cols % compptr->h_samp_factor) != 0 || + (input_cols % cinfo->max_h_samp_factor) != 0 || + input_cols*compptr->h_samp_factor != output_cols*cinfo->max_h_samp_factor) + ERREXIT(cinfo->emethods, "Bogus subsample parameters"); + + h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor; + v_expand = cinfo->max_v_samp_factor / compptr->v_samp_factor; + numpix = h_expand * v_expand; + numpix2 = numpix/2; + + inrow = 0; + for (outrow = 0; outrow < output_rows; outrow++) { + outptr = output_data[outrow]; + for (outcol = 0; outcol < output_cols; outcol++) { + outvalue = 0; + for (v = 0; v < v_expand; v++) { + inptr = input_data[inrow+v] + (outcol*h_expand); + for (h = 0; h < h_expand; h++) { + outvalue += GETJSAMPLE(*inptr++); + } + } + *outptr++ = (outvalue + numpix2) / numpix; + } + inrow += v_expand; + } +} + + +/* + * Subsample pixel values of a single component. + * This version handles the special case of a full-size component. + */ + +METHODDEF void +fullsize_subsample (compress_info_ptr cinfo, int which_component, + long input_cols, int input_rows, + long output_cols, int output_rows, + JSAMPARRAY above, JSAMPARRAY input_data, JSAMPARRAY below, + JSAMPARRAY output_data) +{ + if (input_cols != output_cols || input_rows != output_rows) /* DEBUG */ + ERREXIT(cinfo->emethods, "Pipeline controller messed up"); + + jcopy_sample_rows(input_data, 0, output_data, 0, output_rows, output_cols); +} + + +/* + * Clean up after a scan. + */ + +METHODDEF void +subsample_term (compress_info_ptr cinfo) +{ + /* no work for now */ +} + + + +/* + * The method selection routine for subsampling. + * Note that we must select a routine for each component. + */ + +GLOBAL void +jselsubsample (compress_info_ptr cinfo) +{ + short ci; + jpeg_component_info * compptr; + + if (cinfo->CCIR601_sampling) + ERREXIT(cinfo->emethods, "CCIR601 subsampling not implemented yet"); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + if (compptr->h_samp_factor == cinfo->max_h_samp_factor && + compptr->v_samp_factor == cinfo->max_v_samp_factor) + cinfo->methods->subsample[ci] = fullsize_subsample; + else if ((cinfo->max_h_samp_factor % compptr->h_samp_factor) == 0 && + (cinfo->max_v_samp_factor % compptr->v_samp_factor) == 0) + cinfo->methods->subsample[ci] = subsample; + else + ERREXIT(cinfo->emethods, "Fractional subsampling not implemented yet"); + } + + cinfo->methods->subsample_init = subsample_init; + cinfo->methods->subsample_term = subsample_term; +} diff --git a/jdarith.c b/jdarith.c new file mode 100644 index 0000000..0f19be8 --- /dev/null +++ b/jdarith.c @@ -0,0 +1,42 @@ +/* + * jdarith.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains arithmetic entropy decoding routines. + * These routines are invoked via the methods entropy_decode + * and entropy_decoder_init/term. + */ + +#include "jinclude.h" + +#ifdef ARITH_CODING_SUPPORTED + + +/* + * The arithmetic coding option of the JPEG standard specifies Q-coding, + * which is covered by patents held by IBM (and possibly AT&T and Mitsubishi). + * At this time it does not appear to be legal for the Independent JPEG + * Group to distribute software that implements arithmetic coding. + * We have therefore removed arithmetic coding support from the + * distributed source code. + * + * We're not happy about it either. + */ + + +/* + * The method selection routine for arithmetic entropy decoding. + */ + +GLOBAL void +jseldarithmetic (decompress_info_ptr cinfo) +{ + if (cinfo->arith_code) { + ERREXIT(cinfo->emethods, "Sorry, there are legal restrictions on arithmetic coding"); + } +} + +#endif /* ARITH_CODING_SUPPORTED */ diff --git a/jdcolor.c b/jdcolor.c new file mode 100644 index 0000000..a39ebff --- /dev/null +++ b/jdcolor.c @@ -0,0 +1,194 @@ +/* + * jdcolor.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains output colorspace conversion routines. + * These routines are invoked via the methods color_convert + * and colorout_init/term. + */ + +#include "jinclude.h" + + +/* + * Initialize for colorspace conversion. + */ + +METHODDEF void +colorout_init (decompress_info_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * Convert some rows of samples to the output colorspace. + * This version handles YCbCr -> RGB conversion. + * YCbCr is defined per CCIR 601-1, except that Cb and Cr are + * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + */ + +METHODDEF void +ycc_rgb_convert (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE input_data, JSAMPIMAGE output_data) +{ + register INT32 y, u, v, x; + register JSAMPROW inptr0, inptr1, inptr2; + register JSAMPROW outptr0, outptr1, outptr2; + register long col; + register long width = cinfo->image_width; + register int row; + + for (row = 0; row < num_rows; row++) { + inptr0 = input_data[0][row]; + inptr1 = input_data[1][row]; + inptr2 = input_data[2][row]; + outptr0 = output_data[0][row]; + outptr1 = output_data[1][row]; + outptr2 = output_data[2][row]; + for (col = width; col > 0; col--) { + y = GETJSAMPLE(*inptr0++); + u = (int) GETJSAMPLE(*inptr1++) - CENTERJSAMPLE; + v = (int) GETJSAMPLE(*inptr2++) - CENTERJSAMPLE; + /* Note: if the inputs were computed directly from RGB values, + * range-limiting would be unnecessary here; but due to possible + * noise in the DCT/IDCT phase, we do need to apply range limits. + */ + y *= 1024; /* in case compiler can't spot common subexpression */ + x = y + 1436*v + 512; /* red */ + if (x < 0) x = 0; + if (x > ((INT32) MAXJSAMPLE*1024)) x = (INT32) MAXJSAMPLE*1024; + *outptr0++ = x >> 10; + x = y - 352*u - 731*v + 512; /* green */ + if (x < 0) x = 0; + if (x > ((INT32) MAXJSAMPLE*1024)) x = (INT32) MAXJSAMPLE*1024; + *outptr1++ = x >> 10; + x = y + 1815*u + 512; /* blue */ + if (x < 0) x = 0; + if (x > ((INT32) MAXJSAMPLE*1024)) x = (INT32) MAXJSAMPLE*1024; + *outptr2++ = x >> 10; + } + } +} + + +/* + * Color conversion for no colorspace change: just copy the data. + */ + +METHODDEF void +null_convert (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE input_data, JSAMPIMAGE output_data) +{ + short ci; + + for (ci = 0; ci < cinfo->num_components; ci++) { + jcopy_sample_rows(input_data[ci], 0, output_data[ci], 0, + num_rows, cinfo->image_width); + } +} + + +/* + * Color conversion for grayscale: just copy the data. + * This also works for YCbCr/YIQ -> grayscale conversion, in which + * we just copy the Y (luminance) component and ignore chrominance. + */ + +METHODDEF void +grayscale_convert (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE input_data, JSAMPIMAGE output_data) +{ + jcopy_sample_rows(input_data[0], 0, output_data[0], 0, + num_rows, cinfo->image_width); +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +colorout_term (decompress_info_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * The method selection routine for output colorspace conversion. + */ + +GLOBAL void +jseldcolor (decompress_info_ptr cinfo) +{ + /* Make sure num_components agrees with jpeg_color_space */ + switch (cinfo->jpeg_color_space) { + case CS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo->emethods, "Bogus JPEG colorspace"); + break; + + case CS_RGB: + case CS_YIQ: + case CS_YCbCr: + if (cinfo->num_components != 3) + ERREXIT(cinfo->emethods, "Bogus JPEG colorspace"); + break; + + case CS_CMYK: + if (cinfo->num_components != 4) + ERREXIT(cinfo->emethods, "Bogus JPEG colorspace"); + break; + + default: + ERREXIT(cinfo->emethods, "Unsupported JPEG colorspace"); + break; + } + + /* Set color_out_comps and conversion method based on requested space */ + switch (cinfo->out_color_space) { + case CS_GRAYSCALE: + cinfo->color_out_comps = 1; + if (cinfo->jpeg_color_space == CS_GRAYSCALE || + cinfo->jpeg_color_space == CS_YCbCr || + cinfo->jpeg_color_space == CS_YIQ) + cinfo->methods->color_convert = grayscale_convert; + else + ERREXIT(cinfo->emethods, "Unsupported color conversion request"); + break; + + case CS_RGB: + cinfo->color_out_comps = 3; + if (cinfo->jpeg_color_space == CS_YCbCr) + cinfo->methods->color_convert = ycc_rgb_convert; + else if (cinfo->jpeg_color_space == CS_RGB) + cinfo->methods->color_convert = null_convert; + else + ERREXIT(cinfo->emethods, "Unsupported color conversion request"); + break; + + case CS_CMYK: + cinfo->color_out_comps = 4; + if (cinfo->jpeg_color_space == CS_CMYK) + cinfo->methods->color_convert = null_convert; + else + ERREXIT(cinfo->emethods, "Unsupported color conversion request"); + break; + + default: + ERREXIT(cinfo->emethods, "Unsupported output colorspace"); + break; + } + + if (cinfo->quantize_colors) + cinfo->final_out_comps = 1; /* single colormapped output component */ + else + cinfo->final_out_comps = cinfo->color_out_comps; + + cinfo->methods->colorout_init = colorout_init; + cinfo->methods->colorout_term = colorout_term; +} diff --git a/jdhuff.c b/jdhuff.c new file mode 100644 index 0000000..e9af688 --- /dev/null +++ b/jdhuff.c @@ -0,0 +1,318 @@ +/* + * jdhuff.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines. + * These routines are invoked via the methods entropy_decode + * and entropy_decoder_init/term. + */ + +#include "jinclude.h" + + +/* Static variables to avoid passing 'round extra parameters */ + +static decompress_info_ptr dcinfo; + +static unsigned int get_buffer; /* current bit-extraction buffer */ +static int bits_left; /* # of unused bits in it */ + + +LOCAL void +fix_huff_tbl (HUFF_TBL * htbl) +/* Compute derived values for a Huffman table */ +{ + int p, i, l, lastp, si; + char huffsize[257]; + UINT16 huffcode[257]; + UINT16 code; + + /* Figure 7.3.5.4.2.1: make table of Huffman code length for each symbol */ + /* Note that this is in code-length order. */ + + p = 0; + for (l = 1; l <= 16; l++) { + for (i = 1; i <= htbl->bits[l]; i++) + huffsize[p++] = l; + } + huffsize[p] = 0; + lastp = p; + + /* Figure 7.3.5.4.2.2: generate the codes themselves */ + /* Note that this is in code-length order. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (huffsize[p] == si) { + huffcode[p++] = code; + code++; + } + code <<= 1; + si++; + } + + /* Figure 7.3.5.4.2.3: generate encoding tables */ + /* These are code and size indexed by symbol value */ + + for (p = 0; p < lastp; p++) { + htbl->ehufco[htbl->huffval[p]] = huffcode[p]; + htbl->ehufsi[htbl->huffval[p]] = huffsize[p]; + } + + /* Figure 13.4.2.3.1: generate decoding tables */ + + p = 0; + for (l = 1; l <= 16; l++) { + if (htbl->bits[l]) { + htbl->valptr[l] = p; /* huffval[] index of 1st sym of code len l */ + htbl->mincode[l] = huffcode[p]; /* minimum code of length l */ + p += htbl->bits[l]; + htbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */ + } else { + htbl->maxcode[l] = -1; + } + } +} + + +/* Extract the next N bits from the input stream (N <= 8) */ + +LOCAL int +get_bits (int nbits) +{ + int result; + + while (nbits > bits_left) { + int c = JGETC(dcinfo); + + get_buffer = (get_buffer << 8) + c; + bits_left += 8; + /* If it's 0xFF, check and discard stuffed zero byte */ + if (c == 0xff) { + c = JGETC(dcinfo); /* Byte stuffing */ + if (c != 0) + ERREXIT1(dcinfo->emethods, + "Unexpected marker 0x%02x in compressed data", c); + } + } + + bits_left -= nbits; + result = (get_buffer >> bits_left) & ((1 << nbits) - 1); + return result; +} + +/* Macro to make things go at some speed! */ + +#define get_bit() (bits_left ? \ + ((get_buffer >> (--bits_left)) & 1) : \ + get_bits(1)) + + +/* Figure 13.4.2.3.2: extract next coded symbol from input stream */ + +LOCAL int +huff_DECODE (HUFF_TBL * htbl) +{ + int l, p; + INT32 code; + + code = get_bit(); + l = 1; + while (code > htbl->maxcode[l]) { + code = (code << 1) + get_bit(); + l++; + } + + p = htbl->valptr[l] + (code - htbl->mincode[l]); + + return htbl->huffval[p]; +} + + +/* Figure 13.4.2.1.1: extend sign bit */ + +#define huff_EXTEND(x, s) ((x) < (1 << ((s)-1)) ? \ + (x) + (-1 << (s)) + 1 : \ + (x)) + + +/* Decode a single block's worth of coefficients */ +/* Note that only the difference is returned for the DC coefficient */ + +LOCAL void +decode_one_block (JBLOCK block, HUFF_TBL *dctbl, HUFF_TBL *actbl) +{ + int s, k, r, n; + + /* zero out the coefficient block */ + + MEMZERO((void *) block, SIZEOF(JBLOCK)); + + /* Section 13.4.2.1: decode the DC coefficient difference */ + + s = huff_DECODE(dctbl); + r = get_bits(s); + block[0] = huff_EXTEND(r, s); + + /* Section 13.4.2.2: decode the AC coefficients */ + + for (k = 1; k < DCTSIZE2; k++) { + r = huff_DECODE(actbl); + + s = r & 15; + n = r >> 4; + + if (s) { + k = k + n; + r = get_bits(s); + block[k] = huff_EXTEND(r, s); + } else { + if (n != 15) + break; + k += 15; + } + } +} + + +/* + * Initialize for a Huffman-compressed scan. + * This is invoked after reading the SOS marker. + */ + +METHODDEF void +huff_decoder_init (decompress_info_ptr cinfo) +{ + short ci; + jpeg_component_info * compptr; + + /* Initialize static variables */ + dcinfo = cinfo; + bits_left = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Make sure requested tables are present */ + if (cinfo->dc_huff_tbl_ptrs[compptr->dc_tbl_no] == NULL || + cinfo->ac_huff_tbl_ptrs[compptr->ac_tbl_no] == NULL) + ERREXIT(cinfo->emethods, "Use of undefined Huffman table"); + /* Compute derived values for Huffman tables */ + /* We may do this more than once for same table, but it's not a big deal */ + fix_huff_tbl(cinfo->dc_huff_tbl_ptrs[compptr->dc_tbl_no]); + fix_huff_tbl(cinfo->ac_huff_tbl_ptrs[compptr->ac_tbl_no]); + /* Initialize DC predictions to 0 */ + cinfo->last_dc_val[ci] = 0; + } + + /* Initialize restart stuff */ + cinfo->restarts_to_go = cinfo->restart_interval; + cinfo->next_restart_num = 0; +} + + +/* + * Check for a restart marker & resynchronize decoder. + */ + +LOCAL void +process_restart (decompress_info_ptr cinfo) +{ + int c, nbytes; + short ci; + + /* Throw away any partial unread byte */ + bits_left = 0; + + /* Scan for next JPEG marker */ + nbytes = 0; + do { + do { /* skip any non-FF bytes */ + nbytes++; + c = JGETC(cinfo); + } while (c != 0xFF); + do { /* skip any duplicate FFs */ + nbytes++; + c = JGETC(cinfo); + } while (c == 0xFF); + } while (c == 0); /* repeat if it was a stuffed FF/00 */ + + if (c != (RST0 + cinfo->next_restart_num)) + ERREXIT2(cinfo->emethods, "Found 0x%02x marker instead of RST%d", + c, cinfo->next_restart_num); + + if (nbytes != 2) + TRACEMS2(cinfo->emethods, 1, "Skipped %d bytes before RST%d", + nbytes-2, cinfo->next_restart_num); + else + TRACEMS1(cinfo->emethods, 2, "RST%d", cinfo->next_restart_num); + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + cinfo->last_dc_val[ci] = 0; + + /* Update restart state */ + cinfo->restarts_to_go = cinfo->restart_interval; + cinfo->next_restart_num++; + cinfo->next_restart_num &= 7; +} + + +/* + * Decode and return one MCU's worth of Huffman-compressed coefficients. + */ + +METHODDEF void +huff_decode (decompress_info_ptr cinfo, JBLOCK *MCU_data) +{ + short blkn, ci; + jpeg_component_info * compptr; + + /* Account for restart interval, process restart marker if needed */ + if (cinfo->restart_interval) { + if (cinfo->restarts_to_go == 0) + process_restart(cinfo); + cinfo->restarts_to_go--; + } + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + decode_one_block(MCU_data[blkn], + cinfo->dc_huff_tbl_ptrs[compptr->dc_tbl_no], + cinfo->ac_huff_tbl_ptrs[compptr->ac_tbl_no]); + /* Convert DC difference to actual value, update last_dc_val */ + MCU_data[blkn][0] += cinfo->last_dc_val[ci]; + cinfo->last_dc_val[ci] = MCU_data[blkn][0]; + } +} + + +/* + * Finish up at the end of a Huffman-compressed scan. + */ + +METHODDEF void +huff_decoder_term (decompress_info_ptr cinfo) +{ + /* No work needed */ +} + + +/* + * The method selection routine for Huffman entropy decoding. + */ + +GLOBAL void +jseldhuffman (decompress_info_ptr cinfo) +{ + if (! cinfo->arith_code) { + cinfo->methods->entropy_decoder_init = huff_decoder_init; + cinfo->methods->entropy_decode = huff_decode; + cinfo->methods->entropy_decoder_term = huff_decoder_term; + } +} diff --git a/jdmain.c b/jdmain.c new file mode 100644 index 0000000..109d124 --- /dev/null +++ b/jdmain.c @@ -0,0 +1,289 @@ +/* + * jdmain.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a trivial test user interface for the JPEG decompressor. + * It should work on any system with Unix- or MS-DOS-style command lines. + * + * Two different command line styles are permitted, depending on the + * compile-time switch TWO_FILE_COMMANDLINE: + * djpeg [options] inputfile outputfile + * djpeg [options] [inputfile] + * In the second style, output is always to standard output, which you'd + * normally redirect to a file or pipe to some other program. Input is + * either from a named file or from standard input (typically redirected). + * The second style is convenient on Unix but is unhelpful on systems that + * don't support pipes. Also, you MUST use the first style if your system + * doesn't do binary I/O to stdin/stdout. + */ + +#include "jinclude.h" +#ifdef __STDC__ +#include /* to declare exit() */ +#endif + +#ifdef THINK_C +#include /* command-line reader for Macintosh */ +#endif + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define WRITE_BINARY "w" +#else +#define READ_BINARY "rb" +#define WRITE_BINARY "wb" +#endif + + +/* + * If your system has getopt(3), you can use your library version by + * defining HAVE_GETOPT. By default, we use the PD 'egetopt'. + */ + +#ifdef HAVE_GETOPT +extern int getopt PP((int argc, char **argv, char *optstring)); +extern char * optarg; +extern int optind; +#else +#include "egetopt.c" +#define getopt(argc,argv,opt) egetopt(argc,argv,opt) +#endif + + +typedef enum { /* defines known output image formats */ + FMT_PPM, /* PPM/PGM (PBMPLUS formats) */ + FMT_GIF, /* GIF format */ + FMT_TIFF /* TIFF format */ +} IMAGE_FORMATS; + +static IMAGE_FORMATS requested_fmt; + + +/* + * This routine gets control after the input file header has been read. + * It must determine what output file format is to be written, + * and make any other decompression parameter changes that are desirable. + */ + +METHODDEF void +d_ui_method_selection (decompress_info_ptr cinfo) +{ + /* if grayscale or CMYK input, force similar output; */ + /* else leave the output colorspace as set by options. */ + if (cinfo->jpeg_color_space == CS_GRAYSCALE) + cinfo->out_color_space = CS_GRAYSCALE; + else if (cinfo->jpeg_color_space == CS_CMYK) + cinfo->out_color_space = CS_CMYK; + + /* select output file format */ + /* Note: jselwxxx routine may make additional parameter changes, + * such as forcing color quantization if it's a colormapped format. + */ + switch (requested_fmt) { +#ifdef GIF_SUPPORTED + case FMT_GIF: + jselwgif(cinfo); + break; +#endif +#ifdef PPM_SUPPORTED + case FMT_PPM: + jselwppm(cinfo); + break; +#endif + default: + ERREXIT(cinfo->emethods, "Unsupported output file format"); + break; + } +} + + +/* + * Reload the input buffer after it's been emptied, and return the next byte. + * See the JGETC macro for calling conditions. + * + * This routine would need to be replaced if reading JPEG data from something + * other than a stdio stream. + */ + +METHODDEF int +read_jpeg_data (decompress_info_ptr cinfo) +{ + cinfo->bytes_in_buffer = fread(cinfo->input_buffer + MIN_UNGET, + 1, JPEG_BUF_SIZE, + cinfo->input_file); + + cinfo->next_input_byte = cinfo->input_buffer + MIN_UNGET; + + if (cinfo->bytes_in_buffer <= 0) + ERREXIT(cinfo->emethods, "Unexpected EOF in JPEG file"); + + return JGETC(cinfo); +} + + + +LOCAL void +usage (char * progname) +/* complain about bad command line */ +{ + fprintf(stderr, "usage: %s ", progname); + fprintf(stderr, "[-b] [-q colors] [-2] [-d] [-g] [-G]"); +#ifdef TWO_FILE_COMMANDLINE + fprintf(stderr, " inputfile outputfile\n"); +#else + fprintf(stderr, " [inputfile]\n"); +#endif + exit(2); +} + + +/* + * The main program. + */ + +GLOBAL void +main (int argc, char **argv) +{ + struct decompress_info_struct cinfo; + struct decompress_methods_struct dc_methods; + struct external_methods_struct e_methods; + int c; + + /* On Mac, fetch a command line. */ +#ifdef THINK_C + argc = ccommand(&argv); +#endif + + /* Initialize the system-dependent method pointers. */ + cinfo.methods = &dc_methods; + cinfo.emethods = &e_methods; + jselerror(&e_methods); /* error/trace message routines */ + jselvirtmem(&e_methods); /* memory allocation routines */ + dc_methods.d_ui_method_selection = d_ui_method_selection; + dc_methods.read_jpeg_data = read_jpeg_data; + + /* Allocate memory for input buffer. */ + cinfo.input_buffer = (char *) (*cinfo.emethods->alloc_small) + ((size_t) (JPEG_BUF_SIZE + MIN_UNGET)); + cinfo.bytes_in_buffer = 0; /* initialize buffer to empty */ + + /* Set up default input and output file references. */ + /* (These may be overridden below.) */ + cinfo.input_file = stdin; + cinfo.output_file = stdout; + + /* Set up default parameters. */ + e_methods.trace_level = 0; + cinfo.output_gamma = 1.0; + cinfo.quantize_colors = FALSE; + cinfo.two_pass_quantize = FALSE; + cinfo.use_dithering = FALSE; + cinfo.desired_number_of_colors = 256; + cinfo.do_block_smoothing = FALSE; + cinfo.do_pixel_smoothing = FALSE; + cinfo.out_color_space = CS_RGB; + cinfo.jpeg_color_space = CS_UNKNOWN; + /* setting any other value in jpeg_color_space overrides heuristics */ + /* in jrdjfif.c ... */ + /* You may wanta change the default output format; here's the place: */ +#ifdef PPM_SUPPORTED + requested_fmt = FMT_PPM; +#else + requested_fmt = FMT_GIF; +#endif + + /* Scan parameters */ + + while ((c = getopt(argc, argv, "bq:2DdgG")) != EOF) + switch (c) { + case 'b': /* Enable cross-block smoothing. */ + cinfo.do_block_smoothing = TRUE; + break; + case 'q': /* Do color quantization. */ + { int val; + if (optarg == NULL) + usage(argv[0]); + if (sscanf(optarg, "%d", &val) != 1) + usage(argv[0]); + cinfo.desired_number_of_colors = val; + } + cinfo.quantize_colors = TRUE; + break; + case '2': /* Use two-pass quantization. */ + cinfo.two_pass_quantize = TRUE; + break; + case 'D': /* Use dithering in color quantization. */ + cinfo.use_dithering = TRUE; + break; + case 'd': /* Debugging. */ + e_methods.trace_level++; + break; + case 'g': /* Force grayscale output. */ + cinfo.out_color_space = CS_GRAYSCALE; + break; + case 'G': /* GIF output format. */ + requested_fmt = FMT_GIF; + break; + case '?': + default: + usage(argv[0]); + break; + } + + /* Select the input and output files */ + +#ifdef TWO_FILE_COMMANDLINE + + if (optind != argc-2) { + fprintf(stderr, "%s: must name one input and one output file\n", argv[0]); + usage(argv[0]); + } + if ((cinfo.input_file = fopen(argv[optind], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", argv[0], argv[optind]); + exit(2); + } + if ((cinfo.output_file = fopen(argv[optind+1], WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", argv[0], argv[optind+1]); + exit(2); + } + +#else /* not TWO_FILE_COMMANDLINE -- use Unix style */ + + if (optind < argc-1) { + fprintf(stderr, "%s: only one input file\n", argv[0]); + usage(argv[0]); + } + if (optind < argc) { + if ((cinfo.input_file = fopen(argv[optind], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", argv[0], argv[optind]); + exit(2); + } + } + +#endif /* TWO_FILE_COMMANDLINE */ + + /* Set up to read a JFIF or baseline-JPEG file. */ + /* A smarter UI would inspect the first few bytes of the input file */ + /* to determine its type. */ +#ifdef JFIF_SUPPORTED + jselrjfif(&cinfo); +#else + You shoulda defined JFIF_SUPPORTED. /* deliberate syntax error */ +#endif + + /* Do it to it! */ + jpeg_decompress(&cinfo); + + /* Release memory. */ + (*cinfo.emethods->free_small) ((void *) cinfo.input_buffer); +#ifdef MEM_STATS + if (e_methods.trace_level > 0) + j_mem_stats(); +#endif + + /* All done. */ + exit(0); +} diff --git a/jdmaster.c b/jdmaster.c new file mode 100644 index 0000000..5693882 --- /dev/null +++ b/jdmaster.c @@ -0,0 +1,180 @@ +/* + * jdmaster.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main control for the JPEG decompressor. + * The system-dependent (user interface) code should call jpeg_decompress() + * after doing appropriate setup of the decompress_info_struct parameter. + */ + +#include "jinclude.h" + + +METHODDEF void +d_per_scan_method_selection (decompress_info_ptr cinfo) +/* Central point for per-scan method selection */ +{ + /* MCU disassembly */ + jseldmcu(cinfo); + /* Un-subsampling of pixels */ + jselunsubsample(cinfo); +} + + +LOCAL void +d_initial_method_selection (decompress_info_ptr cinfo) +/* Central point for initial method selection (after reading file header) */ +{ + /* JPEG file scanning method selection is already done. */ + /* So is output file format selection (both are done by user interface). */ + + /* Entropy decoding: either Huffman or arithmetic coding. */ +#ifdef ARITH_CODING_SUPPORTED + jseldarithmetic(cinfo); +#else + if (cinfo->arith_code) { + ERREXIT(cinfo->emethods, "Arithmetic coding not supported"); + } +#endif + jseldhuffman(cinfo); + /* Cross-block smoothing */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + jselbsmooth(cinfo); +#else + cinfo->do_block_smoothing = FALSE; +#endif + /* Gamma and color space conversion */ + jseldcolor(cinfo); + + /* Color quantization */ +#ifdef QUANT_1PASS_SUPPORTED +#ifndef QUANT_2PASS_SUPPORTED + cinfo->two_pass_quantize = FALSE; /* only have 1-pass */ +#endif +#else /* not QUANT_1PASS_SUPPORTED */ +#ifdef QUANT_2PASS_SUPPORTED + cinfo->two_pass_quantize = TRUE; /* only have 2-pass */ +#else /* not QUANT_2PASS_SUPPORTED */ + if (cinfo->quantize_colors) { + ERREXIT(cinfo->emethods, "Color quantization was not compiled"); + } +#endif +#endif + +#ifdef QUANT_1PASS_SUPPORTED + jsel1quantize(cinfo); +#endif +#ifdef QUANT_2PASS_SUPPORTED + jsel2quantize(cinfo); +#endif + + /* Pipeline control */ + jseldpipeline(cinfo); + /* Overall control (that's me!) */ + cinfo->methods->d_per_scan_method_selection = d_per_scan_method_selection; +} + + +LOCAL void +initial_setup (decompress_info_ptr cinfo) +/* Do computations that are needed before initial method selection */ +{ + short ci; + jpeg_component_info *compptr; + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0; ci < cinfo->num_components; ci++) { + compptr = &cinfo->comp_info[ci]; + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo->emethods, "Bogus sampling factors"); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + + } + + /* Compute logical subsampled dimensions of components */ + for (ci = 0; ci < cinfo->num_components; ci++) { + compptr = &cinfo->comp_info[ci]; + compptr->true_comp_width = (cinfo->image_width * compptr->h_samp_factor + + cinfo->max_h_samp_factor - 1) + / cinfo->max_h_samp_factor; + compptr->true_comp_height = (cinfo->image_height * compptr->v_samp_factor + + cinfo->max_v_samp_factor - 1) + / cinfo->max_v_samp_factor; + } +} + + +/* + * This is the main entry point to the JPEG decompressor. + */ + + +GLOBAL void +jpeg_decompress (decompress_info_ptr cinfo) +{ + short i; + + /* Initialize pointers as needed to mark stuff unallocated. */ + cinfo->comp_info = NULL; + for (i = 0; i < NUM_QUANT_TBLS; i++) + cinfo->quant_tbl_ptrs[i] = NULL; + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + /* Read the JPEG file header markers; everything up through the first SOS + * marker is read now. NOTE: the user interface must have initialized the + * read_file_header method pointer (eg, by calling jselrjfif or jselrtiff). + * The other file reading methods (read_scan_header etc.) were probably + * set at the same time, but could be set up by read_file_header itself. + */ + (*cinfo->methods->read_file_header) (cinfo); + if (! ((*cinfo->methods->read_scan_header) (cinfo))) + ERREXIT(cinfo->emethods, "Empty JPEG file"); + + /* Give UI a chance to adjust decompression parameters and select */ + /* output file format based on info from file header. */ + (*cinfo->methods->d_ui_method_selection) (cinfo); + + /* Now select methods for decompression steps. */ + initial_setup(cinfo); + d_initial_method_selection(cinfo); + + /* Initialize the output file & other modules as needed */ + /* (color_quant and entropy_decoder are inited by pipeline controller) */ + + (*cinfo->methods->output_init) (cinfo); + (*cinfo->methods->colorout_init) (cinfo); + + /* And let the pipeline controller do the rest. */ + (*cinfo->methods->d_pipeline_controller) (cinfo); + + /* Finish output file, release working storage, etc */ + (*cinfo->methods->colorout_term) (cinfo); + (*cinfo->methods->output_term) (cinfo); + (*cinfo->methods->read_file_trailer) (cinfo); + + /* Release allocated storage for tables */ +#define FREE(ptr) if ((ptr) != NULL) \ + (*cinfo->emethods->free_small) ((void *) ptr) + + FREE(cinfo->comp_info); + for (i = 0; i < NUM_QUANT_TBLS; i++) + FREE(cinfo->quant_tbl_ptrs[i]); + for (i = 0; i < NUM_HUFF_TBLS; i++) { + FREE(cinfo->dc_huff_tbl_ptrs[i]); + FREE(cinfo->ac_huff_tbl_ptrs[i]); + } + + /* My, that was easy, wasn't it? */ +} diff --git a/jdmcu.c b/jdmcu.c new file mode 100644 index 0000000..0d99170 --- /dev/null +++ b/jdmcu.c @@ -0,0 +1,146 @@ +/* + * jdmcu.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains MCU disassembly routines and quantization descaling. + * These routines are invoked via the disassemble_MCU and + * disassemble_init/term methods. + */ + +#include "jinclude.h" + + +/* + * Quantization descaling and zigzag reordering + */ + + +/* ZAG[i] is the natural-order position of the i'th element of zigzag order. */ + +static const short ZAG[DCTSIZE2] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + + +LOCAL void +qdescale_zig (JBLOCK input, JBLOCKROW outputptr, QUANT_TBL_PTR quanttbl) +{ + short i; + + for (i = 0; i < DCTSIZE2; i++) { + (*outputptr)[ZAG[i]] = (*input++) * (*quanttbl++); + } +} + + + +/* + * Fetch one MCU row from entropy_decode, build coefficient array. + * This version is used for noninterleaved (single-component) scans. + */ + +METHODDEF void +disassemble_noninterleaved_MCU (decompress_info_ptr cinfo, + JBLOCKIMAGE image_data) +{ + JBLOCK MCU_data[1]; + long mcuindex; + jpeg_component_info * compptr; + QUANT_TBL_PTR quant_ptr; + + /* this is pretty easy since there is one component and one block per MCU */ + compptr = cinfo->cur_comp_info[0]; + quant_ptr = cinfo->quant_tbl_ptrs[compptr->quant_tbl_no]; + for (mcuindex = 0; mcuindex < cinfo->MCUs_per_row; mcuindex++) { + /* Fetch the coefficient data */ + (*cinfo->methods->entropy_decode) (cinfo, MCU_data); + /* Descale, reorder, and distribute it into the image array */ + qdescale_zig(MCU_data[0], image_data[0][0] + mcuindex, quant_ptr); + } +} + + +/* + * Fetch one MCU row from entropy_decode, build coefficient array. + * This version is used for interleaved (multi-component) scans. + */ + +METHODDEF void +disassemble_interleaved_MCU (decompress_info_ptr cinfo, + JBLOCKIMAGE image_data) +{ + JBLOCK MCU_data[MAX_BLOCKS_IN_MCU]; + long mcuindex; + short blkn, ci, xpos, ypos; + jpeg_component_info * compptr; + QUANT_TBL_PTR quant_ptr; + JBLOCKROW image_ptr; + + for (mcuindex = 0; mcuindex < cinfo->MCUs_per_row; mcuindex++) { + /* Fetch the coefficient data */ + (*cinfo->methods->entropy_decode) (cinfo, MCU_data); + /* Descale, reorder, and distribute it into the image array */ + blkn = 0; + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + quant_ptr = cinfo->quant_tbl_ptrs[compptr->quant_tbl_no]; + for (ypos = 0; ypos < compptr->MCU_height; ypos++) { + image_ptr = image_data[ci][ypos] + (mcuindex * compptr->MCU_width); + for (xpos = 0; xpos < compptr->MCU_width; xpos++) { + qdescale_zig(MCU_data[blkn], image_ptr, quant_ptr); + image_ptr++; + blkn++; + } + } + } + } +} + + +/* + * Initialize for processing a scan. + */ + +METHODDEF void +disassemble_init (decompress_info_ptr cinfo) +{ + /* no work for now */ +} + + +/* + * Clean up after a scan. + */ + +METHODDEF void +disassemble_term (decompress_info_ptr cinfo) +{ + /* no work for now */ +} + + + +/* + * The method selection routine for MCU disassembly. + */ + +GLOBAL void +jseldmcu (decompress_info_ptr cinfo) +{ + if (cinfo->comps_in_scan == 1) + cinfo->methods->disassemble_MCU = disassemble_noninterleaved_MCU; + else + cinfo->methods->disassemble_MCU = disassemble_interleaved_MCU; + cinfo->methods->disassemble_init = disassemble_init; + cinfo->methods->disassemble_term = disassemble_term; +} diff --git a/jdpipe.c b/jdpipe.c new file mode 100644 index 0000000..8e08874 --- /dev/null +++ b/jdpipe.c @@ -0,0 +1,1309 @@ +/* + * jdpipe.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains decompression pipeline controllers. + * These routines are invoked via the d_pipeline_controller method. + * + * There are four basic pipeline controllers, one for each combination of: + * single-scan JPEG file (single component or fully interleaved) + * vs. multiple-scan JPEG file (noninterleaved or partially interleaved). + * + * 2-pass color quantization + * vs. no color quantization or 1-pass quantization. + * + * Note that these conditions determine the needs for "big" images: + * multiple scans imply a big image for recombining the color components; + * 2-pass color quantization needs a big image for saving the data for pass 2. + * + * All but the simplest controller (single-scan, no 2-pass quantization) can be + * compiled out through configuration options, if you need to make a minimal + * implementation. You should leave in multiple-scan support if at all + * possible, so that you can handle all legal JPEG files. + */ + +#include "jinclude.h" + + +/* + * About the data structures: + * + * The processing chunk size for unsubsampling is referred to in this file as + * a "row group": a row group is defined as Vk (v_samp_factor) sample rows of + * any component while subsampled, or Vmax (max_v_samp_factor) unsubsampled + * rows. In an interleaved scan each MCU row contains exactly DCTSIZE row + * groups of each component in the scan. In a noninterleaved scan an MCU row + * is one row of blocks, which might not be an integral number of row groups; + * therefore, we read in Vk MCU rows to obtain the same amount of data as we'd + * have in an interleaved scan. + * To provide context for the unsubsampling step, we have to retain the last + * two row groups of the previous MCU row while reading in the next MCU row + * (or set of Vk MCU rows). To do this without copying data about, we create + * a rather strange data structure. Exactly DCTSIZE+2 row groups of samples + * are allocated, but we create two different sets of pointers to this array. + * The second set swaps the last two pairs of row groups. By working + * alternately with the two sets of pointers, we can access the data in the + * desired order. + * + * Cross-block smoothing also needs context above and below the "current" row. + * Since this is an optional feature, I've implemented it in a way that is + * much simpler but requires more than the minimum amount of memory. We + * simply allocate three extra MCU rows worth of coefficient blocks and use + * them to "read ahead" one MCU row in the file. For a typical 1000-pixel-wide + * image with 2x2,1x1,1x1 sampling, each MCU row is about 50Kb; an 80x86 + * machine may be unable to apply cross-block smoothing to wider images. + */ + + +/* + * These variables are logically local to the pipeline controller, + * but we make them static so that scan_big_image can use them + * without having to pass them through the quantization routines. + * If you don't support 2-pass quantization, you could make them locals. + */ + +static int rows_in_mem; /* # of sample rows in full-size buffers */ +/* Full-size image array holding desubsampled, color-converted data. */ +static big_sarray_ptr *fullsize_cnvt_image; +static JSAMPIMAGE fullsize_cnvt_ptrs; /* workspace for access_big_sarray() results */ +/* Work buffer for color quantization output (full size, only 1 component). */ +static JSAMPARRAY quantize_out; + + +/* + * Utility routines: common code for pipeline controllers + */ + +LOCAL void +interleaved_scan_setup (decompress_info_ptr cinfo) +/* Compute all derived info for an interleaved (multi-component) scan */ +/* On entry, cinfo->comps_in_scan and cinfo->cur_comp_info[] are set up */ +{ + short ci, mcublks; + jpeg_component_info *compptr; + + if (cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT(cinfo->emethods, "Too many components for interleaved scan"); + + cinfo->MCUs_per_row = (cinfo->image_width + + cinfo->max_h_samp_factor*DCTSIZE - 1) + / (cinfo->max_h_samp_factor*DCTSIZE); + + cinfo->MCU_rows_in_scan = (cinfo->image_height + + cinfo->max_v_samp_factor*DCTSIZE - 1) + / (cinfo->max_v_samp_factor*DCTSIZE); + + cinfo->blocks_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* for interleaved scan, sampling factors give # of blocks per component */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; + /* compute physical dimensions of component */ + compptr->subsampled_width = jround_up(compptr->true_comp_width, + (long) (compptr->MCU_width*DCTSIZE)); + compptr->subsampled_height = jround_up(compptr->true_comp_height, + (long) (compptr->MCU_height*DCTSIZE)); + /* Sanity check */ + if (compptr->subsampled_width != + (cinfo->MCUs_per_row * (compptr->MCU_width*DCTSIZE))) + ERREXIT(cinfo->emethods, "I'm confused about the image width"); + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_blocks; + if (cinfo->blocks_in_MCU + mcublks > MAX_BLOCKS_IN_MCU) + ERREXIT(cinfo->emethods, "Sampling factors too large for interleaved scan"); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; + } + } + + (*cinfo->methods->d_per_scan_method_selection) (cinfo); +} + + +LOCAL void +noninterleaved_scan_setup (decompress_info_ptr cinfo) +/* Compute all derived info for a noninterleaved (single-component) scan */ +/* On entry, cinfo->comps_in_scan = 1 and cinfo->cur_comp_info[0] is set up */ +{ + jpeg_component_info *compptr = cinfo->cur_comp_info[0]; + + /* for noninterleaved scan, always one block per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_blocks = 1; + /* compute physical dimensions of component */ + compptr->subsampled_width = jround_up(compptr->true_comp_width, + (long) DCTSIZE); + compptr->subsampled_height = jround_up(compptr->true_comp_height, + (long) DCTSIZE); + + cinfo->MCUs_per_row = compptr->subsampled_width / DCTSIZE; + cinfo->MCU_rows_in_scan = compptr->subsampled_height / DCTSIZE; + + /* Prepare array describing MCU composition */ + cinfo->blocks_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + (*cinfo->methods->d_per_scan_method_selection) (cinfo); +} + + +LOCAL void +reverse_DCT (decompress_info_ptr cinfo, + JBLOCKIMAGE coeff_data, JSAMPIMAGE output_data, + int start_row) +/* Perform inverse DCT on each block in an MCU row's worth of data; */ +/* output the results into a sample array starting at row start_row. */ +/* NB: start_row can only be nonzero when dealing with a single-component */ +/* scan; otherwise we'd have to provide for different offsets for different */ +/* components, since the heights of interleaved MCU rows can vary. */ +{ + DCTBLOCK block; + JBLOCKROW browptr; + JSAMPARRAY srowptr; + long blocksperrow, bi; + short numrows, ri; + short ci; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + /* calc size of an MCU row in this component */ + blocksperrow = cinfo->cur_comp_info[ci]->subsampled_width / DCTSIZE; + numrows = cinfo->cur_comp_info[ci]->MCU_height; + /* iterate through all blocks in MCU row */ + for (ri = 0; ri < numrows; ri++) { + browptr = coeff_data[ci][ri]; + srowptr = output_data[ci] + (ri * DCTSIZE + start_row); + for (bi = 0; bi < blocksperrow; bi++) { + /* copy the data into a local DCTBLOCK. This allows for change of + * representation (if DCTELEM != JCOEF). On 80x86 machines it also + * brings the data back from FAR storage to NEAR storage. + */ + { register JCOEFPTR elemptr = browptr[bi]; + register DCTELEM *localblkptr = block; + register short elem = DCTSIZE2; + + while (--elem >= 0) + *localblkptr++ = (DCTELEM) *elemptr++; + } + + j_rev_dct(block); /* perform inverse DCT */ + + /* output the data into the sample array. + * Note change from signed to unsigned representation: + * DCT calculation works with values +-CENTERJSAMPLE, + * but sample arrays always hold 0..MAXJSAMPLE. + * Have to do explicit range-limiting because of quantization errors + * and so forth in the DCT/IDCT phase. + */ + { register JSAMPROW elemptr; + register DCTELEM *localblkptr = block; + register short elemr, elemc; + register DCTELEM temp; + + for (elemr = 0; elemr < DCTSIZE; elemr++) { + elemptr = srowptr[elemr] + (bi * DCTSIZE); + for (elemc = 0; elemc < DCTSIZE; elemc++) { + temp = (*localblkptr++) + CENTERJSAMPLE; + if (temp < 0) temp = 0; + else if (temp > MAXJSAMPLE) temp = MAXJSAMPLE; + *elemptr++ = (JSAMPLE) temp; + } + } + } + } + } + } +} + + + +LOCAL JSAMPIMAGE +alloc_sampimage (decompress_info_ptr cinfo, + int num_comps, long num_rows, long num_cols) +/* Allocate an in-memory sample image (all components same size) */ +{ + JSAMPIMAGE image; + int ci; + + image = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (num_comps * SIZEOF(JSAMPARRAY)); + for (ci = 0; ci < num_comps; ci++) { + image[ci] = (*cinfo->emethods->alloc_small_sarray) (num_cols, num_rows); + } + return image; +} + + +LOCAL void +free_sampimage (decompress_info_ptr cinfo, JSAMPIMAGE image, + int num_comps, long num_rows) +/* Release a sample image created by alloc_sampimage */ +{ + int ci; + + for (ci = 0; ci < num_comps; ci++) { + (*cinfo->emethods->free_small_sarray) (image[ci], num_rows); + } + (*cinfo->emethods->free_small) ((void *) image); +} + + +LOCAL JBLOCKIMAGE +alloc_MCU_row (decompress_info_ptr cinfo) +/* Allocate one MCU row's worth of coefficient blocks */ +{ + JBLOCKIMAGE image; + int ci; + + image = (JBLOCKIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->comps_in_scan * SIZEOF(JBLOCKARRAY)); + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + image[ci] = (*cinfo->emethods->alloc_small_barray) + (cinfo->cur_comp_info[ci]->subsampled_width / DCTSIZE, + (long) cinfo->cur_comp_info[ci]->MCU_height); + } + return image; +} + + +LOCAL void +free_MCU_row (decompress_info_ptr cinfo, JBLOCKIMAGE image) +/* Release a coefficient block array created by alloc_MCU_row */ +{ + int ci; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + (*cinfo->emethods->free_small_barray) + (image[ci], (long) cinfo->cur_comp_info[ci]->MCU_height); + } + (*cinfo->emethods->free_small) ((void *) image); +} + + +LOCAL void +alloc_sampling_buffer (decompress_info_ptr cinfo, JSAMPIMAGE subsampled_data[2]) +/* Create a subsampled-data buffer having the desired structure */ +/* (see comments at head of file) */ +{ + short ci, vs, i; + + /* Get top-level space for array pointers */ + subsampled_data[0] = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->comps_in_scan * SIZEOF(JSAMPARRAY)); + subsampled_data[1] = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->comps_in_scan * SIZEOF(JSAMPARRAY)); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + vs = cinfo->cur_comp_info[ci]->v_samp_factor; /* row group height */ + /* Allocate the real storage */ + subsampled_data[0][ci] = (*cinfo->emethods->alloc_small_sarray) + (cinfo->cur_comp_info[ci]->subsampled_width, + (long) (vs * (DCTSIZE+2))); + /* Create space for the scrambled-order pointers */ + subsampled_data[1][ci] = (JSAMPARRAY) (*cinfo->emethods->alloc_small) + (vs * (DCTSIZE+2) * SIZEOF(JSAMPROW)); + /* Duplicate the first DCTSIZE-2 row groups */ + for (i = 0; i < vs * (DCTSIZE-2); i++) { + subsampled_data[1][ci][i] = subsampled_data[0][ci][i]; + } + /* Copy the last four row groups in swapped order */ + for (i = 0; i < vs * 2; i++) { + subsampled_data[1][ci][vs*DCTSIZE + i] = subsampled_data[0][ci][vs*(DCTSIZE-2) + i]; + subsampled_data[1][ci][vs*(DCTSIZE-2) + i] = subsampled_data[0][ci][vs*DCTSIZE + i]; + } + } +} + + +LOCAL void +free_sampling_buffer (decompress_info_ptr cinfo, JSAMPIMAGE subsampled_data[2]) +/* Release a sampling buffer created by alloc_sampling_buffer */ +{ + short ci, vs; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + vs = cinfo->cur_comp_info[ci]->v_samp_factor; /* row group height */ + /* Free the real storage */ + (*cinfo->emethods->free_small_sarray) + (subsampled_data[0][ci], (long) (vs * (DCTSIZE+2))); + /* Free the scrambled-order pointers */ + (*cinfo->emethods->free_small) ((void *) subsampled_data[1][ci]); + } + + /* Free the top-level space */ + (*cinfo->emethods->free_small) ((void *) subsampled_data[0]); + (*cinfo->emethods->free_small) ((void *) subsampled_data[1]); +} + + +LOCAL void +duplicate_row (JSAMPARRAY image_data, + long num_cols, int source_row, int num_rows) +/* Duplicate the source_row at source_row+1 .. source_row+num_rows */ +/* This happens only at the bottom of the image, */ +/* so it needn't be super-efficient */ +{ + register int row; + + for (row = 1; row <= num_rows; row++) { + jcopy_sample_rows(image_data, source_row, image_data, source_row + row, + 1, num_cols); + } +} + + +LOCAL void +expand (decompress_info_ptr cinfo, + JSAMPIMAGE subsampled_data, JSAMPIMAGE fullsize_data, + long fullsize_width, + short above, short current, short below, short out) +/* Do unsubsampling expansion of a single row group (of each component). */ +/* above, current, below are indexes of row groups in subsampled_data; */ +/* out is the index of the target row group in fullsize_data. */ +/* Special case: above, below can be -1 to indicate top, bottom of image. */ +{ + jpeg_component_info *compptr; + JSAMPARRAY above_ptr, below_ptr; + JSAMPROW dummy[MAX_SAMP_FACTOR]; /* for subsample expansion at top/bottom */ + short ci, vs, i; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + vs = compptr->v_samp_factor; /* row group height */ + + if (above >= 0) + above_ptr = subsampled_data[ci] + above * vs; + else { + /* Top of image: make a dummy above-context with copies of 1st row */ + /* We assume current=0 in this case */ + for (i = 0; i < vs; i++) + dummy[i] = subsampled_data[ci][0]; + above_ptr = (JSAMPARRAY) dummy; /* possible near->far pointer conv */ + } + + if (below >= 0) + below_ptr = subsampled_data[ci] + below * vs; + else { + /* Bot of image: make a dummy below-context with copies of last row */ + for (i = 0; i < vs; i++) + dummy[i] = subsampled_data[ci][(current+1)*vs-1]; + below_ptr = (JSAMPARRAY) dummy; /* possible near->far pointer conv */ + } + + (*cinfo->methods->unsubsample[ci]) + (cinfo, (int) ci, + compptr->subsampled_width, (int) vs, + fullsize_width, (int) cinfo->max_v_samp_factor, + above_ptr, + subsampled_data[ci] + current * vs, + below_ptr, + fullsize_data[ci] + out * cinfo->max_v_samp_factor); + } +} + + +LOCAL void +emit_1pass (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE fullsize_data, JSAMPIMAGE color_data) +/* Do color conversion and output of num_rows full-size rows. */ +/* This is not used for 2-pass color quantization. */ +{ + (*cinfo->methods->color_convert) (cinfo, num_rows, + fullsize_data, color_data); + + if (cinfo->quantize_colors) { + (*cinfo->methods->color_quantize) (cinfo, num_rows, + color_data, quantize_out); + + (*cinfo->methods->put_pixel_rows) (cinfo, num_rows, + &quantize_out); + } else { + (*cinfo->methods->put_pixel_rows) (cinfo, num_rows, + color_data); + } +} + + +/* + * Support routines for 2-pass color quantization. + */ + +#ifdef QUANT_2PASS_SUPPORTED + +LOCAL void +emit_2pass (decompress_info_ptr cinfo, long top_row, int num_rows, + JSAMPIMAGE fullsize_data) +/* Do color conversion and output data to the quantization buffer image. */ +/* This is used only with 2-pass color quantization. */ +{ + short ci; + + /* Realign the big buffers */ + for (ci = 0; ci < cinfo->num_components; ci++) { + fullsize_cnvt_ptrs[ci] = (*cinfo->emethods->access_big_sarray) + (fullsize_cnvt_image[ci], top_row, TRUE); + } + + /* Do colorspace conversion */ + (*cinfo->methods->color_convert) (cinfo, num_rows, + fullsize_data, fullsize_cnvt_ptrs); + /* Let quantizer get first-pass peek at the data. */ + /* (Quantizer could change data if it wants to.) */ + (*cinfo->methods->color_quant_prescan) (cinfo, num_rows, fullsize_cnvt_ptrs); +} + + +METHODDEF void +scan_big_image (decompress_info_ptr cinfo, quantize_method_ptr quantize_method) +/* This is the "iterator" routine used by the quantizer. */ +{ + long pixel_rows_output; + short ci; + + for (pixel_rows_output = 0; pixel_rows_output < cinfo->image_height; + pixel_rows_output += rows_in_mem) { + /* Realign the big buffers */ + for (ci = 0; ci < cinfo->num_components; ci++) { + fullsize_cnvt_ptrs[ci] = (*cinfo->emethods->access_big_sarray) + (fullsize_cnvt_image[ci], pixel_rows_output, FALSE); + } + /* Let the quantizer have its way with the data. + * Note that quantize_out is simply workspace for the quantizer; + * when it's ready to output, it must call put_pixel_rows itself. + */ + (*quantize_method) (cinfo, + (int) MIN(rows_in_mem, + cinfo->image_height - pixel_rows_output), + fullsize_cnvt_ptrs, quantize_out); + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Support routines for cross-block smoothing. + */ + +#ifdef BLOCK_SMOOTHING_SUPPORTED + + +LOCAL void +smooth_mcu_row (decompress_info_ptr cinfo, + JBLOCKIMAGE above, JBLOCKIMAGE input, JBLOCKIMAGE below, + JBLOCKIMAGE output) +/* Apply cross-block smoothing to one MCU row's worth of coefficient blocks. */ +/* above,below are NULL if at top/bottom of image. */ +{ + jpeg_component_info *compptr; + short ci, ri, last; + JBLOCKROW prev; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + last = compptr->MCU_height - 1; + + if (above == NULL) + prev = NULL; + else + prev = above[ci][last]; + + for (ri = 0; ri < last; ri++) { + (*cinfo->methods->smooth_coefficients) (cinfo, compptr, + prev, input[ci][ri], input[ci][ri+1], + output[ci][ri]); + prev = input[ci][ri]; + } + + if (below == NULL) + (*cinfo->methods->smooth_coefficients) (cinfo, compptr, + prev, input[ci][last], (JBLOCKROW) NULL, + output[ci][last]); + else + (*cinfo->methods->smooth_coefficients) (cinfo, compptr, + prev, input[ci][last], below[ci][0], + output[ci][last]); + } +} + + +LOCAL void +get_smoothed_row (decompress_info_ptr cinfo, JBLOCKIMAGE coeff_data, + JBLOCKIMAGE bsmooth[3], int * whichb, long cur_mcu_row) +/* Get an MCU row of coefficients, applying cross-block smoothing. */ +/* The output row is placed in coeff_data. bsmooth and whichb hold */ +/* working state, and cur_row is needed to check for image top/bottom. */ +/* This routine just takes care of the buffering logic. */ +{ + int prev, cur, next; + + /* Special case for top of image: need to pre-fetch a row & init whichb */ + if (cur_mcu_row == 0) { + (*cinfo->methods->disassemble_MCU) (cinfo, bsmooth[0]); + if (cinfo->MCU_rows_in_scan > 1) { + (*cinfo->methods->disassemble_MCU) (cinfo, bsmooth[1]); + smooth_mcu_row(cinfo, (JBLOCKIMAGE) NULL, bsmooth[0], bsmooth[1], + coeff_data); + } else { + smooth_mcu_row(cinfo, (JBLOCKIMAGE) NULL, bsmooth[0], (JBLOCKIMAGE) NULL, + coeff_data); + } + *whichb = 1; /* points to next bsmooth[] element to use */ + return; + } + + cur = *whichb; /* set up references */ + prev = (cur == 0 ? 2 : cur - 1); + next = (cur == 2 ? 0 : cur + 1); + *whichb = next; /* advance whichb for next time */ + + /* Special case for bottom of image: don't read another row */ + if (cur_mcu_row >= cinfo->MCU_rows_in_scan - 1) { + smooth_mcu_row(cinfo, bsmooth[prev], bsmooth[cur], (JBLOCKIMAGE) NULL, + coeff_data); + return; + } + + /* Normal case: read ahead a new row, smooth the one I got before */ + (*cinfo->methods->disassemble_MCU) (cinfo, bsmooth[next]); + smooth_mcu_row(cinfo, bsmooth[prev], bsmooth[cur], bsmooth[next], + coeff_data); +} + + +#endif /* BLOCK_SMOOTHING_SUPPORTED */ + + + +/* + * Decompression pipeline controller used for single-scan files + * without 2-pass color quantization. + */ + +METHODDEF void +single_dcontroller (decompress_info_ptr cinfo) +{ + long fullsize_width; /* # of samples per row in full-size buffers */ + long cur_mcu_row; /* counts # of MCU rows processed */ + long pixel_rows_output; /* # of pixel rows actually emitted */ + int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */ + /* Work buffer for dequantized coefficients (IDCT input) */ + JBLOCKIMAGE coeff_data; + /* Work buffer for cross-block smoothing input */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + JBLOCKIMAGE bsmooth[3]; /* this is optional */ + int whichb; +#endif + /* Work buffer for subsampled image data (see comments at head of file) */ + JSAMPIMAGE subsampled_data[2]; + /* Work buffer for desubsampled data */ + JSAMPIMAGE fullsize_data; + /* Work buffer for color conversion output (full size) */ + JSAMPIMAGE color_data; + int whichss, ri; + short i; + + /* Initialize for 1-pass color quantization, if needed */ + if (cinfo->quantize_colors) + (*cinfo->methods->color_quant_init) (cinfo); + + /* Prepare for single scan containing all components */ + if (cinfo->comps_in_scan == 1) { + noninterleaved_scan_setup(cinfo); + /* Need to read Vk MCU rows to obtain Vk block rows */ + mcu_rows_per_loop = cinfo->cur_comp_info[0]->v_samp_factor; + } else { + interleaved_scan_setup(cinfo); + /* in an interleaved scan, one MCU row provides Vk block rows */ + mcu_rows_per_loop = 1; + } + + /* Compute dimensions of full-size pixel buffers */ + /* Note these are the same whether interleaved or not. */ + rows_in_mem = cinfo->max_v_samp_factor * DCTSIZE; + fullsize_width = jround_up(cinfo->image_width, + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + + /* Allocate working memory: */ + /* coeff_data holds a single MCU row of coefficient blocks */ + coeff_data = alloc_MCU_row(cinfo); + /* if doing cross-block smoothing, need extra space for its input */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) { + bsmooth[0] = alloc_MCU_row(cinfo); + bsmooth[1] = alloc_MCU_row(cinfo); + bsmooth[2] = alloc_MCU_row(cinfo); + } +#endif + /* subsampled_data is sample data before unsubsampling */ + alloc_sampling_buffer(cinfo, subsampled_data); + /* fullsize_data is sample data after unsubsampling */ + fullsize_data = alloc_sampimage(cinfo, (int) cinfo->num_components, + (long) rows_in_mem, fullsize_width); + /* color_data is the result of the colorspace conversion step */ + color_data = alloc_sampimage(cinfo, (int) cinfo->color_out_comps, + (long) rows_in_mem, fullsize_width); + /* if quantizing colors, also need a one-component output area for that. */ + if (cinfo->quantize_colors) + quantize_out = (*cinfo->emethods->alloc_small_sarray) + (fullsize_width, (long) rows_in_mem); + + /* Tell the memory manager to instantiate big arrays. + * We don't need any big arrays in this controller, + * but some other module (like the output file writer) may need one. + */ + (*cinfo->emethods->alloc_big_arrays) + ((long) 0, /* no more small sarrays */ + (long) 0, /* no more small barrays */ + (long) 0); /* no more "medium" objects */ + /* NB: quantizer must get any such objects at color_quant_init time */ + + /* Initialize to read scan data */ + + (*cinfo->methods->entropy_decoder_init) (cinfo); + (*cinfo->methods->unsubsample_init) (cinfo); + (*cinfo->methods->disassemble_init) (cinfo); + + /* Loop over scan's data: rows_in_mem pixel rows are processed per loop */ + + pixel_rows_output = 0; + whichss = 1; /* arrange to start with subsampled_data[0] */ + + for (cur_mcu_row = 0; cur_mcu_row < cinfo->MCU_rows_in_scan; + cur_mcu_row += mcu_rows_per_loop) { + whichss ^= 1; /* switch to other subsample buffer */ + + /* Obtain v_samp_factor block rows of each component in the scan. */ + /* This is a single MCU row if interleaved, multiple MCU rows if not. */ + /* In the noninterleaved case there might be fewer than v_samp_factor */ + /* block rows remaining; if so, pad with copies of the last pixel row */ + /* so that unsubsampling doesn't have to treat it as a special case. */ + + for (ri = 0; ri < mcu_rows_per_loop; ri++) { + if (cur_mcu_row + ri < cinfo->MCU_rows_in_scan) { + /* OK to actually read an MCU row. */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) + get_smoothed_row(cinfo, coeff_data, + bsmooth, &whichb, cur_mcu_row + ri); + else +#endif + (*cinfo->methods->disassemble_MCU) (cinfo, coeff_data); + + reverse_DCT(cinfo, coeff_data, subsampled_data[whichss], + ri * DCTSIZE); + } else { + /* Need to pad out with copies of the last subsampled row. */ + /* This can only happen if there is just one component. */ + duplicate_row(subsampled_data[whichss][0], + cinfo->cur_comp_info[0]->subsampled_width, + ri * DCTSIZE - 1, DCTSIZE); + } + } + + /* Unsubsample the data */ + /* First time through is a special case */ + + if (cur_mcu_row) { + /* Expand last row group of previous set */ + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) DCTSIZE, (short) (DCTSIZE+1), (short) 0, + (short) (DCTSIZE-1)); + /* and dump the previous set's expanded data */ + emit_1pass (cinfo, rows_in_mem, fullsize_data, color_data); + pixel_rows_output += rows_in_mem; + /* Expand first row group of this set */ + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) (DCTSIZE+1), (short) 0, (short) 1, + (short) 0); + } else { + /* Expand first row group with dummy above-context */ + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) (-1), (short) 0, (short) 1, + (short) 0); + } + /* Expand second through next-to-last row groups of this set */ + for (i = 1; i <= DCTSIZE-2; i++) { + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) (i-1), (short) i, (short) (i+1), + (short) i); + } + } /* end of outer loop */ + + /* Expand the last row group with dummy below-context */ + /* Note whichss points to last buffer side used */ + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1), + (short) (DCTSIZE-1)); + /* and dump the remaining data (may be less than full height) */ + emit_1pass (cinfo, (int) (cinfo->image_height - pixel_rows_output), + fullsize_data, color_data); + + /* Clean up after the scan */ + (*cinfo->methods->disassemble_term) (cinfo); + (*cinfo->methods->unsubsample_term) (cinfo); + (*cinfo->methods->entropy_decoder_term) (cinfo); + (*cinfo->methods->read_scan_trailer) (cinfo); + + /* Verify that we've seen the whole input file */ + if ((*cinfo->methods->read_scan_header) (cinfo)) + ERREXIT(cinfo->emethods, "Didn't expect more than one scan"); + + /* Release working memory */ + free_MCU_row(cinfo, coeff_data); +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) { + free_MCU_row(cinfo, bsmooth[0]); + free_MCU_row(cinfo, bsmooth[1]); + free_MCU_row(cinfo, bsmooth[2]); + } +#endif + free_sampling_buffer(cinfo, subsampled_data); + free_sampimage(cinfo, fullsize_data, (int) cinfo->num_components, + (long) rows_in_mem); + free_sampimage(cinfo, color_data, (int) cinfo->color_out_comps, + (long) rows_in_mem); + if (cinfo->quantize_colors) + (*cinfo->emethods->free_small_sarray) + (quantize_out, (long) rows_in_mem); + + /* Close up shop */ + if (cinfo->quantize_colors) + (*cinfo->methods->color_quant_term) (cinfo); +} + + +/* + * Decompression pipeline controller used for single-scan files + * with 2-pass color quantization. + */ + +#ifdef QUANT_2PASS_SUPPORTED + +METHODDEF void +single_2quant_dcontroller (decompress_info_ptr cinfo) +{ + long fullsize_width; /* # of samples per row in full-size buffers */ + long cur_mcu_row; /* counts # of MCU rows processed */ + long pixel_rows_output; /* # of pixel rows actually emitted */ + int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */ + /* Work buffer for dequantized coefficients (IDCT input) */ + JBLOCKIMAGE coeff_data; + /* Work buffer for cross-block smoothing input */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + JBLOCKIMAGE bsmooth[3]; /* this is optional */ + int whichb; +#endif + /* Work buffer for subsampled image data (see comments at head of file) */ + JSAMPIMAGE subsampled_data[2]; + /* Work buffer for desubsampled data */ + JSAMPIMAGE fullsize_data; + int whichss, ri; + short ci, i; + + /* Initialize for 2-pass color quantization */ + (*cinfo->methods->color_quant_init) (cinfo); + + /* Prepare for single scan containing all components */ + if (cinfo->comps_in_scan == 1) { + noninterleaved_scan_setup(cinfo); + /* Need to read Vk MCU rows to obtain Vk block rows */ + mcu_rows_per_loop = cinfo->cur_comp_info[0]->v_samp_factor; + } else { + interleaved_scan_setup(cinfo); + /* in an interleaved scan, one MCU row provides Vk block rows */ + mcu_rows_per_loop = 1; + } + + /* Compute dimensions of full-size pixel buffers */ + /* Note these are the same whether interleaved or not. */ + rows_in_mem = cinfo->max_v_samp_factor * DCTSIZE; + fullsize_width = jround_up(cinfo->image_width, + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + + /* Allocate working memory: */ + /* coeff_data holds a single MCU row of coefficient blocks */ + coeff_data = alloc_MCU_row(cinfo); + /* if doing cross-block smoothing, need extra space for its input */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) { + bsmooth[0] = alloc_MCU_row(cinfo); + bsmooth[1] = alloc_MCU_row(cinfo); + bsmooth[2] = alloc_MCU_row(cinfo); + } +#endif + /* subsampled_data is sample data before unsubsampling */ + alloc_sampling_buffer(cinfo, subsampled_data); + /* fullsize_data is sample data after unsubsampling */ + fullsize_data = alloc_sampimage(cinfo, (int) cinfo->num_components, + (long) rows_in_mem, fullsize_width); + /* Also need a one-component output area for color quantizer. */ + quantize_out = (*cinfo->emethods->alloc_small_sarray) + (fullsize_width, (long) rows_in_mem); + + /* Get a big image for quantizer input: desubsampled, color-converted data */ + fullsize_cnvt_image = (big_sarray_ptr *) (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(big_sarray_ptr)); + for (ci = 0; ci < cinfo->num_components; ci++) { + fullsize_cnvt_image[ci] = (*cinfo->emethods->request_big_sarray) + (fullsize_width, + jround_up(cinfo->image_height, (long) rows_in_mem), + (long) rows_in_mem); + } + /* Also get an area for pointers to currently accessible chunks */ + fullsize_cnvt_ptrs = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(JSAMPARRAY)); + + /* Tell the memory manager to instantiate big arrays */ + (*cinfo->emethods->alloc_big_arrays) + ((long) 0, /* no more small sarrays */ + (long) 0, /* no more small barrays */ + (long) 0); /* no more "medium" objects */ + /* NB: quantizer must get any such objects at color_quant_init time */ + + /* Initialize to read scan data */ + + (*cinfo->methods->entropy_decoder_init) (cinfo); + (*cinfo->methods->unsubsample_init) (cinfo); + (*cinfo->methods->disassemble_init) (cinfo); + + /* Loop over scan's data: rows_in_mem pixel rows are processed per loop */ + + pixel_rows_output = 0; + whichss = 1; /* arrange to start with subsampled_data[0] */ + + for (cur_mcu_row = 0; cur_mcu_row < cinfo->MCU_rows_in_scan; + cur_mcu_row += mcu_rows_per_loop) { + whichss ^= 1; /* switch to other subsample buffer */ + + /* Obtain v_samp_factor block rows of each component in the scan. */ + /* This is a single MCU row if interleaved, multiple MCU rows if not. */ + /* In the noninterleaved case there might be fewer than v_samp_factor */ + /* block rows remaining; if so, pad with copies of the last pixel row */ + /* so that unsubsampling doesn't have to treat it as a special case. */ + + for (ri = 0; ri < mcu_rows_per_loop; ri++) { + if (cur_mcu_row + ri < cinfo->MCU_rows_in_scan) { + /* OK to actually read an MCU row. */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) + get_smoothed_row(cinfo, coeff_data, + bsmooth, &whichb, cur_mcu_row + ri); + else +#endif + (*cinfo->methods->disassemble_MCU) (cinfo, coeff_data); + + reverse_DCT(cinfo, coeff_data, subsampled_data[whichss], + ri * DCTSIZE); + } else { + /* Need to pad out with copies of the last subsampled row. */ + /* This can only happen if there is just one component. */ + duplicate_row(subsampled_data[whichss][0], + cinfo->cur_comp_info[0]->subsampled_width, + ri * DCTSIZE - 1, DCTSIZE); + } + } + + /* Unsubsample the data */ + /* First time through is a special case */ + + if (cur_mcu_row) { + /* Expand last row group of previous set */ + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) DCTSIZE, (short) (DCTSIZE+1), (short) 0, + (short) (DCTSIZE-1)); + /* and dump the previous set's expanded data */ + emit_2pass (cinfo, pixel_rows_output, rows_in_mem, fullsize_data); + pixel_rows_output += rows_in_mem; + /* Expand first row group of this set */ + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) (DCTSIZE+1), (short) 0, (short) 1, + (short) 0); + } else { + /* Expand first row group with dummy above-context */ + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) (-1), (short) 0, (short) 1, + (short) 0); + } + /* Expand second through next-to-last row groups of this set */ + for (i = 1; i <= DCTSIZE-2; i++) { + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) (i-1), (short) i, (short) (i+1), + (short) i); + } + } /* end of outer loop */ + + /* Expand the last row group with dummy below-context */ + /* Note whichss points to last buffer side used */ + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1), + (short) (DCTSIZE-1)); + /* and dump the remaining data (may be less than full height) */ + emit_2pass (cinfo, pixel_rows_output, + (int) (cinfo->image_height - pixel_rows_output), + fullsize_data); + + /* Clean up after the scan */ + (*cinfo->methods->disassemble_term) (cinfo); + (*cinfo->methods->unsubsample_term) (cinfo); + (*cinfo->methods->entropy_decoder_term) (cinfo); + (*cinfo->methods->read_scan_trailer) (cinfo); + + /* Verify that we've seen the whole input file */ + if ((*cinfo->methods->read_scan_header) (cinfo)) + ERREXIT(cinfo->emethods, "Didn't expect more than one scan"); + + /* Now that we've collected the data, let the color quantizer do its thing */ + (*cinfo->methods->color_quant_doit) (cinfo, scan_big_image); + + /* Release working memory */ + free_MCU_row(cinfo, coeff_data); +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) { + free_MCU_row(cinfo, bsmooth[0]); + free_MCU_row(cinfo, bsmooth[1]); + free_MCU_row(cinfo, bsmooth[2]); + } +#endif + free_sampling_buffer(cinfo, subsampled_data); + free_sampimage(cinfo, fullsize_data, (int) cinfo->num_components, + (long) rows_in_mem); + (*cinfo->emethods->free_small_sarray) + (quantize_out, (long) rows_in_mem); + for (ci = 0; ci < cinfo->num_components; ci++) { + (*cinfo->emethods->free_big_sarray) (fullsize_cnvt_image[ci]); + } + (*cinfo->emethods->free_small) ((void *) fullsize_cnvt_image); + (*cinfo->emethods->free_small) ((void *) fullsize_cnvt_ptrs); + + /* Close up shop */ + (*cinfo->methods->color_quant_term) (cinfo); +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Decompression pipeline controller used for multiple-scan files + * without 2-pass color quantization. + * + * The current implementation places the "big" buffer at the stage of + * desubsampled data. Buffering subsampled data instead would reduce the + * size of temp files (by about a factor of 2 in typical cases). However, + * the unsubsampling logic is dependent on the assumption that unsubsampling + * occurs during a scan, so it's much easier to do the enlargement as the + * JPEG file is read. This also simplifies life for the memory manager, + * which would otherwise have to deal with overlapping access_big_sarray() + * requests. + * + * At present it appears that most JPEG files will be single-scan, so + * it doesn't seem worthwhile to try to make this implementation smarter. + */ + +#ifdef MULTISCAN_FILES_SUPPORTED + +METHODDEF void +multi_dcontroller (decompress_info_ptr cinfo) +{ + long fullsize_width; /* # of samples per row in full-size buffers */ + long cur_mcu_row; /* counts # of MCU rows processed */ + long pixel_rows_output; /* # of pixel rows actually emitted */ + int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */ + /* Work buffer for dequantized coefficients (IDCT input) */ + JBLOCKIMAGE coeff_data; + /* Work buffer for cross-block smoothing input */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + JBLOCKIMAGE bsmooth[3]; /* this is optional */ + int whichb; +#endif + /* Work buffer for subsampled image data (see comments at head of file) */ + JSAMPIMAGE subsampled_data[2]; + /* Full-image buffer holding desubsampled, but not color-converted, data */ + big_sarray_ptr *fullsize_image; + JSAMPIMAGE fullsize_ptrs; /* workspace for access_big_sarray() results */ + /* Work buffer for color conversion output (full size) */ + JSAMPIMAGE color_data; + int whichss, ri; + short ci, i; + + /* Initialize for 1-pass color quantization, if needed */ + if (cinfo->quantize_colors) + (*cinfo->methods->color_quant_init) (cinfo); + + /* Compute dimensions of full-size pixel buffers */ + /* Note these are the same whether interleaved or not. */ + rows_in_mem = cinfo->max_v_samp_factor * DCTSIZE; + fullsize_width = jround_up(cinfo->image_width, + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + + /* Allocate all working memory that doesn't depend on scan info */ + /* color_data is the result of the colorspace conversion step */ + color_data = alloc_sampimage(cinfo, (int) cinfo->color_out_comps, + (long) rows_in_mem, fullsize_width); + /* if quantizing colors, also need a one-component output area for that. */ + if (cinfo->quantize_colors) + quantize_out = (*cinfo->emethods->alloc_small_sarray) + (fullsize_width, (long) rows_in_mem); + + /* Get a big image: fullsize_image is sample data after unsubsampling. */ + fullsize_image = (big_sarray_ptr *) (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(big_sarray_ptr)); + for (ci = 0; ci < cinfo->num_components; ci++) { + fullsize_image[ci] = (*cinfo->emethods->request_big_sarray) + (fullsize_width, + jround_up(cinfo->image_height, (long) rows_in_mem), + (long) rows_in_mem); + } + /* Also get an area for pointers to currently accessible chunks */ + fullsize_ptrs = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(JSAMPARRAY)); + + /* Tell the memory manager to instantiate big arrays */ + (*cinfo->emethods->alloc_big_arrays) + /* extra sarray space is for subsampled-data buffers: */ + ((long) (fullsize_width /* max width in samples */ + * cinfo->max_v_samp_factor*(DCTSIZE+2) /* max height */ + * cinfo->num_components), /* max components per scan */ + /* extra barray space is for MCU-row buffers: */ + (long) ((fullsize_width / DCTSIZE) /* max width in blocks */ + * cinfo->max_v_samp_factor /* max height */ + * cinfo->num_components /* max components per scan */ + * (cinfo->do_block_smoothing ? 4 : 1)),/* how many of these we need */ + /* no extra "medium"-object space */ + /* NB: quantizer must get any such objects at color_quant_init time */ + (long) 0); + + + /* Loop over scans in file */ + + do { + + /* Prepare for this scan */ + if (cinfo->comps_in_scan == 1) { + noninterleaved_scan_setup(cinfo); + /* Need to read Vk MCU rows to obtain Vk block rows */ + mcu_rows_per_loop = cinfo->cur_comp_info[0]->v_samp_factor; + } else { + interleaved_scan_setup(cinfo); + /* in an interleaved scan, one MCU row provides Vk block rows */ + mcu_rows_per_loop = 1; + } + + /* Allocate scan-local working memory */ + /* coeff_data holds a single MCU row of coefficient blocks */ + coeff_data = alloc_MCU_row(cinfo); + /* if doing cross-block smoothing, need extra space for its input */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) { + bsmooth[0] = alloc_MCU_row(cinfo); + bsmooth[1] = alloc_MCU_row(cinfo); + bsmooth[2] = alloc_MCU_row(cinfo); + } +#endif + /* subsampled_data is sample data before unsubsampling */ + alloc_sampling_buffer(cinfo, subsampled_data); + + /* line up the big buffers */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + fullsize_ptrs[ci] = (*cinfo->emethods->access_big_sarray) + (fullsize_image[cinfo->cur_comp_info[ci]->component_index], + (long) 0, TRUE); + } + + /* Initialize to read scan data */ + + (*cinfo->methods->entropy_decoder_init) (cinfo); + (*cinfo->methods->unsubsample_init) (cinfo); + (*cinfo->methods->disassemble_init) (cinfo); + + /* Loop over scan's data: rows_in_mem pixel rows are processed per loop */ + + pixel_rows_output = 0; + whichss = 1; /* arrange to start with subsampled_data[0] */ + + for (cur_mcu_row = 0; cur_mcu_row < cinfo->MCU_rows_in_scan; + cur_mcu_row += mcu_rows_per_loop) { + whichss ^= 1; /* switch to other subsample buffer */ + + /* Obtain v_samp_factor block rows of each component in the scan. */ + /* This is a single MCU row if interleaved, multiple MCU rows if not. */ + /* In the noninterleaved case there might be fewer than v_samp_factor */ + /* block rows remaining; if so, pad with copies of the last pixel row */ + /* so that unsubsampling doesn't have to treat it as a special case. */ + + for (ri = 0; ri < mcu_rows_per_loop; ri++) { + if (cur_mcu_row + ri < cinfo->MCU_rows_in_scan) { + /* OK to actually read an MCU row. */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) + get_smoothed_row(cinfo, coeff_data, + bsmooth, &whichb, cur_mcu_row + ri); + else +#endif + (*cinfo->methods->disassemble_MCU) (cinfo, coeff_data); + + reverse_DCT(cinfo, coeff_data, subsampled_data[whichss], + ri * DCTSIZE); + } else { + /* Need to pad out with copies of the last subsampled row. */ + /* This can only happen if there is just one component. */ + duplicate_row(subsampled_data[whichss][0], + cinfo->cur_comp_info[0]->subsampled_width, + ri * DCTSIZE - 1, DCTSIZE); + } + } + + /* Unsubsample the data */ + /* First time through is a special case */ + + if (cur_mcu_row) { + /* Expand last row group of previous set */ + expand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width, + (short) DCTSIZE, (short) (DCTSIZE+1), (short) 0, + (short) (DCTSIZE-1)); + /* Realign the big buffers */ + pixel_rows_output += rows_in_mem; + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + fullsize_ptrs[ci] = (*cinfo->emethods->access_big_sarray) + (fullsize_image[cinfo->cur_comp_info[ci]->component_index], + pixel_rows_output, TRUE); + } + /* Expand first row group of this set */ + expand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width, + (short) (DCTSIZE+1), (short) 0, (short) 1, + (short) 0); + } else { + /* Expand first row group with dummy above-context */ + expand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width, + (short) (-1), (short) 0, (short) 1, + (short) 0); + } + /* Expand second through next-to-last row groups of this set */ + for (i = 1; i <= DCTSIZE-2; i++) { + expand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width, + (short) (i-1), (short) i, (short) (i+1), + (short) i); + } + } /* end of outer loop */ + + /* Expand the last row group with dummy below-context */ + /* Note whichss points to last buffer side used */ + expand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width, + (short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1), + (short) (DCTSIZE-1)); + + /* Clean up after the scan */ + (*cinfo->methods->disassemble_term) (cinfo); + (*cinfo->methods->unsubsample_term) (cinfo); + (*cinfo->methods->entropy_decoder_term) (cinfo); + (*cinfo->methods->read_scan_trailer) (cinfo); + + /* Release scan-local working memory */ + free_MCU_row(cinfo, coeff_data); +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) { + free_MCU_row(cinfo, bsmooth[0]); + free_MCU_row(cinfo, bsmooth[1]); + free_MCU_row(cinfo, bsmooth[2]); + } +#endif + free_sampling_buffer(cinfo, subsampled_data); + + /* Repeat if there is another scan */ + } while ((*cinfo->methods->read_scan_header) (cinfo)); + + /* Now that we've collected all the data, color convert & output it. */ + + for (pixel_rows_output = 0; pixel_rows_output < cinfo->image_height; + pixel_rows_output += rows_in_mem) { + + /* realign the big buffers */ + for (ci = 0; ci < cinfo->num_components; ci++) { + fullsize_ptrs[ci] = (*cinfo->emethods->access_big_sarray) + (fullsize_image[ci], pixel_rows_output, FALSE); + } + + emit_1pass (cinfo, + (int) MIN(rows_in_mem, cinfo->image_height-pixel_rows_output), + fullsize_ptrs, color_data); + } + + /* Release working memory */ + free_sampimage(cinfo, color_data, (int) cinfo->color_out_comps, + (long) rows_in_mem); + if (cinfo->quantize_colors) + (*cinfo->emethods->free_small_sarray) + (quantize_out, (long) rows_in_mem); + for (ci = 0; ci < cinfo->num_components; ci++) { + (*cinfo->emethods->free_big_sarray) (fullsize_image[ci]); + } + (*cinfo->emethods->free_small) ((void *) fullsize_image); + (*cinfo->emethods->free_small) ((void *) fullsize_ptrs); + + /* Close up shop */ + if (cinfo->quantize_colors) + (*cinfo->methods->color_quant_term) (cinfo); +} + +#endif /* MULTISCAN_FILES_SUPPORTED */ + + +/* + * Decompression pipeline controller used for multiple-scan files + * with 2-pass color quantization. + */ + +#ifdef MULTISCAN_FILES_SUPPORTED +#ifdef QUANT_2PASS_SUPPORTED + +METHODDEF void +multi_2quant_dcontroller (decompress_info_ptr cinfo) +{ + ERREXIT(cinfo->emethods, "Not implemented yet"); +} + +#endif /* QUANT_2PASS_SUPPORTED */ +#endif /* MULTISCAN_FILES_SUPPORTED */ + + +/* + * The method selection routine for decompression pipeline controllers. + * Note that at this point we've already read the JPEG header and first SOS, + * so we can tell whether the input is one scan or not. + */ + +GLOBAL void +jseldpipeline (decompress_info_ptr cinfo) +{ + /* simplify subsequent tests on color quantization */ + if (! cinfo->quantize_colors) + cinfo->two_pass_quantize = FALSE; + + if (cinfo->comps_in_scan == cinfo->num_components) { + /* It's a single-scan file */ +#ifdef QUANT_2PASS_SUPPORTED + if (cinfo->two_pass_quantize) + cinfo->methods->d_pipeline_controller = single_2quant_dcontroller; + else +#endif + cinfo->methods->d_pipeline_controller = single_dcontroller; + } else { + /* It's a multiple-scan file */ +#ifdef MULTISCAN_FILES_SUPPORTED +#ifdef QUANT_2PASS_SUPPORTED + if (cinfo->two_pass_quantize) + cinfo->methods->d_pipeline_controller = multi_2quant_dcontroller; + else +#endif + cinfo->methods->d_pipeline_controller = multi_dcontroller; +#else + ERREXIT(cinfo->emethods, "Multiple-scan support was not compiled"); +#endif + } +} diff --git a/jdsample.c b/jdsample.c new file mode 100644 index 0000000..15dbf4f --- /dev/null +++ b/jdsample.c @@ -0,0 +1,133 @@ +/* + * jdsample.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains un-subsampling routines. + * These routines are invoked via the unsubsample and + * unsubsample_init/term methods. + */ + +#include "jinclude.h" + + +/* + * Initialize for un-subsampling a scan. + */ + +METHODDEF void +unsubsample_init (decompress_info_ptr cinfo) +{ + /* no work for now */ +} + + +/* + * Un-subsample pixel values of a single component. + * This version only handles integral sampling ratios. + */ + +METHODDEF void +unsubsample (decompress_info_ptr cinfo, int which_component, + long input_cols, int input_rows, + long output_cols, int output_rows, + JSAMPARRAY above, JSAMPARRAY input_data, JSAMPARRAY below, + JSAMPARRAY output_data) +{ + jpeg_component_info * compptr = cinfo->cur_comp_info[which_component]; + short h_expand, v_expand, h, v; + int inrow, outrow; + long incol; + JSAMPROW inptr, outptr; + JSAMPLE invalue; + + /* TEMP FOR DEBUGGING PIPELINE CONTROLLER */ + if (input_rows != compptr->v_samp_factor || + output_rows != cinfo->max_v_samp_factor || + (input_cols % compptr->h_samp_factor) != 0 || + (output_cols % cinfo->max_h_samp_factor) != 0 || + output_cols*compptr->h_samp_factor != input_cols*cinfo->max_h_samp_factor) + ERREXIT(cinfo->emethods, "Bogus unsubsample parameters"); + + h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor; + v_expand = cinfo->max_v_samp_factor / compptr->v_samp_factor; + + outrow = 0; + for (inrow = 0; inrow < input_rows; inrow++) { + for (v = 0; v < v_expand; v++) { + inptr = input_data[inrow]; + outptr = output_data[outrow++]; + for (incol = 0; incol < input_cols; incol++) { + invalue = GETJSAMPLE(*inptr++); + for (h = 0; h < h_expand; h++) { + *outptr++ = invalue; + } + } + } + } +} + + +/* + * Un-subsample pixel values of a single component. + * This version handles the special case of a full-size component. + */ + +METHODDEF void +fullsize_unsubsample (decompress_info_ptr cinfo, int which_component, + long input_cols, int input_rows, + long output_cols, int output_rows, + JSAMPARRAY above, JSAMPARRAY input_data, JSAMPARRAY below, + JSAMPARRAY output_data) +{ + if (input_cols != output_cols || input_rows != output_rows) /* DEBUG */ + ERREXIT(cinfo->emethods, "Pipeline controller messed up"); + + jcopy_sample_rows(input_data, 0, output_data, 0, output_rows, output_cols); +} + + + +/* + * Clean up after a scan. + */ + +METHODDEF void +unsubsample_term (decompress_info_ptr cinfo) +{ + /* no work for now */ +} + + + +/* + * The method selection routine for unsubsampling. + * Note that we must select a routine for each component. + */ + +GLOBAL void +jselunsubsample (decompress_info_ptr cinfo) +{ + short ci; + jpeg_component_info * compptr; + + if (cinfo->CCIR601_sampling) + ERREXIT(cinfo->emethods, "CCIR601 subsampling not implemented yet"); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + if (compptr->h_samp_factor == cinfo->max_h_samp_factor && + compptr->v_samp_factor == cinfo->max_v_samp_factor) + cinfo->methods->unsubsample[ci] = fullsize_unsubsample; + else if ((cinfo->max_h_samp_factor % compptr->h_samp_factor) == 0 && + (cinfo->max_v_samp_factor % compptr->v_samp_factor) == 0) + cinfo->methods->unsubsample[ci] = unsubsample; + else + ERREXIT(cinfo->emethods, "Fractional subsampling not implemented yet"); + } + + cinfo->methods->unsubsample_init = unsubsample_init; + cinfo->methods->unsubsample_term = unsubsample_term; +} diff --git a/jerror.c b/jerror.c new file mode 100644 index 0000000..591b185 --- /dev/null +++ b/jerror.c @@ -0,0 +1,67 @@ +/* + * jerror.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains simple error-reporting and trace-message routines. + * These are suitable for Unix-like systems and others where writing to + * stderr is the right thing to do. If the JPEG software is integrated + * into a larger application, you may well need to replace these. + * + * The error_exit() routine should not return to its caller. Within a + * larger application, you might want to have it do a longjmp() to return + * control to the outer user interface routine. This should work since + * the portable JPEG code doesn't use setjmp/longjmp. However, this won't + * release allocated memory or close temp files --- some bookkeeping would + * need to be added to the memory manager module to make that work. + * + * These routines are used by both the compression and decompression code. + */ + +#include "jinclude.h" +#ifdef __STDC__ +#include /* to declare exit() */ +#endif + + +static external_methods_ptr methods; /* saved for access to message_parm */ + + +METHODDEF void +trace_message (char *msgtext) +{ + fprintf(stderr, msgtext, + methods->message_parm[0], methods->message_parm[1], + methods->message_parm[2], methods->message_parm[3], + methods->message_parm[4], methods->message_parm[5], + methods->message_parm[6], methods->message_parm[7]); + fprintf(stderr, "\n"); +} + + +METHODDEF void +error_exit (char *msgtext) +{ + trace_message(msgtext); + exit(1); +} + + +/* + * The method selection routine for simple error handling. + * The system-dependent setup routine should call this routine + * to install the necessary method pointers in the supplied struct. + */ + +GLOBAL void +jselerror (external_methods_ptr emethods) +{ + methods = emethods; /* save struct addr for msg parm access */ + + emethods->error_exit = error_exit; + emethods->trace_message = trace_message; + + emethods->trace_level = 0; /* default = no tracing */ +} diff --git a/jfwddct.c b/jfwddct.c new file mode 100644 index 0000000..58291ac --- /dev/null +++ b/jfwddct.c @@ -0,0 +1,179 @@ +/* + * jfwddct.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the basic DCT (Discrete Cosine Transform) + * transformation subroutine. + * + * This implementation is based on Appendix A.2 of the book + * "Discrete Cosine Transform---Algorithms, Advantages, Applications" + * by K.R. Rao and P. Yip (Academic Press, Inc, London, 1990). + * It uses scaled fixed-point arithmetic instead of floating point. + */ + +#include "jinclude.h" + + +/* The poop on this scaling stuff is as follows: + * + * Most of the numbers (after multiplication by the constants) are + * (logically) shifted left by LG2_DCT_SCALE. This is undone by UNFIXH + * before assignment to the output array. Note that we want an additional + * division by 2 on the output (required by the equations). + * + * If right shifts are unsigned, then there is a potential problem. + * However, shifting right by 16 and then assigning to a short + * (assuming short = 16 bits) will keep the sign right!! + * + * For other shifts, + * + * ((x + (1 << 30)) >> shft) - (1 << (30 - shft)) + * + * gives a nice right shift with sign (assuming no overflow). However, all the + * scaling is such that this isn't a problem. (Is this true?) + */ + + +#define ONE 1L /* remove L if long > 32 bits */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define LG2_DCT_SCALE 15 +#define RIGHT_SHIFT(_x,_shft) ((((_x) + (ONE << 30)) >> (_shft)) - (ONE << (30 - (_shft)))) +#else +#define LG2_DCT_SCALE 16 +#define RIGHT_SHIFT(_x,_shft) ((_x) >> (_shft)) +#endif + +#define DCT_SCALE (ONE << LG2_DCT_SCALE) + +#define LG2_OVERSCALE 2 +#define OVERSCALE (ONE << LG2_OVERSCALE) + +#define FIX(x) ((INT32) ((x) * DCT_SCALE + 0.5)) +#define FIXO(x) ((INT32) ((x) * DCT_SCALE / OVERSCALE + 0.5)) +#define UNFIX(x) RIGHT_SHIFT((x) + (ONE << (LG2_DCT_SCALE-1)), LG2_DCT_SCALE) +#define UNFIXH(x) RIGHT_SHIFT((x) + (ONE << LG2_DCT_SCALE), LG2_DCT_SCALE+1) +#define UNFIXO(x) RIGHT_SHIFT((x) + (ONE << (LG2_DCT_SCALE-1-LG2_OVERSCALE)), LG2_DCT_SCALE-LG2_OVERSCALE) +#define OVERSH(x) ((x) << LG2_OVERSCALE) + +#define SIN_1_4 FIX(0.7071067811856476) +#define COS_1_4 SIN_1_4 + +#define SIN_1_8 FIX(0.3826834323650898) +#define COS_1_8 FIX(0.9238795325112870) +#define SIN_3_8 COS_1_8 +#define COS_3_8 SIN_1_8 + +#define SIN_1_16 FIX(0.1950903220161282) +#define COS_1_16 FIX(0.9807852804032300) +#define SIN_7_16 COS_1_16 +#define COS_7_16 SIN_1_16 + +#define SIN_3_16 FIX(0.5555702330196022) +#define COS_3_16 FIX(0.8314696123025450) +#define SIN_5_16 COS_3_16 +#define COS_5_16 SIN_3_16 + +#define OSIN_1_4 FIXO(0.707106781185647) +#define OCOS_1_4 OSIN_1_4 + +#define OSIN_1_8 FIXO(0.3826834323650898) +#define OCOS_1_8 FIXO(0.9238795325112870) +#define OSIN_3_8 OCOS_1_8 +#define OCOS_3_8 OSIN_1_8 + +#define OSIN_1_16 FIXO(0.1950903220161282) +#define OCOS_1_16 FIXO(0.9807852804032300) +#define OSIN_7_16 OCOS_1_16 +#define OCOS_7_16 OSIN_1_16 + +#define OSIN_3_16 FIXO(0.5555702330196022) +#define OCOS_3_16 FIXO(0.8314696123025450) +#define OSIN_5_16 OCOS_3_16 +#define OCOS_5_16 OSIN_3_16 + + +INLINE +LOCAL void +fast_dct_8 (DCTELEM *in, int stride) +{ + /* tmp1x are new values of tmpx -- flashy register colourers + * should be able to do this lot very well + */ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17; + INT32 tmp25, tmp26; + INT32 in0, in1, in2, in3, in4, in5, in6, in7; + + in0 = in[ 0]; + in1 = in[stride ]; + in2 = in[stride*2]; + in3 = in[stride*3]; + in4 = in[stride*4]; + in5 = in[stride*5]; + in6 = in[stride*6]; + in7 = in[stride*7]; + + tmp0 = in7 + in0; + tmp1 = in6 + in1; + tmp2 = in5 + in2; + tmp3 = in4 + in3; + tmp4 = in3 - in4; + tmp5 = in2 - in5; + tmp6 = in1 - in6; + tmp7 = in0 - in7; + + tmp10 = tmp3 + tmp0 ; + tmp11 = tmp2 + tmp1 ; + tmp12 = tmp1 - tmp2 ; + tmp13 = tmp0 - tmp3 ; + + /* Now using tmp10, tmp11, tmp12, tmp13 */ + + in[ 0] = UNFIXH((tmp10 + tmp11) * SIN_1_4); + in[stride*4] = UNFIXH((tmp10 - tmp11) * COS_1_4); + + in[stride*2] = UNFIXH(tmp13*COS_1_8 + tmp12*SIN_1_8); + in[stride*6] = UNFIXH(tmp13*SIN_1_8 - tmp12*COS_1_8); + + tmp16 = UNFIXO((tmp6 + tmp5) * SIN_1_4); + tmp15 = UNFIXO((tmp6 - tmp5) * COS_1_4); + + /* Now using tmp10, tmp11, tmp13, tmp14, tmp15, tmp16 */ + + tmp14 = OVERSH(tmp4) + tmp15; + tmp25 = OVERSH(tmp4) - tmp15; + tmp26 = OVERSH(tmp7) - tmp16; + tmp17 = OVERSH(tmp7) + tmp16; + + /* These are now overscaled by OVERSCALE */ + + /* tmp10, tmp11, tmp12, tmp13, tmp14, tmp25, tmp26, tmp17 */ + + in[stride ] = UNFIXH(tmp17*OCOS_1_16 + tmp14*OSIN_1_16); + in[stride*7] = UNFIXH(tmp17*OCOS_7_16 - tmp14*OSIN_7_16); + in[stride*5] = UNFIXH(tmp26*OCOS_5_16 + tmp25*OSIN_5_16); + in[stride*3] = UNFIXH(tmp26*OCOS_3_16 - tmp25*OSIN_3_16); +} + + +/* + * Perform the forward DCT on one block of samples. + * + * Note that this code is specialized to the case DCTSIZE = 8. + */ + +GLOBAL void +j_fwd_dct (DCTBLOCK data) +{ + int i; + + for (i = 0; i < DCTSIZE; i++) + fast_dct_8(data+i*DCTSIZE, 1); + + for (i = 0; i < DCTSIZE; i++) + fast_dct_8(data+i, DCTSIZE); +} diff --git a/jinclude.h b/jinclude.h new file mode 100644 index 0000000..ec7a7e8 --- /dev/null +++ b/jinclude.h @@ -0,0 +1,73 @@ +/* + * jinclude.h + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This is the central file that's #include'd by all the JPEG .c files. + * Its purpose is to provide a single place to fix any problems with + * including the wrong system include files. + * You can edit these declarations if you use a system with nonstandard + * system include files. + */ + + +/* + * is included to get the FILE typedef and NULL macro. + * Note that the core portable-JPEG files do not actually do any I/O + * using the stdio library; only the user interface, error handler, + * and file reading/writing modules invoke any stdio functions. + * (Well, we did cheat a bit in jvirtmem.c, but only if MEM_STATS is defined.) + */ + +#include + +/* + * We need the size_t typedef, which defines the parameter type of malloc(). + * In an ANSI-conforming implementation this is provided by , + * but on non-ANSI systems it's more likely to be in . + */ + +#ifndef __STDC__ /* shouldn't need this if __STDC__ */ +#include +#endif + +/* + * In ANSI C, and indeed any rational implementation, size_t is also the + * type returned by sizeof(). However, it seems there are some irrational + * implementations out there, in which sizeof() returns an int even though + * size_t is defined as long or unsigned long. To ensure consistent results + * we always use this SIZEOF() macro in place of using sizeof() directly. + */ + +#define SIZEOF(object) ((size_t) sizeof(object)) + +/* + * We need the memcpy() and strcmp() functions, plus memory zeroing. + * ANSI and System V implementations declare these in . + * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). + * NOTE: we assume the size parameters to these functions are of type size_t. + * Insert casts in these macros if not! + */ + +#ifdef __STDC__ +#include +#define MEMZERO(voidptr,size) memset((voidptr), 0, (size)) +#else /* not STDC */ +#ifdef BSD +#include +#define MEMZERO(voidptr,size) bzero((voidptr), (size)) +#define memcpy(dest,src,size) bcopy((src), (dest), (size)) +#else /* not BSD, assume Sys V or compatible */ +#include +#define MEMZERO(voidptr,size) memset((voidptr), 0, (size)) +#endif /* BSD */ +#endif /* STDC */ + + +/* Now include the portable JPEG definition files. */ + +#include "jconfig.h" + +#include "jpegdata.h" diff --git a/jpegdata.h b/jpegdata.h new file mode 100644 index 0000000..3e4d753 --- /dev/null +++ b/jpegdata.h @@ -0,0 +1,812 @@ +/* + * jpegdata.h + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines shared data structures for the various JPEG modules. + */ + + +/* + * You might need to change some of the following declarations if you are + * using the JPEG software within a surrounding application program + * or porting it to an unusual system. + */ + + +/* If the source or destination of image data is not to be stdio streams, + * these types may need work. You can replace them with some kind of + * pointer or indicator that is useful to you, or just ignore 'em. + * Note that the user interface and the various jrdxxx/jwrxxx modules + * will also need work for non-stdio input/output. + */ + +typedef FILE * JFILEREF; /* source or dest of JPEG-compressed data */ + +typedef FILE * IFILEREF; /* source or dest of non-JPEG image data */ + + +/* These defines are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions, + * as is shown below for use with C++. Another application would be to make + * all functions global for use with code profilers that require it. + * NOTE: the C++ test does the right thing if you are reading this include + * file in a C++ application to link to JPEG code that's been compiled with a + * regular C compiler. I'm not sure it works if you try to compile the JPEG + * code with C++. + */ + +#define METHODDEF static /* a function called through method pointers */ +#define LOCAL static /* a function used only in its module */ +#define GLOBAL /* a function referenced thru EXTERNs */ +#ifdef __cplusplus +#define EXTERN extern "C" /* a reference to a GLOBAL function */ +#else +#define EXTERN extern /* a reference to a GLOBAL function */ +#endif + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifdef NEED_FAR_POINTERS +#define FAR far +#else +#define FAR +#endif + + + +/* The remaining declarations are not system-dependent, we hope. */ + + +/* + * NOTE: if you have an ancient, strict-K&R C compiler, it may choke on the + * similarly-named fields in compress_info_struct and decompress_info_struct. + * If this happens, you can get around it by rearranging the two structs so + * that the similarly-named fields appear first and in the same order in + * each struct. Since such compilers are now pretty rare, we haven't done + * this in the portable code, preferring to maintain a logical ordering. + */ + + + +/* This macro is used to declare a "method", that is, a function pointer. */ +/* We want to supply prototype parameters if the compiler can cope. */ +/* Note that the arglist parameter must be parenthesized! */ + +#ifdef PROTO +#define METHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define METHOD(type,methodname,arglist) type (*methodname) () +#endif + +/* Forward references to lists of method pointers */ +typedef struct external_methods_struct * external_methods_ptr; +typedef struct compress_methods_struct * compress_methods_ptr; +typedef struct decompress_methods_struct * decompress_methods_ptr; + + +/* Data structures for images containing either samples or coefficients. */ +/* Note that the topmost (leftmost) index is always color component. */ +/* On 80x86 machines, the image arrays are too big for near pointers, */ +/* but the pointer arrays can fit in near memory. */ + +typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* The input and output data of the DCT transform subroutines are of + * the following type, which need not be the same as JCOEF. + * For example, on a machine with fast floating point, it might make sense + * to recode the DCT routines to use floating point; then DCTELEM would be + * 'float' or 'double'. + */ + +typedef JCOEF DCTELEM; +typedef DCTELEM DCTBLOCK[DCTSIZE2]; + + +/* Types for JPEG compression parameters and working tables. */ + + +typedef enum { /* defines known color spaces */ + CS_UNKNOWN, /* error/unspecified */ + CS_GRAYSCALE, /* monochrome (only 1 component) */ + CS_RGB, /* red/green/blue */ + CS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + CS_YIQ, /* Y/I/Q */ + CS_CMYK /* C/M/Y/K */ +} COLOR_SPACE; + + +typedef struct { /* Basic info about one component */ + /* These values are fixed over the whole image */ + /* For compression, they must be supplied by the user interface; */ + /* for decompression, they are read from the SOF marker. */ + short component_id; /* identifier for this component (0..255) */ + short component_index; /* its index in SOF or cinfo->comp_info[] */ + short h_samp_factor; /* horizontal sampling factor (1..4) */ + short v_samp_factor; /* vertical sampling factor (1..4) */ + short quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans */ + /* For compression, they must be supplied by the user interface; */ + /* for decompression, they are read from the SOS marker. */ + short dc_tbl_no; /* DC entropy table selector (0..3) */ + short ac_tbl_no; /* AC entropy table selector (0..3) */ + /* These values are computed during compression or decompression startup */ + long true_comp_width; /* component's image width in samples */ + long true_comp_height; /* component's image height in samples */ + /* the above are the logical dimensions of the subsampled image */ + /* These values are computed before starting a scan of the component */ + short MCU_width; /* number of blocks per MCU, horizontally */ + short MCU_height; /* number of blocks per MCU, vertically */ + short MCU_blocks; /* MCU_width * MCU_height */ + long subsampled_width; /* image width in samples, after expansion */ + long subsampled_height; /* image height in samples, after expansion */ + /* the above are the true_comp_xxx values rounded up to multiples of */ + /* the MCU dimensions; these are the working dimensions of the array */ + /* as it is passed through the DCT or IDCT step. NOTE: these values */ + /* differ depending on whether the component is interleaved or not!! */ +} jpeg_component_info; + + +/* DCT coefficient quantization tables. + * For 8-bit precision, 'INT16' should be good enough for quantization values; + * for more precision, we go for the full 16 bits. 'INT16' provides a useful + * speedup on many machines (multiplication & division of JCOEFs by + * quantization values is a significant chunk of the runtime). + * Note: the values in a QUANT_TBL are always given in zigzag order. + */ +#ifdef EIGHT_BIT_SAMPLES +typedef INT16 QUANT_VAL; /* element of a quantization table */ +#else +typedef UINT16 QUANT_VAL; /* element of a quantization table */ +#endif +typedef QUANT_VAL QUANT_TBL[DCTSIZE2]; /* A quantization table */ +typedef QUANT_VAL * QUANT_TBL_PTR; /* pointer to same */ + + +typedef struct { /* A Huffman coding table */ + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + */ + boolean sent_table; /* TRUE when table has been output */ + /* The remaining fields are computed from the above to allow more efficient + * coding and decoding. These fields should be considered private to the + * Huffman compression & decompression modules. + */ + UINT16 ehufco[256]; /* code for each symbol */ + char ehufsi[256]; /* length of code for each symbol */ + UINT16 mincode[17]; /* smallest code of length k */ + INT32 maxcode[17]; /* largest code of length k (-1 if none) */ + short valptr[17]; /* huffval[] index of 1st symbol of length k */ +} HUFF_TBL; + + +#define NUM_QUANT_TBLS 4 /* quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +#define MAX_BLOCKS_IN_MCU 10 /* JPEG limit on # of blocks in an MCU */ + + +/* Working data for compression */ + +struct compress_info_struct { +/* + * All of these fields shall be established by the user interface before + * calling jpeg_compress, or by the input_init or c_ui_method_selection + * methods. + * Most parameters can be set to reasonable defaults by j_default_compression. + * Note that the UI must supply the storage for the main methods struct, + * though it sets only a few of the methods there. + */ + compress_methods_ptr methods; /* Points to list of methods to use */ + + external_methods_ptr emethods; /* Points to list of methods to use */ + + IFILEREF input_file; /* tells input routines where to read image */ + JFILEREF output_file; /* tells output routines where to write JPEG */ + + long image_width; /* input image width */ + long image_height; /* input image height */ + short input_components; /* # of color components in input image */ + + short data_precision; /* bits of precision in image data */ + + COLOR_SPACE in_color_space; /* colorspace of input file */ + COLOR_SPACE jpeg_color_space; /* colorspace of JPEG file */ + + double input_gamma; /* image gamma of input file */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + /* These three values are not used by the JPEG code, only copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + + short num_components; /* # of color components in JPEG image */ + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + QUANT_TBL_PTR quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + HUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + HUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arithmetic-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arithmetic-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arithmetic-coding tables */ + + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean interleave; /* TRUE=interleaved output, FALSE=not */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + UINT16 restart_interval;/* MDUs per restart interval, or 0 for no restart */ + +/* + * These fields are computed during jpeg_compress startup + */ + short max_h_samp_factor; /* largest h_samp_factor */ + short max_v_samp_factor; /* largest v_samp_factor */ + +/* + * These fields are valid during any one scan + */ + short comps_in_scan; /* # of JPEG components output this time */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + long MCUs_per_row; /* # of MCUs across the image */ + long MCU_rows_in_scan; /* # of MCU rows in the image */ + + short blocks_in_MCU; /* # of DCT blocks per MCU */ + short MCU_membership[MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + /* these fields are private data for the entropy encoder */ + JCOEF last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each comp */ + JCOEF last_dc_diff[MAX_COMPS_IN_SCAN]; /* last DC diff for each comp */ + UINT16 restarts_to_go; /* MDUs left in this restart interval */ + short next_restart_num; /* # of next RSTn marker (0..7) */ +}; + +typedef struct compress_info_struct * compress_info_ptr; + + +/* Working data for decompression */ + +struct decompress_info_struct { +/* + * These fields shall be established by the user interface before + * calling jpeg_decompress. Note that the UI must supply the storage for + * the main methods struct, though it sets only a few of the methods there. + */ + decompress_methods_ptr methods; /* Points to list of methods to use */ + + external_methods_ptr emethods; /* Points to list of methods to use */ + + JFILEREF input_file; /* tells input routines where to read JPEG */ + IFILEREF output_file; /* tells output routines where to write image */ + + /* these can be set at d_ui_method_selection time: */ + + COLOR_SPACE out_color_space; /* colorspace of output */ + + double output_gamma; /* image gamma wanted in output */ + + boolean quantize_colors; /* T if output is a colormapped format */ + /* the following are ignored if not quantize_colors: */ + boolean two_pass_quantize; /* use two-pass color quantization? */ + boolean use_dithering; /* want color dithering? */ + int desired_number_of_colors; /* number of colors to use */ + + boolean do_block_smoothing; /* T = apply cross-block smoothing */ + boolean do_pixel_smoothing; /* T = apply post-subsampling smoothing */ + +/* + * These fields are used for efficient buffering of data between read_jpeg_data + * and the entropy decoding object. By using a shared buffer, we avoid copying + * data and eliminate the need for an "unget" operation at the end of a scan. + * The actual source of the data is known only to read_jpeg_data; see the + * JGETC macro, below. + * Note: the user interface is expected to allocate the input_buffer and + * initialize bytes_in_buffer to 0. Also, for JFIF/raw-JPEG input, the UI + * actually supplies the read_jpeg_data method. + */ + char * input_buffer; /* start of buffer (private to input code) */ + char * next_input_byte; /* => next byte to read from buffer */ + int bytes_in_buffer; /* # of bytes remaining in buffer */ + +/* + * These fields are set by read_file_header or read_scan_header + */ + long image_width; /* overall image width */ + long image_height; /* overall image height */ + + short data_precision; /* bits of precision in image data */ + + COLOR_SPACE jpeg_color_space; /* colorspace of JPEG file */ + + /* These three values are not used by the JPEG code, merely copied */ + /* from the JFIF APP0 marker (if any). */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + + short num_components; /* # of color components in JPEG image */ + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + QUANT_TBL_PTR quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + HUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + HUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + UINT16 restart_interval;/* MDUs per restart interval, or 0 for no restart */ + +/* + * These fields are computed during jpeg_decompress startup + */ + short max_h_samp_factor; /* largest h_samp_factor */ + short max_v_samp_factor; /* largest v_samp_factor */ + + short color_out_comps; /* # of color components output by color_convert */ + /* (need not match num_components) */ + short final_out_comps; /* # of color components in output image */ + /* (1 when quantizing colors, else same as color_out_comps) */ + +/* + * These fields are valid during any one scan + */ + short comps_in_scan; /* # of JPEG components input this time */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + long MCUs_per_row; /* # of MCUs across the image */ + long MCU_rows_in_scan; /* # of MCU rows in the image */ + + short blocks_in_MCU; /* # of DCT blocks per MCU */ + short MCU_membership[MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + /* these fields are private data for the entropy encoder */ + JCOEF last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each comp */ + JCOEF last_dc_diff[MAX_COMPS_IN_SCAN]; /* last DC diff for each comp */ + UINT16 restarts_to_go; /* MDUs left in this restart interval */ + short next_restart_num; /* # of next RSTn marker (0..7) */ +}; + +typedef struct decompress_info_struct * decompress_info_ptr; + + +/* Macros for reading data from the decompression input buffer */ + +#ifdef CHAR_IS_UNSIGNED +#define JGETC(cinfo) ( --(cinfo)->bytes_in_buffer < 0 ? \ + (*(cinfo)->methods->read_jpeg_data) (cinfo) : \ + (int) *(cinfo)->next_input_byte++ ) +#else +#define JGETC(cinfo) ( --(cinfo)->bytes_in_buffer < 0 ? \ + (*(cinfo)->methods->read_jpeg_data) (cinfo) : \ + (int) (*(cinfo)->next_input_byte++) & 0xFF ) +#endif + +#define JUNGETC(ch,cinfo) ((cinfo)->bytes_in_buffer++, \ + *(--((cinfo)->next_input_byte)) = (ch)) + +#define MIN_UNGET 2 /* may always do at least 2 JUNGETCs */ + + +/* A virtual image has a control block whose contents are private to the + * memory manager module (and may differ between managers). The rest of the + * code only refers to virtual images by these pointer types. + */ + +typedef struct big_sarray_control * big_sarray_ptr; +typedef struct big_barray_control * big_barray_ptr; + + +/* Method types that need typedefs */ + +typedef METHOD(void, MCU_output_method_ptr, (compress_info_ptr cinfo, + JBLOCK *MCU_data)); +typedef METHOD(void, MCU_output_caller_ptr, (compress_info_ptr cinfo, + MCU_output_method_ptr output_method)); +typedef METHOD(void, subsample_ptr, (compress_info_ptr cinfo, + int which_component, + long input_cols, int input_rows, + long output_cols, int output_rows, + JSAMPARRAY above, + JSAMPARRAY input_data, + JSAMPARRAY below, + JSAMPARRAY output_data)); +typedef METHOD(void, unsubsample_ptr, (decompress_info_ptr cinfo, + int which_component, + long input_cols, int input_rows, + long output_cols, int output_rows, + JSAMPARRAY above, + JSAMPARRAY input_data, + JSAMPARRAY below, + JSAMPARRAY output_data)); +typedef METHOD(void, quantize_method_ptr, (decompress_info_ptr cinfo, + int num_rows, + JSAMPIMAGE input_data, + JSAMPARRAY output_workspace)); +typedef METHOD(void, quantize_caller_ptr, (decompress_info_ptr cinfo, + quantize_method_ptr quantize_method)); + + +/* These structs contain function pointers for the various JPEG methods. */ + +/* Routines to be provided by the surrounding application, rather than the + * portable JPEG code proper. These are the same for compression and + * decompression. + */ + +struct external_methods_struct { + /* User interface: error exit and trace message routines */ + /* NOTE: the string msgtext parameters will eventually be replaced */ + /* by an enumerated-type code so that non-English error messages */ + /* can be substituted easily. This will not be done until all the */ + /* code is in place, so that we know what messages are needed. */ + METHOD(void, error_exit, (char *msgtext)); + METHOD(void, trace_message, (char *msgtext)); + + /* Working data for error/trace facility */ + /* See macros below for the usage of these variables */ + int trace_level; /* level of detail of tracing messages */ + /* Use level 0 for unsuppressable messages (nonfatal errors) */ + /* Use levels 1, 2, 3 for successively more detailed trace options */ + + int message_parm[8]; /* store numeric parms for messages here */ + + /* Memory management */ + /* NB: alloc routines never return NULL. They exit to */ + /* error_exit if not successful. */ + METHOD(void *, alloc_small, (size_t sizeofobject)); + METHOD(void, free_small, (void *ptr)); +#ifdef NEED_FAR_POINTERS /* routines for getting far-heap space */ + METHOD(void FAR *, alloc_medium, (size_t sizeofobject)); + METHOD(void, free_medium, (void FAR *ptr)); +#else +#define alloc_medium alloc_small +#define free_medium free_small +#endif + METHOD(JSAMPARRAY, alloc_small_sarray, (long samplesperrow, + long numrows)); + METHOD(void, free_small_sarray, (JSAMPARRAY ptr, + long numrows)); + METHOD(JBLOCKARRAY, alloc_small_barray, (long blocksperrow, + long numrows)); + METHOD(void, free_small_barray, (JBLOCKARRAY ptr, + long numrows)); + METHOD(big_sarray_ptr, request_big_sarray, (long samplesperrow, + long numrows, + long unitheight)); + METHOD(big_barray_ptr, request_big_barray, (long blocksperrow, + long numrows, + long unitheight)); + METHOD(void, alloc_big_arrays, (long extra_small_samples, + long extra_small_blocks, + long extra_medium_space)); + METHOD(JSAMPARRAY, access_big_sarray, (big_sarray_ptr ptr, + long start_row, + boolean writable)); + METHOD(JBLOCKARRAY, access_big_barray, (big_barray_ptr ptr, + long start_row, + boolean writable)); + METHOD(void, free_big_sarray, (big_sarray_ptr ptr)); + METHOD(void, free_big_barray, (big_barray_ptr ptr)); +}; + +/* Macros to simplify using the error and trace message stuff */ +/* The first parameter is generally cinfo->emethods */ + +#define ERREXIT(emeth,msg) ((*(emeth)->error_exit) (msg)) +#define ERREXIT1(emeth,msg,p1) ((emeth)->message_parm[0] = (p1), \ + (*(emeth)->error_exit) (msg)) +#define ERREXIT2(emeth,msg,p1,p2) ((emeth)->message_parm[0] = (p1), \ + (emeth)->message_parm[1] = (p2), \ + (*(emeth)->error_exit) (msg)) +#define ERREXIT3(emeth,msg,p1,p2,p3) ((emeth)->message_parm[0] = (p1), \ + (emeth)->message_parm[1] = (p2), \ + (emeth)->message_parm[2] = (p3), \ + (*(emeth)->error_exit) (msg)) +#define ERREXIT4(emeth,msg,p1,p2,p3,p4) ((emeth)->message_parm[0] = (p1), \ + (emeth)->message_parm[1] = (p2), \ + (emeth)->message_parm[2] = (p3), \ + (emeth)->message_parm[3] = (p4), \ + (*(emeth)->error_exit) (msg)) + +#define TRACEMS(emeth,lvl,msg) \ + ( (emeth)->trace_level >= (lvl) ? \ + ((*(emeth)->trace_message) (msg), 0) : 0) +#define TRACEMS1(emeth,lvl,msg,p1) \ + ( (emeth)->trace_level >= (lvl) ? \ + ((emeth)->message_parm[0] = (p1), \ + (*(emeth)->trace_message) (msg), 0) : 0) +#define TRACEMS2(emeth,lvl,msg,p1,p2) \ + ( (emeth)->trace_level >= (lvl) ? \ + ((emeth)->message_parm[0] = (p1), \ + (emeth)->message_parm[1] = (p2), \ + (*(emeth)->trace_message) (msg), 0) : 0) +#define TRACEMS3(emeth,lvl,msg,p1,p2,p3) \ + ( (emeth)->trace_level >= (lvl) ? \ + ((emeth)->message_parm[0] = (p1), \ + (emeth)->message_parm[1] = (p2), \ + (emeth)->message_parm[2] = (p3), \ + (*(emeth)->trace_message) (msg), 0) : 0) +#define TRACEMS4(emeth,lvl,msg,p1,p2,p3,p4) \ + ( (emeth)->trace_level >= (lvl) ? \ + ((emeth)->message_parm[0] = (p1), \ + (emeth)->message_parm[1] = (p2), \ + (emeth)->message_parm[2] = (p3), \ + (emeth)->message_parm[3] = (p4), \ + (*(emeth)->trace_message) (msg), 0) : 0) +#define TRACEMS8(emeth,lvl,msg,p1,p2,p3,p4,p5,p6,p7,p8) \ + ( (emeth)->trace_level >= (lvl) ? \ + ((emeth)->message_parm[0] = (p1), \ + (emeth)->message_parm[1] = (p2), \ + (emeth)->message_parm[2] = (p3), \ + (emeth)->message_parm[3] = (p4), \ + (emeth)->message_parm[4] = (p5), \ + (emeth)->message_parm[5] = (p6), \ + (emeth)->message_parm[6] = (p7), \ + (emeth)->message_parm[7] = (p8), \ + (*(emeth)->trace_message) (msg), 0) : 0) + + +/* Methods used during JPEG compression. */ + +struct compress_methods_struct { + /* Hook for user interface to get control after input_init */ + METHOD(void, c_ui_method_selection, (compress_info_ptr cinfo)); + /* Input image reading & conversion to standard form */ + METHOD(void, input_init, (compress_info_ptr cinfo)); + METHOD(void, get_input_row, (compress_info_ptr cinfo, + JSAMPARRAY pixel_row)); + METHOD(void, input_term, (compress_info_ptr cinfo)); + /* Gamma and color space conversion */ + METHOD(void, colorin_init, (compress_info_ptr cinfo)); + METHOD(void, get_sample_rows, (compress_info_ptr cinfo, + int rows_to_read, + JSAMPIMAGE image_data)); + METHOD(void, colorin_term, (compress_info_ptr cinfo)); + /* Expand picture data at edges */ + METHOD(void, edge_expand, (compress_info_ptr cinfo, + long input_cols, int input_rows, + long output_cols, int output_rows, + JSAMPIMAGE image_data)); + /* Subsample pixel values of a single component */ + /* There can be a different subsample method for each component */ + METHOD(void, subsample_init, (compress_info_ptr cinfo)); + subsample_ptr subsample[MAX_COMPS_IN_SCAN]; + METHOD(void, subsample_term, (compress_info_ptr cinfo)); + /* Extract samples in MCU order, process & hand off to output_method */ + /* The input is always exactly N MCU rows worth of data */ + METHOD(void, extract_init, (compress_info_ptr cinfo)); + METHOD(void, extract_MCUs, (compress_info_ptr cinfo, + JSAMPIMAGE image_data, + int num_mcu_rows, + MCU_output_method_ptr output_method)); + METHOD(void, extract_term, (compress_info_ptr cinfo)); + /* Entropy encoding parameter optimization */ + METHOD(void, entropy_optimize, (compress_info_ptr cinfo, + MCU_output_caller_ptr source_method)); + /* Entropy encoding */ + METHOD(void, entropy_encoder_init, (compress_info_ptr cinfo)); + METHOD(void, entropy_encode, (compress_info_ptr cinfo, + JBLOCK *MCU_data)); + METHOD(void, entropy_encoder_term, (compress_info_ptr cinfo)); + /* JPEG file header construction */ + METHOD(void, write_file_header, (compress_info_ptr cinfo)); + METHOD(void, write_scan_header, (compress_info_ptr cinfo)); + METHOD(void, write_jpeg_data, (compress_info_ptr cinfo, + char *dataptr, + int datacount)); + METHOD(void, write_scan_trailer, (compress_info_ptr cinfo)); + METHOD(void, write_file_trailer, (compress_info_ptr cinfo)); + /* Pipeline control */ + METHOD(void, c_pipeline_controller, (compress_info_ptr cinfo)); + METHOD(void, entropy_output, (compress_info_ptr cinfo, + char *dataptr, + int datacount)); + /* Overall control */ + METHOD(void, c_per_scan_method_selection, (compress_info_ptr cinfo)); +}; + +/* Methods used during JPEG decompression. */ + +struct decompress_methods_struct { + /* Hook for user interface to get control after reading file header */ + METHOD(void, d_ui_method_selection, (decompress_info_ptr cinfo)); + /* JPEG file scanning */ + /* Note: user interface supplies read_jpeg_data for JFIF/raw-JPEG + * reading. For file formats that require random access (eg, TIFF) + * the JPEG file header module will override the UI read_jpeg_data. + */ + METHOD(void, read_file_header, (decompress_info_ptr cinfo)); + METHOD(boolean, read_scan_header, (decompress_info_ptr cinfo)); + METHOD(int, read_jpeg_data, (decompress_info_ptr cinfo)); + METHOD(void, read_scan_trailer, (decompress_info_ptr cinfo)); + METHOD(void, read_file_trailer, (decompress_info_ptr cinfo)); + /* Entropy decoding */ + METHOD(void, entropy_decoder_init, (decompress_info_ptr cinfo)); + METHOD(void, entropy_decode, (decompress_info_ptr cinfo, + JBLOCK *MCU_data)); + METHOD(void, entropy_decoder_term, (decompress_info_ptr cinfo)); + /* MCU disassembly: fetch MCUs from entropy_decode, build coef array */ + METHOD(void, disassemble_init, (decompress_info_ptr cinfo)); + METHOD(void, disassemble_MCU, (decompress_info_ptr cinfo, + JBLOCKIMAGE image_data)); + METHOD(void, disassemble_term, (decompress_info_ptr cinfo)); + /* Cross-block smoothing */ + METHOD(void, smooth_coefficients, (decompress_info_ptr cinfo, + jpeg_component_info *compptr, + JBLOCKROW above, + JBLOCKROW currow, + JBLOCKROW below, + JBLOCKROW output)); + /* Un-subsample pixel values of a single component */ + /* There can be a different unsubsample method for each component */ + METHOD(void, unsubsample_init, (decompress_info_ptr cinfo)); + unsubsample_ptr unsubsample[MAX_COMPS_IN_SCAN]; + METHOD(void, unsubsample_term, (decompress_info_ptr cinfo)); + /* Gamma and color space conversion */ + METHOD(void, colorout_init, (decompress_info_ptr cinfo)); + METHOD(void, color_convert, (decompress_info_ptr cinfo, + int num_rows, + JSAMPIMAGE input_data, + JSAMPIMAGE output_data)); + METHOD(void, colorout_term, (decompress_info_ptr cinfo)); + /* Color quantization */ + METHOD(void, color_quant_init, (decompress_info_ptr cinfo)); + METHOD(void, color_quantize, (decompress_info_ptr cinfo, + int num_rows, + JSAMPIMAGE input_data, + JSAMPARRAY output_data)); + METHOD(void, color_quant_prescan, (decompress_info_ptr cinfo, + int num_rows, + JSAMPIMAGE image_data)); + METHOD(void, color_quant_doit, (decompress_info_ptr cinfo, + quantize_caller_ptr source_method)); + METHOD(void, color_quant_term, (decompress_info_ptr cinfo)); + /* Output image writing */ + METHOD(void, output_init, (decompress_info_ptr cinfo)); + METHOD(void, put_color_map, (decompress_info_ptr cinfo, + int num_colors, JSAMPARRAY colormap)); + METHOD(void, put_pixel_rows, (decompress_info_ptr cinfo, + int num_rows, + JSAMPIMAGE pixel_data)); + METHOD(void, output_term, (decompress_info_ptr cinfo)); + /* Pipeline control */ + METHOD(void, d_pipeline_controller, (decompress_info_ptr cinfo)); + /* Overall control */ + METHOD(void, d_per_scan_method_selection, (decompress_info_ptr cinfo)); +}; + + +/* External declarations for routines that aren't called via method ptrs. */ +/* Note: use "j" as first char of names to minimize namespace pollution. */ +/* The PP macro hides prototype parameters from compilers that can't cope. */ + +#ifdef PROTO +#define PP(arglist) arglist +#else +#define PP(arglist) () +#endif + + +/* main entry for compression */ +EXTERN void jpeg_compress PP((compress_info_ptr cinfo)); +/* default parameter setup for compression */ +EXTERN void j_default_compression PP((compress_info_ptr cinfo, int quality)); +EXTERN void j_monochrome_default PP((compress_info_ptr cinfo)); +EXTERN void j_set_quality PP((compress_info_ptr cinfo, int quality, + boolean force_baseline)); +EXTERN void j_free_defaults PP((compress_info_ptr cinfo)); + +/* main entry for decompression */ +EXTERN void jpeg_decompress PP((decompress_info_ptr cinfo)); + +/* forward DCT */ +EXTERN void j_fwd_dct PP((DCTBLOCK data)); +/* inverse DCT */ +EXTERN void j_rev_dct PP((DCTBLOCK data)); + +/* utility routines in jutils.c */ +EXTERN long jround_up PP((long a, long b)); +EXTERN void jcopy_sample_rows PP((JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, long num_cols)); +EXTERN void jcopy_block_row PP((JBLOCKROW input_row, JBLOCKROW output_row, + long num_blocks)); +EXTERN void jzero_far PP((void FAR * target, size_t bytestozero)); + +/* method selection routines for compression modules */ +EXTERN void jselcpipeline PP((compress_info_ptr cinfo)); /* jcpipe.c */ +EXTERN void jselchuffman PP((compress_info_ptr cinfo)); /* jchuff.c */ +EXTERN void jselcarithmetic PP((compress_info_ptr cinfo)); /* jcarith.c */ +EXTERN void jselexpand PP((compress_info_ptr cinfo)); /* jcexpand.c */ +EXTERN void jselsubsample PP((compress_info_ptr cinfo)); /* jcsample.c */ +EXTERN void jselcmcu PP((compress_info_ptr cinfo)); /* jcmcu.c */ +EXTERN void jselccolor PP((compress_info_ptr cinfo)); /* jccolor.c */ +/* The user interface should call one of these to select input format: */ +EXTERN void jselrgif PP((compress_info_ptr cinfo)); /* jrdgif.c */ +EXTERN void jselrppm PP((compress_info_ptr cinfo)); /* jrdppm.c */ +/* and one of these to select output header format: */ +EXTERN void jselwjfif PP((compress_info_ptr cinfo)); /* jwrjfif.c */ + +/* method selection routines for decompression modules */ +EXTERN void jseldpipeline PP((decompress_info_ptr cinfo)); /* jdpipe.c */ +EXTERN void jseldhuffman PP((decompress_info_ptr cinfo)); /* jdhuff.c */ +EXTERN void jseldarithmetic PP((decompress_info_ptr cinfo)); /* jdarith.c */ +EXTERN void jseldmcu PP((decompress_info_ptr cinfo)); /* jdmcu.c */ +EXTERN void jselbsmooth PP((decompress_info_ptr cinfo)); /* jbsmooth.c */ +EXTERN void jselunsubsample PP((decompress_info_ptr cinfo)); /* jdsample.c */ +EXTERN void jseldcolor PP((decompress_info_ptr cinfo)); /* jdcolor.c */ +EXTERN void jsel1quantize PP((decompress_info_ptr cinfo)); /* jquant1.c */ +EXTERN void jsel2quantize PP((decompress_info_ptr cinfo)); /* jquant2.c */ +/* The user interface should call one of these to select input format: */ +EXTERN void jselrjfif PP((decompress_info_ptr cinfo)); /* jrdjfif.c */ +/* and one of these to select output image format: */ +EXTERN void jselwgif PP((decompress_info_ptr cinfo)); /* jwrgif.c */ +EXTERN void jselwppm PP((decompress_info_ptr cinfo)); /* jwrppm.c */ + +/* method selection routines for system-dependent modules */ +EXTERN void jselerror PP((external_methods_ptr emethods)); /* jerror.c */ +EXTERN void jselvirtmem PP((external_methods_ptr emethods)); /* jvirtmem.c */ + +/* debugging hook in jvirtmem.c */ +#ifdef MEM_STATS +EXTERN void j_mem_stats PP((void)); +#endif + +/* Miscellaneous useful macros */ + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + + +#define RST0 0xD0 /* RST0 marker code */ diff --git a/jquant1.c b/jquant1.c new file mode 100644 index 0000000..49dfd97 --- /dev/null +++ b/jquant1.c @@ -0,0 +1,387 @@ +/* + * jquant1.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 1-pass color quantization (color mapping) routines. + * These routines are invoked via the methods color_quantize + * and color_quant_init/term. + */ + +#include "jinclude.h" + +#ifdef QUANT_1PASS_SUPPORTED + + +/* + * This implementation is a fairly dumb, quick-and-dirty quantizer; + * it's here mostly so that we can start working on colormapped output formats. + * + * We quantize to a color map that is selected in advance of seeing the image; + * the map depends only on the requested number of colors (at least 8). + * The map consists of all combinations of Ncolors[j] color values for each + * component j; we choose Ncolors[] based on the requested # of colors. + * We always use 0 and MAXJSAMPLE in each color (hence the minimum 8 colors). + * Any additional color values are equally spaced between these limits. + * + * The result almost always needs dithering to look decent. + */ + +#define MAX_COMPONENTS 4 /* max components I can handle */ + +static int total_colors; /* Number of distinct output colors */ +static int Ncolors[MAX_COMPONENTS]; /* # of values alloced to each component */ +/* total_colors is the product of the Ncolors[] values */ + +static JSAMPARRAY colormap; /* The actual color map */ +/* colormap[i][j] = value of i'th color component for output pixel value j */ + +static JSAMPARRAY colorindex; /* Precomputed mapping for speed */ +/* colorindex[i][j] = index of color closest to pixel value j in component i, + * premultiplied so that the correct mapped value for a pixel (r,g,b) is: + * colorindex[0][r] + colorindex[1][g] + colorindex[2][b] + */ + + +/* Declarations for Floyd-Steinberg dithering. + * Errors are accumulated into the arrays evenrowerrs[] and oddrowerrs[], + * each of which have #colors * (#columns + 2) entries (so that first/last + * pixels need not be special cases). These have resolutions of 1/16th of + * a pixel count. The error at a given pixel is propagated to its unprocessed + * neighbors using the standard F-S fractions, + * ... (here) 7/16 + * 3/16 5/16 1/16 + * We work left-to-right on even rows, right-to-left on odd rows. + * + * Note: on a wide image, we might not have enough room in a PC's near data + * segment to hold the error arrays; so they are allocated with alloc_medium. + */ + +#ifdef EIGHT_BIT_SAMPLES +typedef short FSERROR; /* 16 bits should be enough */ +#else +typedef INT32 FSERROR; /* may need more than 16 bits? */ +#endif + +typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */ + +static FSERRPTR evenrowerrs, oddrowerrs; /* current-row and next-row errors */ +static boolean on_odd_row; /* flag to remember which row we are on */ + + +/* + * Initialize for one-pass color quantization. + */ + +METHODDEF void +color_quant_init (decompress_info_ptr cinfo) +{ + int max_colors = cinfo->desired_number_of_colors; + int i,j,k, ntc, nci, blksize, blkdist, ptr, val; + + if (cinfo->color_out_comps > MAX_COMPONENTS) + ERREXIT1(cinfo->emethods, "Cannot quantize more than %d color components", + MAX_COMPONENTS); + if (max_colors > (MAXJSAMPLE+1)) + ERREXIT1(cinfo->emethods, "Cannot request more than %d quantized colors", + MAXJSAMPLE+1); + + /* Initialize to 2 color values for each component */ + total_colors = 1; + for (i = 0; i < cinfo->color_out_comps; i++) { + Ncolors[i] = 2; + total_colors *= 2; + } + if (total_colors > max_colors) + ERREXIT1(cinfo->emethods, "Cannot quantize to fewer than %d colors", + total_colors); + + /* Increase the number of color values until requested limit is reached. */ + /* Note that for standard RGB color space, we will have at least as many */ + /* red values as green, and at least as many green values as blue. */ + i = 0; /* component index to increase next */ + /* test calculates ntc = new total_colors if Ncolors[i] is incremented */ + while ((ntc = (total_colors / Ncolors[i]) * (Ncolors[i]+1)) <= max_colors) { + Ncolors[i]++; /* OK, apply the increment */ + total_colors = ntc; + i++; /* advance to next component */ + if (i >= cinfo->color_out_comps) i = 0; + } + + /* Report selected color counts */ + if (cinfo->color_out_comps == 3) + TRACEMS4(cinfo->emethods, 1, "Quantizing to %d = %d*%d*%d colors", + total_colors, Ncolors[0], Ncolors[1], Ncolors[2]); + else + TRACEMS1(cinfo->emethods, 1, "Quantizing to %d colors", total_colors); + + /* Allocate and fill in the colormap and color index. */ + /* The colors are ordered in the map in standard row-major order, */ + /* i.e. rightmost (highest-indexed) color changes most rapidly. */ + + colormap = (*cinfo->emethods->alloc_small_sarray) + ((long) total_colors, (long) cinfo->color_out_comps); + colorindex = (*cinfo->emethods->alloc_small_sarray) + ((long) (MAXJSAMPLE+1), (long) cinfo->color_out_comps); + + /* blksize is number of adjacent repeated entries for a component */ + /* blkdist is distance between groups of identical entries for a component */ + blkdist = total_colors; + + for (i = 0; i < cinfo->color_out_comps; i++) { + /* fill in colormap entries for i'th color component */ + nci = Ncolors[i]; /* # of distinct values for this color */ + blksize = blkdist / nci; + for (j = 0; j < nci; j++) { + val = (j * MAXJSAMPLE + (nci-1)/2) / (nci-1); /* j'th value of color */ + for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) { + /* fill in blksize entries beginning at ptr */ + for (k = 0; k < blksize; k++) + colormap[i][ptr+k] = val; + } + } + blkdist = blksize; /* blksize of this color is blkdist of next */ + + /* fill in colorindex entries for i'th color component */ + for (j = 0; j <= MAXJSAMPLE; j++) { + /* compute index of color closest to pixel value j */ + val = (j * (nci-1) + CENTERJSAMPLE) / MAXJSAMPLE; + /* premultiply so that no multiplication needed in main processing */ + val *= blksize; + colorindex[i][j] = val; + } + } + + /* Pass the colormap to the output module. Note that the output */ + /* module is allowed to save this pointer and use the map during */ + /* any put_pixel_rows call! */ + (*cinfo->methods->put_color_map) (cinfo, total_colors, colormap); + + /* Allocate Floyd-Steinberg workspace if necessary */ + if (cinfo->use_dithering) { + size_t arraysize = (cinfo->image_width + 2L) * cinfo->color_out_comps + * SIZEOF(FSERROR); + + evenrowerrs = (FSERRPTR) (*cinfo->emethods->alloc_medium) (arraysize); + oddrowerrs = (FSERRPTR) (*cinfo->emethods->alloc_medium) (arraysize); + /* we only need to zero the forward contribution for current row. */ + jzero_far((void FAR *) evenrowerrs, arraysize); + on_odd_row = FALSE; + } + +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +METHODDEF void +color_quantize (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE input_data, JSAMPARRAY output_data) +/* General case, no dithering */ +{ + register int pixcode, ci; + register long col; + register int row; + register long widthm1 = cinfo->image_width - 1; + register int nc = cinfo->color_out_comps; + + for (row = 0; row < num_rows; row++) { + for (col = widthm1; col >= 0; col--) { + pixcode = 0; + for (ci = 0; ci < nc; ci++) { + pixcode += GETJSAMPLE(colorindex[ci] + [GETJSAMPLE(input_data[ci][row][col])]); + } + output_data[row][col] = pixcode; + } + } +} + + +METHODDEF void +color_quantize3 (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE input_data, JSAMPARRAY output_data) +/* Fast path for color_out_comps==3, no dithering */ +{ + register int pixcode; + register JSAMPROW ptr0, ptr1, ptr2, ptrout; + register long col; + register int row; + register long width = cinfo->image_width; + + for (row = 0; row < num_rows; row++) { + ptr0 = input_data[0][row]; + ptr1 = input_data[1][row]; + ptr2 = input_data[2][row]; + ptrout = output_data[row]; + for (col = width; col > 0; col--) { + pixcode = GETJSAMPLE(colorindex[0][GETJSAMPLE(*ptr0++)]); + pixcode += GETJSAMPLE(colorindex[1][GETJSAMPLE(*ptr1++)]); + pixcode += GETJSAMPLE(colorindex[2][GETJSAMPLE(*ptr2++)]); + *ptrout++ = pixcode; + } + } +} + + +METHODDEF void +color_quantize_dither (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE input_data, JSAMPARRAY output_data) +/* General case, with Floyd-Steinberg dithering */ +{ + register int pixcode, ci; + register FSERROR val; + register FSERRPTR thisrowerr, nextrowerr; + register long col; + register int row; + register long width = cinfo->image_width; + register int nc = cinfo->color_out_comps; + + for (row = 0; row < num_rows; row++) { + if (on_odd_row) { + /* work right to left in this row */ + thisrowerr = oddrowerrs + width*nc; + nextrowerr = evenrowerrs + width*nc; + for (ci = 0; ci < nc; ci++) /* need only initialize this one entry */ + nextrowerr[ci] = 0; + for (col = width - 1; col >= 0; col--) { + /* select the output pixel value */ + pixcode = 0; + for (ci = 0; ci < nc; ci++) { + /* compute pixel value + accumulated error */ + val = (((FSERROR) GETJSAMPLE(input_data[ci][row][col])) << 4) + + thisrowerr[ci]; + if (val < 0) val = 0; /* must watch for range overflow! */ + else { + val += 8; /* divide by 16 with proper rounding */ + val >>= 4; + if (val > MAXJSAMPLE) val = MAXJSAMPLE; + } + thisrowerr[ci] = val; /* save for error propagation */ + pixcode += GETJSAMPLE(colorindex[ci][val]); + } + output_data[row][col] = pixcode; + /* propagate error to adjacent pixels */ + for (ci = 0; ci < nc; ci++) { + val = thisrowerr[ci] - GETJSAMPLE(colormap[ci][pixcode]); + thisrowerr[ci-nc] += val * 7; + nextrowerr[ci+nc] += val * 3; + nextrowerr[ci ] += val * 5; + nextrowerr[ci-nc] = val; /* not +=, since not initialized yet */ + } + thisrowerr -= nc; /* advance error ptrs to next pixel entry */ + nextrowerr -= nc; + } + on_odd_row = FALSE; + } else { + /* work left to right in this row */ + thisrowerr = evenrowerrs + nc; + nextrowerr = oddrowerrs + nc; + for (ci = 0; ci < nc; ci++) /* need only initialize this one entry */ + nextrowerr[ci] = 0; + for (col = 0; col < width; col++) { + /* select the output pixel value */ + pixcode = 0; + for (ci = 0; ci < nc; ci++) { + /* compute pixel value + accumulated error */ + val = (((FSERROR) GETJSAMPLE(input_data[ci][row][col])) << 4) + + thisrowerr[ci]; + if (val < 0) val = 0; /* must watch for range overflow! */ + else { + val += 8; /* divide by 16 with proper rounding */ + val >>= 4; + if (val > MAXJSAMPLE) val = MAXJSAMPLE; + } + thisrowerr[ci] = val; /* save for error propagation */ + pixcode += GETJSAMPLE(colorindex[ci][val]); + } + output_data[row][col] = pixcode; + /* propagate error to adjacent pixels */ + for (ci = 0; ci < nc; ci++) { + val = thisrowerr[ci] - GETJSAMPLE(colormap[ci][pixcode]); + thisrowerr[ci+nc] += val * 7; + nextrowerr[ci-nc] += val * 3; + nextrowerr[ci ] += val * 5; + nextrowerr[ci+nc] = val; /* not +=, since not initialized yet */ + } + thisrowerr += nc; /* advance error ptrs to next pixel entry */ + nextrowerr += nc; + } + on_odd_row = TRUE; + } + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +color_quant_term (decompress_info_ptr cinfo) +{ + /* We can't free the colormap until now, since output module may use it! */ + (*cinfo->emethods->free_small_sarray) + (colormap, (long) cinfo->color_out_comps); + (*cinfo->emethods->free_small_sarray) + (colorindex, (long) cinfo->color_out_comps); + if (cinfo->use_dithering) { + (*cinfo->emethods->free_medium) ((void FAR *) evenrowerrs); + (*cinfo->emethods->free_medium) ((void FAR *) oddrowerrs); + } +} + + +/* + * Prescan some rows of pixels. + * Not used in one-pass case. + */ + +METHODDEF void +color_quant_prescan (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE image_data) +{ + ERREXIT(cinfo->emethods, "Should not get here!"); +} + + +/* + * Do two-pass quantization. + * Not used in one-pass case. + */ + +METHODDEF void +color_quant_doit (decompress_info_ptr cinfo, quantize_caller_ptr source_method) +{ + ERREXIT(cinfo->emethods, "Should not get here!"); +} + + +/* + * The method selection routine for 1-pass color quantization. + */ + +GLOBAL void +jsel1quantize (decompress_info_ptr cinfo) +{ + if (! cinfo->two_pass_quantize) { + cinfo->methods->color_quant_init = color_quant_init; + if (cinfo->use_dithering) { + cinfo->methods->color_quantize = color_quantize_dither; + } else { + if (cinfo->color_out_comps == 3) + cinfo->methods->color_quantize = color_quantize3; + else + cinfo->methods->color_quantize = color_quantize; + } + cinfo->methods->color_quant_prescan = color_quant_prescan; + cinfo->methods->color_quant_doit = color_quant_doit; + cinfo->methods->color_quant_term = color_quant_term; + } +} + +#endif /* QUANT_1PASS_SUPPORTED */ diff --git a/jquant2.c b/jquant2.c new file mode 100644 index 0000000..2569b20 --- /dev/null +++ b/jquant2.c @@ -0,0 +1,122 @@ +/* + * jquant2.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 2-pass color quantization (color mapping) routines. + * These routines are invoked via the methods color_quant_prescan, + * color_quant_doit, and color_quant_init/term. + */ + +#include "jinclude.h" + +#ifdef QUANT_2PASS_SUPPORTED + + +/* + * Initialize for two-pass color quantization. + */ + +METHODDEF void +color_quant_init (decompress_info_ptr cinfo) +{ + TRACEMS(cinfo->emethods, 1, "color_quant_init 2 pass"); +} + + +/* + * Prescan some rows of pixels. + * Note: this could change the data being written into the big image array, + * if there were any benefit to doing so. The doit routine is not allowed + * to modify the big image array, because the memory manager is not required + * to support multiple write passes on a big image. + */ + +METHODDEF void +color_quant_prescan (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE image_data) +{ + TRACEMS1(cinfo->emethods, 2, "color_quant_prescan %d rows", num_rows); +} + + +/* + * This routine makes the final pass over the image data. + * output_workspace is a one-component array of pixel dimensions at least + * as large as the input image strip; it can be used to hold the converted + * pixels' colormap indexes. + */ + +METHODDEF void +final_pass (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE image_data, JSAMPARRAY output_workspace) +{ + TRACEMS1(cinfo->emethods, 2, "final_pass %d rows", num_rows); + /* for debug purposes, just emit input data */ + /* NB: this only works for PPM output */ + (*cinfo->methods->put_pixel_rows) (cinfo, num_rows, image_data); +} + + +/* + * Perform two-pass quantization: rescan the image data and output the + * converted data via put_color_map and put_pixel_rows. + * The source_method is a routine that can scan the image data; it can + * be called as many times as desired. The processing routine called by + * source_method has the same interface as color_quantize does in the + * one-pass case, except it must call put_pixel_rows itself. (This allows + * me to use multiple passes in which earlier passes don't output anything.) + */ + +METHODDEF void +color_quant_doit (decompress_info_ptr cinfo, quantize_caller_ptr source_method) +{ + TRACEMS(cinfo->emethods, 1, "color_quant_doit 2 pass"); + (*source_method) (cinfo, final_pass); +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +color_quant_term (decompress_info_ptr cinfo) +{ + TRACEMS(cinfo->emethods, 1, "color_quant_term 2 pass"); +} + + +/* + * Map some rows of pixels to the output colormapped representation. + * Not used in two-pass case. + */ + +METHODDEF void +color_quantize (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE input_data, JSAMPARRAY output_data) +{ + ERREXIT(cinfo->emethods, "Should not get here!"); +} + + +/* + * The method selection routine for 2-pass color quantization. + */ + +GLOBAL void +jsel2quantize (decompress_info_ptr cinfo) +{ + if (cinfo->two_pass_quantize) { + /* just one alternative for the moment */ + cinfo->methods->color_quant_init = color_quant_init; + cinfo->methods->color_quant_prescan = color_quant_prescan; + cinfo->methods->color_quant_doit = color_quant_doit; + cinfo->methods->color_quant_term = color_quant_term; + cinfo->methods->color_quantize = color_quantize; + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ diff --git a/jrdgif.c b/jrdgif.c new file mode 100644 index 0000000..e2d4b33 --- /dev/null +++ b/jrdgif.c @@ -0,0 +1,620 @@ +/* + * jrdgif.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in GIF format. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume input from + * an ordinary stdio stream. They further assume that reading begins + * at the start of the file; input_init may need work if the + * user interface has already read some data (e.g., to determine that + * the file is indeed GIF format). + * + * These routines are invoked via the methods get_input_row + * and input_init/term. + */ + +/* + * This code is loosely based on giftoppm from the PBMPLUS distribution + * of Feb. 1991. That file contains the following copyright notice: + * +-------------------------------------------------------------------+ + * | Copyright 1990, David Koblas. | + * | 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. | + * +-------------------------------------------------------------------+ + * + * We are also required to state that + * "The Graphics Interchange Format(c) is the Copyright property of + * CompuServe Incorporated. GIF(sm) is a Service Mark property of + * CompuServe Incorporated." + */ + +#include "jinclude.h" + +#ifdef GIF_SUPPORTED + + +#define MAXCOLORMAPSIZE 256 /* max # of colors in a GIF colormap */ +#define NUMCOLORS 3 /* # of colors */ +#define CM_RED 0 /* color component numbers */ +#define CM_GREEN 1 +#define CM_BLUE 2 + +static JSAMPARRAY colormap; /* the colormap to use */ +/* colormap[i][j] = value of i'th color component for pixel value j */ + +#define MAX_LZW_BITS 12 /* maximum LZW code size */ +#define LZW_TABLE_SIZE (1< table of prefix symbols */ +static UINT8 FAR *symbol_tail; /* => table of suffix bytes */ +static UINT8 FAR *symbol_stack; /* stack for symbol expansions */ +static UINT8 FAR *sp; /* stack pointer */ + +/* Static state for interlaced image processing */ + +static boolean is_interlaced; /* TRUE if have interlaced image */ +static big_sarray_ptr interlaced_image; /* full image in interlaced order */ +static long cur_row_number; /* need to know actual row number */ +static long pass2_offset; /* # of pixel rows in pass 1 */ +static long pass3_offset; /* # of pixel rows in passes 1&2 */ +static long pass4_offset; /* # of pixel rows in passes 1,2,3 */ + + +/* Forward declarations */ +METHODDEF void load_interlaced_image PP((compress_info_ptr cinfo, JSAMPARRAY pixel_row)); +METHODDEF void get_interlaced_row PP((compress_info_ptr cinfo, JSAMPARRAY pixel_row)); + + + +LOCAL int +ReadByte (compress_info_ptr cinfo) +/* Read next byte from GIF file */ +{ + register FILE * infile = cinfo->input_file; + int c; + + if ((c = getc(infile)) == EOF) + ERREXIT(cinfo->emethods, "Premature EOF in GIF file"); + return c; +} + + +LOCAL int +GetDataBlock (compress_info_ptr cinfo, char *buf) +/* Read a GIF data block, which has a leading count byte */ +/* A zero-length block marks the end of a data block sequence */ +{ + int count; + + count = ReadByte(cinfo); + if (count > 0) { + if (! ReadOK(cinfo->input_file, buf, count)) + ERREXIT(cinfo->emethods, "Premature EOF in GIF file"); + } + return count; +} + + +LOCAL void +SkipDataBlocks (compress_info_ptr cinfo) +/* Skip a series of data blocks, until a block terminator is found */ +{ + char buf[256]; + + while (GetDataBlock(cinfo, buf) > 0) + /* skip */; +} + + +LOCAL void +ReInitLZW (void) +/* (Re)initialize LZW state; shared code for startup and Clear processing */ +{ + code_size = input_code_size+1; + limit_code = clear_code << 1; /* 2^code_size */ + max_code = clear_code + 2; /* first unused code value */ + sp = symbol_stack; /* init stack to empty */ +} + + +LOCAL void +InitLZWCode (void) +/* Initialize for a series of LZWReadByte (and hence GetCode) calls */ +{ + /* GetCode initialization */ + last_byte = 2; /* make safe to "recopy last two bytes" */ + last_bit = 0; /* nothing in the buffer */ + cur_bit = 0; /* force buffer load on first call */ + out_of_blocks = FALSE; + + /* LZWReadByte initialization */ + clear_code = 1 << input_code_size; /* compute special code values */ + end_code = clear_code + 1; /* note that these do not change */ + first_time = TRUE; + ReInitLZW(); +} + + +LOCAL int +GetCode (compress_info_ptr cinfo) +/* Fetch the next code_size bits from the GIF data */ +/* We assume code_size is less than 16 */ +{ + register INT32 accum; + int offs, ret, count; + + if ( (cur_bit+code_size) > last_bit) { + /* Time to reload the buffer */ + if (out_of_blocks) { + TRACEMS(cinfo->emethods, 1, "Ran out of GIF bits"); + return end_code; /* fake something useful */ + } + /* preserve last two bytes of what we have -- assume code_size <= 16 */ + code_buf[0] = code_buf[last_byte-2]; + code_buf[1] = code_buf[last_byte-1]; + /* Load more bytes; set flag if we reach the terminator block */ + if ((count = GetDataBlock(cinfo, &code_buf[2])) == 0) { + out_of_blocks = TRUE; + TRACEMS(cinfo->emethods, 1, "Ran out of GIF bits"); + return end_code; /* fake something useful */ + } + /* Reset counters */ + cur_bit = (cur_bit - last_bit) + 16; + last_byte = 2 + count; + last_bit = last_byte * 8; + } + + /* Form up next 24 bits in accum */ + offs = cur_bit >> 3; /* byte containing cur_bit */ +#ifdef CHAR_IS_UNSIGNED + accum = code_buf[offs+2]; + accum <<= 8; + accum |= code_buf[offs+1]; + accum <<= 8; + accum |= code_buf[offs]; +#else + accum = code_buf[offs+2] & 0xFF; + accum <<= 8; + accum |= code_buf[offs+1] & 0xFF; + accum <<= 8; + accum |= code_buf[offs] & 0xFF; +#endif + + /* Right-align cur_bit in accum, then mask off desired number of bits */ + accum >>= (cur_bit & 7); + ret = ((int) accum) & ((1 << code_size) - 1); + + cur_bit += code_size; + return ret; +} + + +LOCAL int +LZWReadByte (compress_info_ptr cinfo) +/* Read an LZW-compressed byte */ +{ + static int oldcode; /* previous LZW symbol */ + static int firstcode; /* first byte of oldcode's expansion */ + register int code; /* current working code */ + int incode; /* saves actual input code */ + + /* First time, just eat the expected Clear code(s) and return next code, */ + /* which is assumed to be a raw byte. */ + if (first_time) { + first_time = FALSE; + do { + code = GetCode(cinfo); + } while (code == clear_code); + firstcode = oldcode = code; /* make firstcode, oldcode valid! */ + return code; + } + + /* If any codes are stacked from a previously read symbol, return them */ + if (sp > symbol_stack) + return *(--sp); + + code = GetCode(cinfo); + + if (code == clear_code) { + /* Reinit static state, swallow any extra Clear codes, and return */ + ReInitLZW(); + do { + code = GetCode(cinfo); + } while (code == clear_code); + firstcode = oldcode = code; /* gotta reinit these too */ + return code; + } + + if (code == end_code) { + /* Skip the rest of the image, unless GetCode already read terminator */ + if (! out_of_blocks) + SkipDataBlocks(cinfo); + return -1; + } + + /* Normal raw byte or LZW symbol */ + incode = code; /* save for a moment */ + + if (code >= max_code) { /* special case for not-yet-defined symbol */ + *sp++ = firstcode; /* it will be defined as oldcode/firstcode */ + code = oldcode; + } + + /* If it's a symbol, expand it into the stack */ + while (code >= clear_code) { + *sp++ = symbol_tail[code]; /* tail of symbol: a simple byte value */ + code = symbol_head[code]; /* head of symbol: another LZW symbol */ + } + /* At this point code just represents a raw byte */ + firstcode = code; /* save for possible future use */ + + /* If there's room in table, */ + if ((code = max_code) < LZW_TABLE_SIZE) { + /* Define a new symbol = prev sym + head of this sym's expansion */ + symbol_head[code] = oldcode; + symbol_tail[code] = firstcode; + max_code++; + /* Is it time to increase code_size? */ + if ((max_code >= limit_code) && (code_size < MAX_LZW_BITS)) { + code_size++; + limit_code <<= 1; /* keep equal to 2^code_size */ + } + } + + oldcode = incode; /* save last input symbol for future use */ + return firstcode; /* return first byte of symbol's expansion */ +} + + +LOCAL void +ReadColorMap (compress_info_ptr cinfo, int cmaplen, JSAMPARRAY cmap) +/* Read a GIF colormap */ +{ + int i; + + for (i = 0; i < cmaplen; i++) { + cmap[CM_RED][i] = ReadByte(cinfo); + cmap[CM_GREEN][i] = ReadByte(cinfo); + cmap[CM_BLUE][i] = ReadByte(cinfo); + } +} + + +LOCAL void +DoExtension (compress_info_ptr cinfo) +/* Process an extension block */ +/* Currently we ignore 'em all */ +{ + int extlabel; + + /* Read extension label byte */ + extlabel = ReadByte(cinfo); + TRACEMS1(cinfo->emethods, 1, "Ignoring GIF extension block of type 0x%02x", + extlabel); + /* Skip the data block(s) associated with the extension */ + SkipDataBlocks(cinfo); +} + + +/* + * Read the file header; return image size and component count. + */ + +METHODDEF void +input_init (compress_info_ptr cinfo) +{ + char hdrbuf[10]; /* workspace for reading control blocks */ + UINT16 width, height; /* image dimensions */ + int colormaplen, aspectRatio; + int c; + + /* Allocate space to store the colormap */ + colormap = (*cinfo->emethods->alloc_small_sarray) + ((long) MAXCOLORMAPSIZE, (long) NUMCOLORS); + + /* Read and verify GIF Header */ + if (! ReadOK(cinfo->input_file, hdrbuf, 6)) + ERREXIT(cinfo->emethods, "Not a GIF file"); + if (strncmp(hdrbuf, "GIF", 3) != 0) + ERREXIT(cinfo->emethods, "Not a GIF file"); + /* Check for expected version numbers. + * If unknown version, give warning and try to process anyway; + * this is per recommendation in GIF89a standard. + */ + if ((strncmp(hdrbuf+3, "87a", 3) != 0) && + (strncmp(hdrbuf+3, "89a", 3) != 0)) + TRACEMS3(cinfo->emethods, 1, + "Warning: unexpected GIF version number '%c%c%c'", + hdrbuf[3], hdrbuf[4], hdrbuf[5]); + + /* Read and decipher Logical Screen Descriptor */ + if (! ReadOK(cinfo->input_file, hdrbuf, 7)) + ERREXIT(cinfo->emethods, "Premature EOF in GIF file"); + width = LM_to_uint(hdrbuf[0],hdrbuf[1]); + height = LM_to_uint(hdrbuf[2],hdrbuf[3]); + colormaplen = 2 << (hdrbuf[4] & 0x07); + /* we ignore the color resolution, sort flag, and background color index */ + aspectRatio = hdrbuf[6] & 0xFF; + if (aspectRatio != 0 && aspectRatio != 49) + TRACEMS(cinfo->emethods, 1, "Warning: nonsquare pixels in input"); + + /* Read global colormap if header indicates it is present */ + if (BitSet(hdrbuf[4], COLORMAPFLAG)) + ReadColorMap(cinfo, colormaplen, colormap); + + /* Scan until we reach start of desired image. + * We don't currently support skipping images, but could add it easily. + */ + for (;;) { + c = ReadByte(cinfo); + + if (c == ';') /* GIF terminator?? */ + ERREXIT(cinfo->emethods, "Too few images in GIF file"); + + if (c == '!') { /* Extension */ + DoExtension(cinfo); + continue; + } + + if (c != ',') { /* Not an image separator? */ + TRACEMS1(cinfo->emethods, 1, "Bogus input char 0x%02x, ignoring", c); + continue; + } + + /* Read and decipher Local Image Descriptor */ + if (! ReadOK(cinfo->input_file, hdrbuf, 9)) + ERREXIT(cinfo->emethods, "Premature EOF in GIF file"); + /* we ignore top/left position info, also sort flag */ + width = LM_to_uint(hdrbuf[4],hdrbuf[5]); + height = LM_to_uint(hdrbuf[6],hdrbuf[7]); + is_interlaced = BitSet(hdrbuf[8], INTERLACE); + colormaplen = 2 << (hdrbuf[8] & 0x07); + + /* Read local colormap if header indicates it is present */ + /* Note: if we wanted to support skipping images, */ + /* we'd need to skip rather than read colormap for ignored images */ + if (BitSet(hdrbuf[8], COLORMAPFLAG)) + ReadColorMap(cinfo, colormaplen, colormap); + + input_code_size = ReadByte(cinfo); /* get minimum-code-size byte */ + if (input_code_size < 2 || input_code_size >= MAX_LZW_BITS) + ERREXIT1(cinfo->emethods, "Bogus codesize %d", input_code_size); + + /* Reached desired image, so break out of loop */ + /* If we wanted to skip this image, */ + /* we'd call SkipDataBlocks and then continue the loop */ + break; + } + + /* Prepare to read selected image: first initialize LZW decompressor */ + symbol_head = (UINT16 FAR *) (*cinfo->emethods->alloc_medium) + (LZW_TABLE_SIZE * SIZEOF(UINT16)); + symbol_tail = (UINT8 FAR *) (*cinfo->emethods->alloc_medium) + (LZW_TABLE_SIZE * SIZEOF(UINT8)); + symbol_stack = (UINT8 FAR *) (*cinfo->emethods->alloc_medium) + (LZW_TABLE_SIZE * SIZEOF(UINT8)); + InitLZWCode(); + + /* + * If image is interlaced, we read it into a full-size sample array, + * decompressing as we go; then get_input_row selects rows from the + * sample array in the proper order. + */ + if (is_interlaced) { + /* We request the big array now, but can't access it until the pipeline + * controller causes all the big arrays to be allocated. Hence, the + * actual work of reading the image is postponed until the first call + * of get_input_row. + */ + interlaced_image = (*cinfo->emethods->request_big_sarray) + ((long) width, (long) height, (long) 1); + cinfo->methods->get_input_row = load_interlaced_image; + } + + /* Return info about the image. */ + cinfo->input_components = NUMCOLORS; + cinfo->in_color_space = CS_RGB; + cinfo->image_width = width; + cinfo->image_height = height; + cinfo->data_precision = 8; +} + + +/* + * Read one row of pixels. + * This version is used for noninterlaced GIF images: + * we read directly from the GIF file. + */ + +METHODDEF void +get_input_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row) +{ + register JSAMPROW ptr0, ptr1, ptr2; + register long col; + register int c; + + ptr0 = pixel_row[0]; + ptr1 = pixel_row[1]; + ptr2 = pixel_row[2]; + for (col = cinfo->image_width; col > 0; col--) { + if ((c = LZWReadByte(cinfo)) < 0) + ERREXIT(cinfo->emethods, "Premature end of GIF image"); + *ptr0++ = colormap[CM_RED][c]; + *ptr1++ = colormap[CM_GREEN][c]; + *ptr2++ = colormap[CM_BLUE][c]; + } +} + + +/* + * Read one row of pixels. + * This version is used for the first call on get_input_row when + * reading an interlaced GIF file: we read the whole image into memory. + */ + +METHODDEF void +load_interlaced_image (compress_info_ptr cinfo, JSAMPARRAY pixel_row) +{ + JSAMPARRAY image_ptr; + register JSAMPROW sptr; + register long col; + register int c; + long row; + + /* Read the interlaced image into the big array we've created. */ + for (row = 0; row < cinfo->image_height; row++) { + image_ptr = (*cinfo->emethods->access_big_sarray) + (interlaced_image, row, TRUE); + sptr = image_ptr[0]; + for (col = cinfo->image_width; col > 0; col--) { + if ((c = LZWReadByte(cinfo)) < 0) + ERREXIT(cinfo->emethods, "Premature end of GIF image"); + *sptr++ = c; + } + } + + /* Replace method pointer so subsequent calls don't come here. */ + cinfo->methods->get_input_row = get_interlaced_row; + /* Initialize for get_interlaced_row, and perform first call on it. */ + cur_row_number = 0; + pass2_offset = (cinfo->image_height + 7L) / 8L; + pass3_offset = pass2_offset + (cinfo->image_height + 3L) / 8L; + pass4_offset = pass3_offset + (cinfo->image_height + 1L) / 4L; + + get_interlaced_row(cinfo, pixel_row); +} + + +/* + * Read one row of pixels. + * This version is used for interlaced GIF images: + * we read from the big in-memory image. + */ + +METHODDEF void +get_interlaced_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row) +{ + JSAMPARRAY image_ptr; + register JSAMPROW sptr, ptr0, ptr1, ptr2; + register long col; + register int c; + long irow; + + /* Figure out which row of interlaced image is needed, and access it. */ + switch ((int) (cur_row_number & 7L)) { + case 0: /* first-pass row */ + irow = cur_row_number >> 3; + break; + case 4: /* second-pass row */ + irow = (cur_row_number >> 3) + pass2_offset; + break; + case 2: /* third-pass row */ + case 6: + irow = (cur_row_number >> 2) + pass3_offset; + break; + default: /* fourth-pass row */ + irow = (cur_row_number >> 1) + pass4_offset; + break; + } + image_ptr = (*cinfo->emethods->access_big_sarray) + (interlaced_image, irow, FALSE); + /* Scan the row, expand colormap, and output */ + sptr = image_ptr[0]; + ptr0 = pixel_row[0]; + ptr1 = pixel_row[1]; + ptr2 = pixel_row[2]; + for (col = cinfo->image_width; col > 0; col--) { + c = GETJSAMPLE(*sptr++); + *ptr0++ = colormap[CM_RED][c]; + *ptr1++ = colormap[CM_GREEN][c]; + *ptr2++ = colormap[CM_BLUE][c]; + } + cur_row_number++; /* for next time */ +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +input_term (compress_info_ptr cinfo) +{ + if (is_interlaced) { + (*cinfo->emethods->free_big_sarray) (interlaced_image); + } + (*cinfo->emethods->free_small_sarray) + (colormap, (long) NUMCOLORS); + (*cinfo->emethods->free_medium) ((void FAR *) symbol_head); + (*cinfo->emethods->free_medium) ((void FAR *) symbol_tail); + (*cinfo->emethods->free_medium) ((void FAR *) symbol_stack); +} + + +/* + * The method selection routine for GIF format input. + * Note that this must be called by the user interface before calling + * jpeg_compress. If multiple input formats are supported, the + * user interface is responsible for discovering the file format and + * calling the appropriate method selection routine. + */ + +GLOBAL void +jselrgif (compress_info_ptr cinfo) +{ + cinfo->methods->input_init = input_init; + cinfo->methods->get_input_row = get_input_row; /* assume uninterlaced */ + cinfo->methods->input_term = input_term; +} + +#endif /* GIF_SUPPORTED */ diff --git a/jrdjfif.c b/jrdjfif.c new file mode 100644 index 0000000..5ff14ba --- /dev/null +++ b/jrdjfif.c @@ -0,0 +1,733 @@ +/* + * jrdjfif.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to decode standard JPEG file headers/markers. + * This will handle baseline and JFIF-convention JPEG files. + * + * This module relies on the JGETC macro and the read_jpeg_data method (which + * is provided by the user interface) to read from the JPEG data stream. + * Therefore, this module is NOT dependent on any particular assumption about + * the data source. This fact does not carry over to more complex JPEG file + * formats such as JPEG-in-TIFF; those format control modules may well need to + * assume stdio input. + * + * read_file_header assumes that reading begins at the JPEG SOI marker + * (although it will skip non-FF bytes looking for a JPEG marker). + * The user interface must position the data stream appropriately. + * + * These routines are invoked via the methods read_file_header, + * read_scan_header, read_jpeg_data, read_scan_trailer, and read_file_trailer. + */ + +#include "jinclude.h" + +#ifdef JFIF_SUPPORTED + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* + * Reload the input buffer after it's been emptied, and return the next byte. + * This is exported for direct use by the entropy decoder. + * See the JGETC macro for calling conditions. + * + * For this header control module, read_jpeg_data is supplied by the + * user interface. However, header formats that require random access + * to the input file would need to supply their own code. This code is + * left here to indicate what is required. + */ + +#if 0 /* not needed in this module */ + +METHODDEF int +read_jpeg_data (decompress_info_ptr cinfo) +{ + cinfo->bytes_in_buffer = fread(cinfo->input_buffer + MIN_UNGET, + 1, JPEG_BUF_SIZE, + cinfo->input_file); + + cinfo->next_input_byte = cinfo->input_buffer + MIN_UNGET; + + if (cinfo->bytes_in_buffer <= 0) + ERREXIT(cinfo->emethods, "Unexpected EOF in JPEG file"); + + return JGETC(cinfo); +} + +#endif + + +/* + * Routines to parse JPEG markers & save away the useful info. + */ + + +LOCAL INT32 +get_2bytes (decompress_info_ptr cinfo) +/* Get a 2-byte unsigned integer (e.g., a marker parameter length field) */ +{ + INT32 a; + + a = JGETC(cinfo); + return (a << 8) + JGETC(cinfo); +} + + +LOCAL void +skip_variable (decompress_info_ptr cinfo, int code) +/* Skip over an unknown or uninteresting variable-length marker */ +{ + INT32 length; + + length = get_2bytes(cinfo); + + TRACEMS2(cinfo->emethods, 1, + "Skipping marker 0x%02x, length %d", code, length); + + for (length -= 2; length > 0; length--) + (void) JGETC(cinfo); +} + + +LOCAL void +get_dht (decompress_info_ptr cinfo) +/* Process a DHT marker */ +{ + INT32 length; + UINT8 bits[17]; + UINT8 huffval[256]; + int i, index, count; + HUFF_TBL **htblptr; + + length = get_2bytes(cinfo)-2; + + while (length > 0) { + index = JGETC(cinfo); + + TRACEMS1(cinfo->emethods, 1, "Define Huffman Table 0x%02x", index); + + bits[0] = 0; + count = 0; + for (i = 1; i <= 16; i++) { + bits[i] = JGETC(cinfo); + count += bits[i]; + } + + TRACEMS8(cinfo->emethods, 2, " %3d %3d %3d %3d %3d %3d %3d %3d", + bits[1], bits[2], bits[3], bits[4], + bits[5], bits[6], bits[7], bits[8]); + TRACEMS8(cinfo->emethods, 2, " %3d %3d %3d %3d %3d %3d %3d %3d", + bits[9], bits[10], bits[11], bits[12], + bits[13], bits[14], bits[15], bits[16]); + + if (count > 256) + ERREXIT(cinfo->emethods, "Bogus DHT counts"); + + for (i = 0; i < count; i++) + huffval[i] = JGETC(cinfo); + + length -= 1 + 16 + count; + + if (index & 0x10) { /* AC table definition */ + index -= 0x10; + htblptr = &cinfo->ac_huff_tbl_ptrs[index]; + } else { /* DC table definition */ + htblptr = &cinfo->dc_huff_tbl_ptrs[index]; + } + + if (index < 0 || index >= NUM_HUFF_TBLS) + ERREXIT1(cinfo->emethods, "Bogus DHT index %d", index); + + if (*htblptr == NULL) + *htblptr = (*cinfo->emethods->alloc_small) (SIZEOF(HUFF_TBL)); + + memcpy((void *) (*htblptr)->bits, (void *) bits, + SIZEOF((*htblptr)->bits)); + memcpy((void *) (*htblptr)->huffval, (void *) huffval, + SIZEOF((*htblptr)->huffval)); + } +} + + +LOCAL void +get_dac (decompress_info_ptr cinfo) +/* Process a DAC marker */ +{ + INT32 length; + int index, val; + + length = get_2bytes(cinfo)-2; + + while (length > 0) { + index = JGETC(cinfo); + val = JGETC(cinfo); + + TRACEMS2(cinfo->emethods, 1, + "Define Arithmetic Table 0x%02x: 0x%02x", index, val); + + if (index < 0 || index >= (2*NUM_ARITH_TBLS)) + ERREXIT1(cinfo->emethods, "Bogus DAC index %d", index); + + if (index >= NUM_ARITH_TBLS) { /* define AC table */ + cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = val; + } else { /* define DC table */ + cinfo->arith_dc_L[index] = val & 0x0F; + cinfo->arith_dc_U[index] = val >> 4; + if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index]) + ERREXIT1(cinfo->emethods, "Bogus DAC value 0x%x", val); + } + + length -= 2; + } +} + + +LOCAL void +get_dqt (decompress_info_ptr cinfo) +/* Process a DQT marker */ +{ + INT32 length; + int n, i, prec; + UINT16 tmp; + QUANT_TBL_PTR quant_ptr; + + length = get_2bytes(cinfo) - 2; + + while (length > 0) { + n = JGETC(cinfo); + prec = n >> 4; + n &= 0x0F; + + TRACEMS2(cinfo->emethods, 1, + "Define Quantization Table %d precision %d", n, prec); + + if (n >= NUM_QUANT_TBLS) + ERREXIT1(cinfo->emethods, "Bogus table number %d", n); + + if (cinfo->quant_tbl_ptrs[n] == NULL) + cinfo->quant_tbl_ptrs[n] = (*cinfo->emethods->alloc_small) (SIZEOF(QUANT_TBL)); + quant_ptr = cinfo->quant_tbl_ptrs[n]; + + for (i = 0; i < DCTSIZE2; i++) { + tmp = JGETC(cinfo); + if (prec) + tmp = (tmp<<8) + JGETC(cinfo); + quant_ptr[i] = tmp; + } + + for (i = 0; i < DCTSIZE2; i += 8) { + TRACEMS8(cinfo->emethods, 2, " %4d %4d %4d %4d %4d %4d %4d %4d", + quant_ptr[i ], quant_ptr[i+1], quant_ptr[i+2], quant_ptr[i+3], + quant_ptr[i+4], quant_ptr[i+5], quant_ptr[i+6], quant_ptr[i+7]); + } + + length -= DCTSIZE2+1; + if (prec) length -= DCTSIZE2; + } +} + + +LOCAL void +get_dri (decompress_info_ptr cinfo) +/* Process a DRI marker */ +{ + if (get_2bytes(cinfo) != 4) + ERREXIT(cinfo->emethods, "Bogus length in DRI"); + + cinfo->restart_interval = get_2bytes(cinfo); + + TRACEMS1(cinfo->emethods, 1, + "Define Restart Interval %d", cinfo->restart_interval); +} + + +LOCAL void +get_app0 (decompress_info_ptr cinfo) +/* Process an APP0 marker */ +{ +#define JFIF_LEN 14 + INT32 length; + UINT8 b[JFIF_LEN]; + int buffp; + + length = get_2bytes(cinfo) - 2; + + /* See if a JFIF APP0 marker is present */ + + if (length >= JFIF_LEN) { + for (buffp = 0; buffp < JFIF_LEN; buffp++) + b[buffp] = JGETC(cinfo); + length -= JFIF_LEN; + + if (b[0]=='J' && b[1]=='F' && b[2]=='I' && b[3]=='F' && b[4]==0) { + /* Found JFIF APP0 marker: check version */ + /* Major version must be 1 */ + if (b[5] != 1) + ERREXIT2(cinfo->emethods, "Unsupported JFIF revision number %d.%02d", + b[5], b[6]); + /* Minor version should be 0 or 1, but try to process anyway if newer */ + if (b[6] != 0 && b[6] != 1) + TRACEMS2(cinfo->emethods, 0, "Warning: unknown JFIF revision number %d.%02d", + b[5], b[6]); + /* Save info */ + cinfo->density_unit = b[7]; + cinfo->X_density = (b[8] << 8) + b[9]; + cinfo->Y_density = (b[10] << 8) + b[11]; + /* Assume colorspace is YCbCr, unless UI has overridden me */ + if (cinfo->jpeg_color_space == CS_UNKNOWN) + cinfo->jpeg_color_space = CS_YCbCr; + TRACEMS3(cinfo->emethods, 1, "JFIF APP0 marker, density %dx%d %d", + cinfo->X_density, cinfo->Y_density, cinfo->density_unit); + } else { + TRACEMS(cinfo->emethods, 1, "Unknown APP0 marker (not JFIF)"); + } + } else { + TRACEMS1(cinfo->emethods, 1, + "Short APP0 marker, length %d", (int) length); + } + + while (length-- > 0) /* skip any remaining data */ + (void) JGETC(cinfo); +} + + +LOCAL void +get_sof (decompress_info_ptr cinfo, int code) +/* Process a SOFn marker */ +{ + INT32 length; + short ci; + int c; + jpeg_component_info * compptr; + + length = get_2bytes(cinfo); + + cinfo->data_precision = JGETC(cinfo); + cinfo->image_height = get_2bytes(cinfo); + cinfo->image_width = get_2bytes(cinfo); + cinfo->num_components = JGETC(cinfo); + + TRACEMS4(cinfo->emethods, 1, + "Start Of Frame 0x%02x: width=%d, height=%d, components=%d", + code, cinfo->image_width, cinfo->image_height, + cinfo->num_components); + + /* We don't support files in which the image height is initially specified */ + /* as 0 and is later redefined by DNL. As long as we have to check that, */ + /* might as well have a general sanity check. */ + if (cinfo->image_height <= 0 || cinfo->image_width <= 0 + || cinfo->num_components <= 0) + ERREXIT(cinfo->emethods, "Empty JPEG image (DNL not supported)"); + +#ifdef EIGHT_BIT_SAMPLES + if (cinfo->data_precision != 8) + ERREXIT(cinfo->emethods, "Unsupported JPEG data precision"); +#endif +#ifdef TWELVE_BIT_SAMPLES + if (cinfo->data_precision != 12) /* this needs more thought?? */ + ERREXIT(cinfo->emethods, "Unsupported JPEG data precision"); +#endif +#ifdef SIXTEEN_BIT_SAMPLES + if (cinfo->data_precision != 16) /* this needs more thought?? */ + ERREXIT(cinfo->emethods, "Unsupported JPEG data precision"); +#endif + + if (length != (cinfo->num_components * 3 + 8)) + ERREXIT(cinfo->emethods, "Bogus SOF length"); + + cinfo->comp_info = (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(jpeg_component_info)); + + for (ci = 0; ci < cinfo->num_components; ci++) { + compptr = &cinfo->comp_info[ci]; + compptr->component_index = ci; + compptr->component_id = JGETC(cinfo); + c = JGETC(cinfo); + compptr->h_samp_factor = (c >> 4) & 15; + compptr->v_samp_factor = (c ) & 15; + compptr->quant_tbl_no = JGETC(cinfo); + + TRACEMS4(cinfo->emethods, 1, " Component %d: %dhx%dv q=%d", + compptr->component_id, compptr->h_samp_factor, + compptr->v_samp_factor, compptr->quant_tbl_no); + } +} + + +LOCAL void +get_sos (decompress_info_ptr cinfo) +/* Process a SOS marker */ +{ + INT32 length; + int i, ci, n, c, cc; + jpeg_component_info * compptr; + + length = get_2bytes(cinfo); + + n = JGETC(cinfo); /* Number of components */ + cinfo->comps_in_scan = n; + length -= 3; + + if (length != (n * 2 + 3) || n < 1 || n > MAX_COMPS_IN_SCAN) + ERREXIT(cinfo->emethods, "Bogus SOS length"); + + TRACEMS1(cinfo->emethods, 1, "Start Of Scan: %d components", n); + + for (i = 0; i < n; i++) { + cc = JGETC(cinfo); + c = JGETC(cinfo); + length -= 2; + + for (ci = 0; ci < cinfo->num_components; ci++) + if (cc == cinfo->comp_info[ci].component_id) + break; + + if (ci >= cinfo->num_components) + ERREXIT(cinfo->emethods, "Invalid component number in SOS"); + + compptr = &cinfo->comp_info[ci]; + cinfo->cur_comp_info[i] = compptr; + compptr->dc_tbl_no = (c >> 4) & 15; + compptr->ac_tbl_no = (c ) & 15; + + TRACEMS3(cinfo->emethods, 1, " c%d: [dc=%d ac=%d]", cc, + compptr->dc_tbl_no, compptr->ac_tbl_no); + } + + while (length > 0) { + (void) JGETC(cinfo); + length--; + } +} + + +LOCAL void +get_soi (decompress_info_ptr cinfo) +/* Process an SOI marker */ +{ + int i; + + TRACEMS(cinfo->emethods, 1, "Start of Image"); + + /* Reset all parameters that are defined to be reset by SOI */ + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + cinfo->restart_interval = 0; + + cinfo->density_unit = 0; /* set default JFIF APP0 values */ + cinfo->X_density = 1; + cinfo->Y_density = 1; + + cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling */ +} + + +LOCAL int +next_marker (decompress_info_ptr cinfo) +/* Find the next JPEG marker */ +/* Note that the output might not be a valid marker code, */ +/* but it will never be 0 or FF */ +{ + int c, nbytes; + + nbytes = 0; + do { + do { /* skip any non-FF bytes */ + nbytes++; + c = JGETC(cinfo); + } while (c != 0xFF); + do { /* skip any duplicate FFs */ + nbytes++; + c = JGETC(cinfo); + } while (c == 0xFF); + } while (c == 0); /* repeat if it was a stuffed FF/00 */ + + if (nbytes != 2) + TRACEMS2(cinfo->emethods, 1, "Skipped %d bytes before marker 0x%02x", + nbytes-2, c); + + return c; +} + + +LOCAL JPEG_MARKER +process_tables (decompress_info_ptr cinfo) +/* Scan and process JPEG markers that can appear in any order */ +/* Return when an SOI, EOI, SOFn, or SOS is found */ +{ + int c; + + while (TRUE) { + c = next_marker(cinfo); + + switch (c) { + case M_SOF0: + case M_SOF1: + case M_SOF2: + case M_SOF3: + case M_SOF5: + case M_SOF6: + case M_SOF7: + case M_JPG: + case M_SOF9: + case M_SOF10: + case M_SOF11: + case M_SOF13: + case M_SOF14: + case M_SOF15: + case M_SOI: + case M_EOI: + case M_SOS: + return c; + + case M_DHT: + get_dht(cinfo); + break; + + case M_DAC: + get_dac(cinfo); + break; + + case M_DQT: + get_dqt(cinfo); + break; + + case M_DRI: + get_dri(cinfo); + break; + + case M_APP0: + get_app0(cinfo); + break; + + case M_RST0: /* these are all parameterless */ + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + case M_TEM: + TRACEMS1(cinfo->emethods, 1, "Unexpected marker 0x%02x", c); + break; + + default: /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn */ + skip_variable(cinfo, c); + break; + } + } +} + + + +/* + * Initialize and read the file header (everything through the SOF marker). + */ + +METHODDEF void +read_file_header (decompress_info_ptr cinfo) +{ + int c; + + /* Expect an SOI marker first */ + if (next_marker(cinfo) == M_SOI) + get_soi(cinfo); + else + ERREXIT(cinfo->emethods, "File does not start with JPEG SOI marker"); + + /* Process markers until SOF */ + c = process_tables(cinfo); + + switch (c) { + case M_SOF0: + case M_SOF1: + get_sof(cinfo, c); + cinfo->arith_code = FALSE; + break; + + case M_SOF9: + get_sof(cinfo, c); + cinfo->arith_code = TRUE; + break; + + default: + ERREXIT1(cinfo->emethods, "Unsupported SOF marker type 0x%02x", c); + break; + } + + /* Figure out what colorspace we have */ + /* (too bad the JPEG committee didn't provide a real way to specify this) */ + + switch (cinfo->num_components) { + case 1: + cinfo->jpeg_color_space = CS_GRAYSCALE; + break; + + case 3: + /* if we saw a JFIF marker, leave it set to YCbCr; */ + /* also leave it alone if UI has provided a value */ + if (cinfo->jpeg_color_space == CS_UNKNOWN) { + short cid0 = cinfo->comp_info[0].component_id; + short cid1 = cinfo->comp_info[1].component_id; + short cid2 = cinfo->comp_info[2].component_id; + + if (cid0 == 1 && cid1 == 2 && cid2 == 3) + cinfo->jpeg_color_space = CS_YCbCr; /* assume it's JFIF w/out marker */ + else if (cid0 == 1 && cid1 == 4 && cid2 == 5) + cinfo->jpeg_color_space = CS_YIQ; /* prototype's YIQ matrix */ + else { + TRACEMS3(cinfo->emethods, 0, + "Unrecognized component IDs %d %d %d, assuming YCbCr", + cid0, cid1, cid2); + cinfo->jpeg_color_space = CS_YCbCr; + } + } + break; + + case 4: + cinfo->jpeg_color_space = CS_CMYK; + break; + + default: + cinfo->jpeg_color_space = CS_UNKNOWN; + break; + } +} + + +/* + * Read the start of a scan (everything through the SOS marker). + * Return TRUE if find SOS, FALSE if find EOI. + */ + +METHODDEF boolean +read_scan_header (decompress_info_ptr cinfo) +{ + int c; + + /* Process markers until SOS or EOI */ + c = process_tables(cinfo); + + switch (c) { + case M_SOS: + get_sos(cinfo); + return TRUE; + + case M_EOI: + TRACEMS(cinfo->emethods, 1, "End Of Image"); + return FALSE; + + default: + ERREXIT1(cinfo->emethods, "Unexpected marker 0x%02x", c); + break; + } + return FALSE; /* keeps lint happy */ +} + + +/* + * Finish up after a compressed scan (series of read_jpeg_data calls); + * prepare for another read_scan_header call. + */ + +METHODDEF void +read_scan_trailer (decompress_info_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +read_file_trailer (decompress_info_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * The method selection routine for standard JPEG header reading. + * Note that this must be called by the user interface before calling + * jpeg_decompress. When a non-JFIF file is to be decompressed (TIFF, + * perhaps), the user interface must discover the file type and call + * the appropriate method selection routine. + */ + +GLOBAL void +jselrjfif (decompress_info_ptr cinfo) +{ + cinfo->methods->read_file_header = read_file_header; + cinfo->methods->read_scan_header = read_scan_header; + /* For JFIF/raw-JPEG format, the user interface supplies read_jpeg_data. */ +#if 0 + cinfo->methods->read_jpeg_data = read_jpeg_data; +#endif + cinfo->methods->read_scan_trailer = read_scan_trailer; + cinfo->methods->read_file_trailer = read_file_trailer; +} + +#endif /* JFIF_SUPPORTED */ diff --git a/jrdppm.c b/jrdppm.c new file mode 100644 index 0000000..15e2393 --- /dev/null +++ b/jrdppm.c @@ -0,0 +1,124 @@ +/* + * jrdppm.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in PPM format. + * The PBMPLUS library is required (well, it will be in the real version). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume input from + * an ordinary stdio stream. They further assume that reading begins + * at the start of the file; input_init may need work if the + * user interface has already read some data (e.g., to determine that + * the file is indeed PPM format). + * + * These routines are invoked via the methods get_input_row + * and input_init/term. + */ + +#include "jinclude.h" + +#ifdef PPM_SUPPORTED + + +/* + * Read the file header; return image size and component count. + */ + +METHODDEF void +input_init (compress_info_ptr cinfo) +{ + int c, w, h, prec; + + if (getc(cinfo->input_file) != 'P') + ERREXIT(cinfo->emethods, "Not a PPM file"); + + c = getc(cinfo->input_file); + switch (c) { + case '5': /* it's a PGM file */ + cinfo->input_components = 1; + cinfo->in_color_space = CS_GRAYSCALE; + break; + + case '6': /* it's a PPM file */ + cinfo->input_components = 3; + cinfo->in_color_space = CS_RGB; + break; + + default: + ERREXIT(cinfo->emethods, "Not a PPM file"); + break; + } + + if (fscanf(cinfo->input_file, " %d %d %d", &w, &h, &prec) != 3) + ERREXIT(cinfo->emethods, "Not a PPM file"); + + if (getc(cinfo->input_file) != '\n' || w <= 0 || h <= 0 || prec != 255) + ERREXIT(cinfo->emethods, "Not a PPM file"); + + cinfo->image_width = w; + cinfo->image_height = h; + cinfo->data_precision = 8; +} + + +/* + * Read one row of pixels. + */ + +METHODDEF void +get_input_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row) +{ + register FILE * infile = cinfo->input_file; + register JSAMPROW ptr0, ptr1, ptr2; + register long col; + + if (cinfo->input_components == 1) { + ptr0 = pixel_row[0]; + for (col = cinfo->image_width; col > 0; col--) { + *ptr0++ = getc(infile); + } + } else { + ptr0 = pixel_row[0]; + ptr1 = pixel_row[1]; + ptr2 = pixel_row[2]; + for (col = cinfo->image_width; col > 0; col--) { + *ptr0++ = getc(infile); + *ptr1++ = getc(infile); + *ptr2++ = getc(infile); + } + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +input_term (compress_info_ptr cinfo) +{ + /* no work required */ +} + + +/* + * The method selection routine for PPM format input. + * Note that this must be called by the user interface before calling + * jpeg_compress. If multiple input formats are supported, the + * user interface is responsible for discovering the file format and + * calling the appropriate method selection routine. + */ + +GLOBAL void +jselrppm (compress_info_ptr cinfo) +{ + cinfo->methods->input_init = input_init; + cinfo->methods->get_input_row = get_input_row; + cinfo->methods->input_term = input_term; +} + +#endif /* PPM_SUPPORTED */ diff --git a/jrevdct.c b/jrevdct.c new file mode 100644 index 0000000..bafbf55 --- /dev/null +++ b/jrevdct.c @@ -0,0 +1,171 @@ +/* + * jrevdct.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the basic inverse-DCT transformation subroutine. + * + * This implementation is based on Appendix A.2 of the book + * "Discrete Cosine Transform---Algorithms, Advantages, Applications" + * by K.R. Rao and P. Yip (Academic Press, Inc, London, 1990). + * It uses scaled fixed-point arithmetic instead of floating point. + */ + +#include "jinclude.h" + + +/* The poop on this scaling stuff is as follows: + * + * Most of the numbers (after multiplication by the constants) are + * (logically) shifted left by LG2_DCT_SCALE. This is undone by UNFIXH + * before assignment to the output array. Note that we want an additional + * division by 2 on the output (required by the equations). + * + * If right shifts are unsigned, then there is a potential problem. + * However, shifting right by 16 and then assigning to a short + * (assuming short = 16 bits) will keep the sign right!! + * + * For other shifts, + * + * ((x + (1 << 30)) >> shft) - (1 << (30 - shft)) + * + * gives a nice right shift with sign (assuming no overflow). However, all the + * scaling is such that this isn't a problem. (Is this true?) + */ + + +#define ONE 1L /* remove L if long > 32 bits */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define LG2_DCT_SCALE 15 +#define RIGHT_SHIFT(_x,_shft) ((((_x) + (ONE << 30)) >> (_shft)) - (ONE << (30 - (_shft)))) +#else +#define LG2_DCT_SCALE 16 +#define RIGHT_SHIFT(_x,_shft) ((_x) >> (_shft)) +#endif + +#define DCT_SCALE (ONE << LG2_DCT_SCALE) + +#define LG2_OVERSCALE 2 +#define OVERSCALE (ONE << LG2_OVERSCALE) + +#define FIX(x) ((INT32) ((x) * DCT_SCALE + 0.5)) +#define FIXO(x) ((INT32) ((x) * DCT_SCALE / OVERSCALE + 0.5)) +#define UNFIX(x) RIGHT_SHIFT((x) + (ONE << (LG2_DCT_SCALE-1)), LG2_DCT_SCALE) +#define UNFIXH(x) RIGHT_SHIFT((x) + (ONE << LG2_DCT_SCALE), LG2_DCT_SCALE+1) +#define UNFIXO(x) RIGHT_SHIFT((x) + (ONE << (LG2_DCT_SCALE-1-LG2_OVERSCALE)), LG2_DCT_SCALE-LG2_OVERSCALE) +#define OVERSH(x) ((x) << LG2_OVERSCALE) + +#define SIN_1_4 FIX(0.7071067811856476) +#define COS_1_4 SIN_1_4 + +#define SIN_1_8 FIX(0.3826834323650898) +#define COS_1_8 FIX(0.9238795325112870) +#define SIN_3_8 COS_1_8 +#define COS_3_8 SIN_1_8 + +#define SIN_1_16 FIX(0.1950903220161282) +#define COS_1_16 FIX(0.9807852804032300) +#define SIN_7_16 COS_1_16 +#define COS_7_16 SIN_1_16 + +#define SIN_3_16 FIX(0.5555702330196022) +#define COS_3_16 FIX(0.8314696123025450) +#define SIN_5_16 COS_3_16 +#define COS_5_16 SIN_3_16 + +#define OSIN_1_4 FIXO(0.707106781185647) +#define OCOS_1_4 OSIN_1_4 + +#define OSIN_1_8 FIXO(0.3826834323650898) +#define OCOS_1_8 FIXO(0.9238795325112870) +#define OSIN_3_8 OCOS_1_8 +#define OCOS_3_8 OSIN_1_8 + +#define OSIN_1_16 FIXO(0.1950903220161282) +#define OCOS_1_16 FIXO(0.9807852804032300) +#define OSIN_7_16 OCOS_1_16 +#define OCOS_7_16 OSIN_1_16 + +#define OSIN_3_16 FIXO(0.5555702330196022) +#define OCOS_3_16 FIXO(0.8314696123025450) +#define OSIN_5_16 OCOS_3_16 +#define OCOS_5_16 OSIN_3_16 + + +INLINE +LOCAL void +fast_idct_8 (DCTELEM *in, int stride) +{ + /* tmp1x are new values of tmpx -- flashy register colourers + * should be able to do this lot very well + */ + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 tmp20, tmp21, tmp22, tmp23; + INT32 tmp30, tmp31; + INT32 tmp40, tmp41, tmp42, tmp43; + INT32 tmp50, tmp51, tmp52, tmp53; + INT32 in0, in1, in2, in3, in4, in5, in6, in7; + + in0 = in[ 0]; + in1 = in[stride ]; + in2 = in[stride*2]; + in3 = in[stride*3]; + in4 = in[stride*4]; + in5 = in[stride*5]; + in6 = in[stride*6]; + in7 = in[stride*7]; + + tmp10 = (in0 + in4) * COS_1_4; + tmp11 = (in0 - in4) * COS_1_4; + tmp12 = in2 * SIN_1_8 - in6 * COS_1_8; + tmp13 = in6 * SIN_1_8 + in2 * COS_1_8; + + tmp20 = tmp10 + tmp13; + tmp21 = tmp11 + tmp12; + tmp22 = tmp11 - tmp12; + tmp23 = tmp10 - tmp13; + + tmp30 = UNFIXO((in3 + in5) * COS_1_4); + tmp31 = UNFIXO((in3 - in5) * COS_1_4); + + tmp40 = OVERSH(in1) + tmp30; + tmp41 = OVERSH(in7) + tmp31; + tmp42 = OVERSH(in1) - tmp30; + tmp43 = OVERSH(in7) - tmp31; + + tmp50 = tmp40 * OCOS_1_16 + tmp41 * OSIN_1_16; + tmp51 = tmp40 * OSIN_1_16 - tmp41 * OCOS_1_16; + tmp52 = tmp42 * OCOS_5_16 + tmp43 * OSIN_5_16; + tmp53 = tmp42 * OSIN_5_16 - tmp43 * OCOS_5_16; + + in[ 0] = UNFIXH(tmp20 + tmp50); + in[stride ] = UNFIXH(tmp21 + tmp53); + in[stride*2] = UNFIXH(tmp22 + tmp52); + in[stride*3] = UNFIXH(tmp23 + tmp51); + in[stride*4] = UNFIXH(tmp23 - tmp51); + in[stride*5] = UNFIXH(tmp22 - tmp52); + in[stride*6] = UNFIXH(tmp21 - tmp53); + in[stride*7] = UNFIXH(tmp20 - tmp50); +} + + +/* + * Perform the inverse DCT on one block of coefficients. + * + * Note that this code is specialized to the case DCTSIZE = 8. + */ + +GLOBAL void +j_rev_dct (DCTBLOCK data) +{ + int i; + + for (i = 0; i < DCTSIZE; i++) + fast_idct_8(data+i*DCTSIZE, 1); + + for (i = 0; i < DCTSIZE; i++) + fast_idct_8(data+i, DCTSIZE); +} diff --git a/jutils.c b/jutils.c new file mode 100644 index 0000000..aebcaa9 --- /dev/null +++ b/jutils.c @@ -0,0 +1,106 @@ +/* + * jutils.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains miscellaneous utility routines needed for both + * compression and decompression. + * Note we prefix all global names with "j" to minimize conflicts with + * a surrounding application. + */ + +#include "jinclude.h" + + +GLOBAL long +jround_up (long a, long b) +/* Compute a rounded up to next multiple of b; a >= 0, b > 0 */ +{ + a += b-1; + return a - (a % b); +} + + +GLOBAL void +jcopy_sample_rows (JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, long num_cols) +/* Copy some rows of samples from one place to another. + * num_rows rows are copied from input_array[source_row++] + * to output_array[dest_row++]; these areas should not overlap. + * The source and destination arrays must be at least as wide as num_cols. + */ +{ + /* On normal machines we can use memcpy(). This won't work on 80x86 because + * the sample arrays are FAR and we're assuming a small-pointer memory model. + */ + register JSAMPROW inptr, outptr; +#ifdef NEED_FAR_POINTERS + register long count; +#else + register size_t count = num_cols * SIZEOF(JSAMPLE); +#endif + register int row; + + input_array += source_row; + output_array += dest_row; + + for (row = num_rows; row > 0; row--) { + inptr = *input_array++; + outptr = *output_array++; +#ifdef NEED_FAR_POINTERS + for (count = num_cols; count > 0; count--) + *outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */ +#else + memcpy((void *) outptr, (void *) inptr, count); +#endif + } +} + + +GLOBAL void +jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row, long num_blocks) +/* Copy a row of coefficient blocks from one place to another. */ +{ + /* On normal machines we can use memcpy(). This won't work on 80x86 because + * the block arrays are FAR and we're assuming a small-pointer memory model. + */ +#ifdef NEED_FAR_POINTERS + register JCOEFPTR inptr, outptr; + register int i; + register long count; + + for (count = num_blocks; count > 0; count--) { + inptr = *input_row++; + outptr = *output_row++; + for (i = DCTSIZE2; i > 0; i--) + *outptr++ = *inptr++; + } +#else + memcpy((void *) output_row, (void *) input_row, + (size_t) (num_blocks * (DCTSIZE2 * SIZEOF(JCOEF)))); +#endif +} + + +GLOBAL void +jzero_far (void FAR * target, size_t bytestozero) +/* Zero out a chunk of FAR memory. */ +/* This might be sample-array data, block-array data, or alloc_medium data. */ +{ + /* On normal machines we can use MEMZERO(). This won't work on 80x86 + * because we're assuming a small-pointer memory model. + */ +#ifdef NEED_FAR_POINTERS + register char FAR * ptr = (char FAR *) target; + register size_t count; + + for (count = bytestozero; count > 0; count--) { + *ptr++ = 0; + } +#else + MEMZERO((void *) target, bytestozero); +#endif +} diff --git a/jvirtmem.c b/jvirtmem.c new file mode 100644 index 0000000..4a0627c --- /dev/null +++ b/jvirtmem.c @@ -0,0 +1,548 @@ +/* + * jvirtmem.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides the system-dependent memory allocation routines + * for the case where we can rely on virtual memory to handle large arrays. + * + * This includes some MS-DOS code just for trial purposes; "big" arrays will + * have to be handled with temp files on MS-DOS, so a real implementation of + * a DOS memory manager will probably be a separate file. (See additional + * comments about big arrays, below.) + * + * NB: allocation routines never return NULL. + * They should exit to error_exit if unsuccessful. + */ + +#include "jinclude.h" + +#ifdef __STDC__ +#include /* to declare malloc(), free() */ +#else +extern void * malloc PP((size_t size)); +extern void free PP((void *ptr)); +#endif + + +/* Insert system-specific definitions of far_malloc, far_free here. */ + +#ifndef NEED_FAR_POINTERS /* Generic for non-braindamaged CPUs */ + +#define far_malloc(x) malloc(x) +#define far_free(x) free(x) + +#else /* NEED_FAR_POINTERS */ + +#ifdef __TURBOC__ +/* These definitions work for Turbo C */ +#include /* need farmalloc(), farfree() */ +#define far_malloc(x) farmalloc(x) +#define far_free(x) farfree(x) +#else +#ifdef MSDOS +/* These definitions work for Microsoft C and compatible compilers */ +#include /* need _fmalloc(), _ffree() */ +#define far_malloc(x) _fmalloc(x) +#define far_free(x) _ffree(x) +#endif +#endif + +#endif /* NEED_FAR_POINTERS */ + + +/* + * Some important notes: + * The array alloc/dealloc routines are not merely a convenience; + * on 80x86 machines the bottom-level pointers in an array are FAR + * and thus may not be allocatable by alloc_small. + * + * Also, it's not a good idea to try to merge the sarray and barray + * routines, even though they are textually almost the same, because + * samples are usually stored as bytes while coefficients are shorts. + * Thus, in machines where byte pointers have a different representation + * from word pointers, the resulting machine code could not be the same. + */ + + +static external_methods_ptr methods; /* saved for access to error_exit */ + + +#ifdef MEM_STATS /* optional extra stuff for statistics */ + +#define MALLOC_OVERHEAD (SIZEOF(char *)) /* assumed overhead per request */ +#define MALLOC_FAR_OVERHEAD (SIZEOF(char FAR *)) /* for "far" storage */ + +static long total_num_small = 0; /* total # of small objects alloced */ +static long total_bytes_small = 0; /* total bytes requested */ +static long cur_num_small = 0; /* # currently alloced */ +static long max_num_small = 0; /* max simultaneously alloced */ + +#ifdef NEED_FAR_POINTERS +static long total_num_medium = 0; /* total # of medium objects alloced */ +static long total_bytes_medium = 0; /* total bytes requested */ +static long cur_num_medium = 0; /* # currently alloced */ +static long max_num_medium = 0; /* max simultaneously alloced */ +#endif + +static long total_num_sarray = 0; /* total # of sarray objects alloced */ +static long total_bytes_sarray = 0; /* total bytes requested */ +static long cur_num_sarray = 0; /* # currently alloced */ +static long max_num_sarray = 0; /* max simultaneously alloced */ + +static long total_num_barray = 0; /* total # of barray objects alloced */ +static long total_bytes_barray = 0; /* total bytes requested */ +static long cur_num_barray = 0; /* # currently alloced */ +static long max_num_barray = 0; /* max simultaneously alloced */ + + +GLOBAL void +j_mem_stats (void) +{ + /* since this is only a debugging stub, we can cheat a little on the + * trace message mechanism... helps 'cuz trace can't handle longs. + */ + fprintf(stderr, "total_num_small = %ld\n", total_num_small); + fprintf(stderr, "total_bytes_small = %ld\n", total_bytes_small); + if (cur_num_small) + fprintf(stderr, "CUR_NUM_SMALL = %ld\n", cur_num_small); + fprintf(stderr, "max_num_small = %ld\n", max_num_small); + +#ifdef NEED_FAR_POINTERS + fprintf(stderr, "total_num_medium = %ld\n", total_num_medium); + fprintf(stderr, "total_bytes_medium = %ld\n", total_bytes_medium); + if (cur_num_medium) + fprintf(stderr, "CUR_NUM_MEDIUM = %ld\n", cur_num_medium); + fprintf(stderr, "max_num_medium = %ld\n", max_num_medium); +#endif + + fprintf(stderr, "total_num_sarray = %ld\n", total_num_sarray); + fprintf(stderr, "total_bytes_sarray = %ld\n", total_bytes_sarray); + if (cur_num_sarray) + fprintf(stderr, "CUR_NUM_SARRAY = %ld\n", cur_num_sarray); + fprintf(stderr, "max_num_sarray = %ld\n", max_num_sarray); + + fprintf(stderr, "total_num_barray = %ld\n", total_num_barray); + fprintf(stderr, "total_bytes_barray = %ld\n", total_bytes_barray); + if (cur_num_barray) + fprintf(stderr, "CUR_NUM_BARRAY = %ld\n", cur_num_barray); + fprintf(stderr, "max_num_barray = %ld\n", max_num_barray); +} + +#endif /* MEM_STATS */ + + +LOCAL void +out_of_memory (int which) +/* Report an out-of-memory error and stop execution */ +/* If we compiled MEM_STATS support, report alloc requests before dying */ +{ +#ifdef MEM_STATS + j_mem_stats(); +#endif + ERREXIT1(methods, "Insufficient memory (case %d)", which); +} + + + +METHODDEF void * +alloc_small (size_t sizeofobject) +/* Allocate a "small" (all-in-memory) object */ +{ + void * result; + +#ifdef MEM_STATS + total_num_small++; + total_bytes_small += sizeofobject + MALLOC_OVERHEAD; + cur_num_small++; + if (cur_num_small > max_num_small) max_num_small = cur_num_small; +#endif + + result = malloc(sizeofobject); + if (result == NULL) + out_of_memory(1); + return result; +} + + +METHODDEF void +free_small (void *ptr) +/* Free a "small" (all-in-memory) object */ +{ + free(ptr); + +#ifdef MEM_STATS + cur_num_small--; +#endif +} + + +#ifdef NEED_FAR_POINTERS + +METHODDEF void FAR * +alloc_medium (size_t sizeofobject) +/* Allocate a "medium" (all in memory, but in far heap) object */ +{ + void FAR * result; + +#ifdef MEM_STATS + total_num_medium++; + total_bytes_medium += sizeofobject + MALLOC_FAR_OVERHEAD; + cur_num_medium++; + if (cur_num_medium > max_num_medium) max_num_medium = cur_num_medium; +#endif + + result = far_malloc(sizeofobject); + if (result == NULL) + out_of_memory(2); + return result; +} + + +METHODDEF void +free_medium (void FAR *ptr) +/* Free a "medium" (all in memory, but in far heap) object */ +{ + far_free(ptr); + +#ifdef MEM_STATS + cur_num_medium--; +#endif +} + +#endif /* NEED_FAR_POINTERS */ + + +METHODDEF JSAMPARRAY +alloc_small_sarray (long samplesperrow, long numrows) +/* Allocate a "small" (all-in-memory) 2-D sample array */ +{ + JSAMPARRAY result; + long i; + +#ifdef MEM_STATS + total_num_sarray++; + total_bytes_sarray += (samplesperrow * SIZEOF(JSAMPLE) + MALLOC_FAR_OVERHEAD) + * numrows; + cur_num_sarray++; + if (cur_num_sarray > max_num_sarray) max_num_sarray = cur_num_sarray; +#endif + + /* Get space for row pointers; this is always "near" on 80x86 */ + result = (JSAMPARRAY) alloc_small((size_t) (numrows * SIZEOF(JSAMPROW))); + + /* Get the rows themselves; on 80x86 these are "far" */ + for (i = 0; i < numrows; i++) { + result[i] = (JSAMPROW) far_malloc((size_t) (samplesperrow * SIZEOF(JSAMPLE))); + if (result[i] == NULL) + out_of_memory(3); + } + + return result; +} + + +METHODDEF void +free_small_sarray (JSAMPARRAY ptr, long numrows) +/* Free a "small" (all-in-memory) 2-D sample array */ +{ + long i; + + /* Free the rows themselves; on 80x86 these are "far" */ + for (i = 0; i < numrows; i++) { + far_free((void FAR *) ptr[i]); + } + + /* Free space for row pointers; this is always "near" on 80x86 */ + free_small((void *) ptr); + +#ifdef MEM_STATS + cur_num_sarray--; +#endif +} + + +METHODDEF JBLOCKARRAY +alloc_small_barray (long blocksperrow, long numrows) +/* Allocate a "small" (all-in-memory) 2-D coefficient-block array */ +{ + JBLOCKARRAY result; + long i; + +#ifdef MEM_STATS + total_num_barray++; + total_bytes_barray += (blocksperrow * SIZEOF(JBLOCK) + MALLOC_FAR_OVERHEAD) + * numrows; + cur_num_barray++; + if (cur_num_barray > max_num_barray) max_num_barray = cur_num_barray; +#endif + + /* Get space for row pointers; this is always "near" on 80x86 */ + result = (JBLOCKARRAY) alloc_small((size_t) (numrows * SIZEOF(JBLOCKROW))); + + /* Get the rows themselves; on 80x86 these are "far" */ + for (i = 0; i < numrows; i++) { + result[i] = (JBLOCKROW) far_malloc((size_t) (blocksperrow * SIZEOF(JBLOCK))); + if (result[i] == NULL) + out_of_memory(4); + } + + return result; +} + + +METHODDEF void +free_small_barray (JBLOCKARRAY ptr, long numrows) +/* Free a "small" (all-in-memory) 2-D coefficient-block array */ +{ + long i; + + /* Free the rows themselves; on 80x86 these are "far" */ + for (i = 0; i < numrows; i++) { + far_free((void FAR *) ptr[i]); + } + + /* Free space for row pointers; this is always "near" on 80x86 */ + free_small((void *) ptr); + +#ifdef MEM_STATS + cur_num_barray--; +#endif +} + + + +/* + * About "big" array management: + * + * To allow machines with limited memory to handle large images, + * all processing in the JPEG system is done a few pixel or block rows + * at a time. The above "small" array routines are only used to allocate + * strip buffers (as wide as the image, but just a few rows high). + * In some cases multiple passes must be made over the data. In these + * cases the "big" array routines are used. The array is still accessed + * a strip at a time, but the memory manager must save the whole array + * for repeated accesses. The intended implementation is that there is + * a strip buffer in memory (as high as is possible given the desired memory + * limit), plus a backing file that holds the rest of the array. + * + * The request_big_array routines are told the total size of the image (in case + * it is useful to know the total file size that will be needed). They are + * also given the unit height, which is the number of rows that will be + * accessed at once; the in-memory buffer should usually be made a multiple of + * this height for best efficiency. + * + * The request routines create control blocks (and may open backing files), + * but they don't create the in-memory buffers. This is postponed until + * alloc_big_arrays is called. At that time the total amount of space needed + * is known (approximately, anyway), so free memory can be divided up fairly. + * + * The access_big_array routines are responsible for making a specific strip + * area accessible (after reading or writing the backing file, if necessary). + * Note that the access routines are told whether the caller intends to modify + * the accessed strip; during a read-only pass this saves having to rewrite + * data to disk. + * + * The typical access pattern is one top-to-bottom pass to write the data, + * followed by one or more read-only top-to-bottom passes. However, other + * access patterns may occur while reading. For example, translation of image + * formats that use bottom-to-top scan order will require bottom-to-top read + * passes. The memory manager need not support multiple write passes nor + * funny write orders (meaning that rearranging rows must be handled while + * reading data out of the big array, not while putting it in). + * + * In current usage, the access requests are always for nonoverlapping strips; + * that is, successive access start_row numbers always differ by exactly the + * unitheight. This allows fairly simple buffer dump/reload logic if the + * in-memory buffer is made a multiple of the unitheight. It would be + * possible to keep subsampled rather than fullsize data in the "big" arrays, + * thus reducing temp file size, if we supported overlapping strip access + * (access requests differing by less than the unitheight). At the moment + * I don't believe this is worth the extra complexity. + * + * This particular implementation doesn't use temp files; the whole of a big + * array is allocated in (virtual) memory, and any swapping is done behind the + * scenes by the operating system. + */ + + + +/* The control blocks for virtual arrays. + * These are pretty minimal in this implementation. + * Note: in this implementation we could realize big arrays + * at request time and make alloc_big_arrays a no-op; + * however, doing it separately keeps callers honest. + */ + +struct big_sarray_control { + JSAMPARRAY mem_buffer; /* memory buffer (the whole thing, here) */ + long rows_in_mem; /* Height of memory buffer */ + long samplesperrow; /* Width of memory buffer */ + long unitheight; /* # of rows accessed by access_big_sarray() */ + big_sarray_ptr next; /* list link for unrealized arrays */ +}; + +struct big_barray_control { + JBLOCKARRAY mem_buffer; /* memory buffer (the whole thing, here) */ + long rows_in_mem; /* Height of memory buffer */ + long blocksperrow; /* Width of memory buffer */ + long unitheight; /* # of rows accessed by access_big_barray() */ + big_barray_ptr next; /* list link for unrealized arrays */ +}; + + +/* Headers of lists of control blocks for unrealized big arrays */ +static big_sarray_ptr unalloced_sarrays; +static big_barray_ptr unalloced_barrays; + + +METHODDEF big_sarray_ptr +request_big_sarray (long samplesperrow, long numrows, long unitheight) +/* Request a "big" (virtual-memory) 2-D sample array */ +{ + big_sarray_ptr result; + + /* get control block */ + result = (big_sarray_ptr) alloc_small(SIZEOF(struct big_sarray_control)); + + result->mem_buffer = NULL; /* lets access routine spot premature access */ + result->rows_in_mem = numrows; + result->samplesperrow = samplesperrow; + result->unitheight = unitheight; + result->next = unalloced_sarrays; /* add to list of unallocated arrays */ + unalloced_sarrays = result; + + return result; +} + + +METHODDEF big_barray_ptr +request_big_barray (long blocksperrow, long numrows, long unitheight) +/* Request a "big" (virtual-memory) 2-D coefficient-block array */ +{ + big_barray_ptr result; + + /* get control block */ + result = (big_barray_ptr) alloc_small(SIZEOF(struct big_barray_control)); + + result->mem_buffer = NULL; /* lets access routine spot premature access */ + result->rows_in_mem = numrows; + result->blocksperrow = blocksperrow; + result->unitheight = unitheight; + result->next = unalloced_barrays; /* add to list of unallocated arrays */ + unalloced_barrays = result; + + return result; +} + + +METHODDEF void +alloc_big_arrays (long extra_small_samples, long extra_small_blocks, + long extra_medium_space) +/* Allocate the in-memory buffers for any unrealized "big" arrays */ +/* 'extra' values are upper bounds for total future small-array requests */ +/* and far-heap requests */ +{ + /* In this implementation we just malloc the whole arrays */ + /* and expect the system's virtual memory to worry about swapping them */ + big_sarray_ptr sptr; + big_barray_ptr bptr; + + for (sptr = unalloced_sarrays; sptr != NULL; sptr = sptr->next) { + sptr->mem_buffer = alloc_small_sarray(sptr->samplesperrow, + sptr->rows_in_mem); + } + + for (bptr = unalloced_barrays; bptr != NULL; bptr = bptr->next) { + bptr->mem_buffer = alloc_small_barray(bptr->blocksperrow, + bptr->rows_in_mem); + } + + unalloced_sarrays = NULL; /* reset for possible future cycles */ + unalloced_barrays = NULL; +} + + +METHODDEF JSAMPARRAY +access_big_sarray (big_sarray_ptr ptr, long start_row, boolean writable) +/* Access the part of a "big" sample array starting at start_row */ +/* and extending for ptr->unitheight rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + /* debugging check */ + if (start_row < 0 || start_row+ptr->unitheight > ptr->rows_in_mem || + ptr->mem_buffer == NULL) + ERREXIT(methods, "Bogus access_big_sarray request"); + + return ptr->mem_buffer + start_row; +} + + +METHODDEF JBLOCKARRAY +access_big_barray (big_barray_ptr ptr, long start_row, boolean writable) +/* Access the part of a "big" coefficient-block array starting at start_row */ +/* and extending for ptr->unitheight rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + /* debugging check */ + if (start_row < 0 || start_row+ptr->unitheight > ptr->rows_in_mem || + ptr->mem_buffer == NULL) + ERREXIT(methods, "Bogus access_big_barray request"); + + return ptr->mem_buffer + start_row; +} + + +METHODDEF void +free_big_sarray (big_sarray_ptr ptr) +/* Free a "big" (virtual-memory) 2-D sample array */ +{ + free_small_sarray(ptr->mem_buffer, ptr->rows_in_mem); + free_small((void *) ptr); /* free the control block too */ +} + + +METHODDEF void +free_big_barray (big_barray_ptr ptr) +/* Free a "big" (virtual-memory) 2-D coefficient-block array */ +{ + free_small_barray(ptr->mem_buffer, ptr->rows_in_mem); + free_small((void *) ptr); /* free the control block too */ +} + + + +/* + * The method selection routine for virtual memory systems. + * The system-dependent setup routine should call this routine + * to install the necessary method pointers in the supplied struct. + */ + +GLOBAL void +jselvirtmem (external_methods_ptr emethods) +{ + methods = emethods; /* save struct addr for error exit access */ + + emethods->alloc_small = alloc_small; + emethods->free_small = free_small; +#ifdef NEED_FAR_POINTERS + emethods->alloc_medium = alloc_medium; + emethods->free_medium = free_medium; +#endif + emethods->alloc_small_sarray = alloc_small_sarray; + emethods->free_small_sarray = free_small_sarray; + emethods->alloc_small_barray = alloc_small_barray; + emethods->free_small_barray = free_small_barray; + emethods->request_big_sarray = request_big_sarray; + emethods->request_big_barray = request_big_barray; + emethods->alloc_big_arrays = alloc_big_arrays; + emethods->access_big_sarray = access_big_sarray; + emethods->access_big_barray = access_big_barray; + emethods->free_big_sarray = free_big_sarray; + emethods->free_big_barray = free_big_barray; + + unalloced_sarrays = NULL; /* make sure list headers are empty */ + unalloced_barrays = NULL; +} diff --git a/jwrgif.c b/jwrgif.c new file mode 100644 index 0000000..44062ec --- /dev/null +++ b/jwrgif.c @@ -0,0 +1,497 @@ +/* + * jwrgif.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in GIF format. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + * + * These routines are invoked via the methods put_pixel_rows, put_color_map, + * and output_init/term. + */ + +/* + * This code is loosely based on ppmtogif from the PBMPLUS distribution + * of Feb. 1991. That file contains the following copyright notice: + * Based on GIFENCODE by David Rowley . + * Lempel-Ziv compression based on "compress" by Spencer W. Thomas et al. + * Copyright (C) 1989 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. + * + * We are also required to state that + * "The Graphics Interchange Format(c) is the Copyright property of + * CompuServe Incorporated. GIF(sm) is a Service Mark property of + * CompuServe Incorporated." + */ + +#include "jinclude.h" + +#ifdef GIF_SUPPORTED + + +static decompress_info_ptr dcinfo; /* to avoid passing to all functions */ + +#define MAX_LZW_BITS 12 /* maximum LZW code size (4096 symbols) */ + +typedef INT16 code_int; /* must hold -1 .. 2**MAX_LZW_BITS */ + +#define LZW_TABLE_SIZE ((code_int) 1 << MAX_LZW_BITS) + +#define HSIZE 5003 /* hash table size for 80% occupancy */ + +typedef int hash_int; /* must hold -2*HSIZE..2*HSIZE */ + +static int n_bits; /* current number of bits/code */ +static code_int maxcode; /* maximum code, given n_bits */ +#define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1) + +static int init_bits; /* initial n_bits ... restored after clear */ + +static code_int ClearCode; /* clear code (doesn't change) */ +static code_int EOFCode; /* EOF code (ditto) */ + +static code_int free_code; /* first not-yet-used symbol code */ + +/* + * The LZW hash table consists of three parallel arrays: + * hash_code[i] code of symbol in slot i, or 0 if empty slot + * hash_prefix[i] symbol's prefix code; undefined if empty slot + * hash_suffix[i] symbol's suffix character; undefined if empty slot + * where slot values (i) range from 0 to HSIZE-1. + * + * Algorithm: use open addressing double hashing (no chaining) on the + * prefix code / suffix character combination. We do a variant of Knuth's + * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime + * secondary probe. + * + * The hash tables are allocated from FAR heap space since they would use up + * rather a lot of the near data space in a PC. + */ + +static code_int FAR *hash_code; /* => hash table of symbol codes */ +static code_int FAR *hash_prefix; /* => hash table of prefix symbols */ +static UINT8 FAR *hash_suffix; /* => hash table of suffix bytes */ + + +/* + * Routines to package compressed data bytes into GIF data blocks. + * A data block consists of a count byte (1..255) and that many data bytes. + */ + +static int bytesinpkt; /* # of bytes in current packet */ +static char packetbuf[256]; /* workspace for accumulating packet */ + + +LOCAL void +flush_packet (void) +/* flush any accumulated data */ +{ + if (bytesinpkt > 0) { /* never write zero-length packet */ + packetbuf[0] = bytesinpkt++; + if (fwrite(packetbuf, 1, bytesinpkt, dcinfo->output_file) != bytesinpkt) + ERREXIT(dcinfo->emethods, "Output file write error"); + bytesinpkt = 0; + } +} + + +LOCAL void +char_out (int c) +/* Add a character to current packet; flush to disk if necessary */ +{ + packetbuf[++bytesinpkt] = c; + if (bytesinpkt >= 255) + flush_packet(); +} + + +/* Routine to convert variable-width codes into a byte stream */ + +static INT32 cur_accum; /* holds bits not yet output */ +static int cur_bits; /* # of bits in cur_accum */ + + +LOCAL void +output (code_int code) +/* Emit a code of n_bits bits */ +/* Uses cur_accum and cur_bits to reblock into 8-bit bytes */ +{ + if (cur_bits > 0) + cur_accum |= ((INT32) code << cur_bits); + else + cur_accum = code; + cur_bits += n_bits; + + while (cur_bits >= 8) { + char_out((int) (cur_accum & 0xFF)); + cur_accum >>= 8; + cur_bits -= 8; + } + + /* + * If the next entry is going to be too big for the code size, + * then increase it, if possible. We do this here to ensure + * that it's done in sync with the decoder's codesize increases. + */ + if (free_code > maxcode) { + n_bits++; + if (n_bits == MAX_LZW_BITS) + maxcode = LZW_TABLE_SIZE; /* free_code will never exceed this */ + else + maxcode = MAXCODE(n_bits); + } +} + + +/* The LZW algorithm proper */ + +static code_int waiting_code; /* symbol not yet output; may be extendable */ +static boolean first_byte; /* if TRUE, waiting_code is not valid */ + + +LOCAL void +clear_hash (void) +/* Fill the hash table with empty entries */ +{ + /* It's sufficient to zero hash_code[] */ + jzero_far((void FAR *) hash_code, HSIZE * SIZEOF(code_int)); +} + + +LOCAL void +clear_block (void) +/* Reset compressor and issue a Clear code */ +{ + clear_hash(); /* delete all the symbols */ + free_code = ClearCode + 2; + output(ClearCode); /* inform decoder */ + n_bits = init_bits; /* reset code size */ + maxcode = MAXCODE(n_bits); +} + + +LOCAL void +compress_init (int i_bits) +/* Initialize LZW compressor */ +{ + /* init all the static variables */ + n_bits = init_bits = i_bits; + maxcode = MAXCODE(n_bits); + ClearCode = ((code_int) 1 << (init_bits - 1)); + EOFCode = ClearCode + 1; + free_code = ClearCode + 2; + first_byte = TRUE; /* no waiting symbol yet */ + /* init output buffering vars */ + bytesinpkt = 0; + cur_accum = 0; + cur_bits = 0; + /* clear hash table */ + clear_hash(); + /* GIF specifies an initial Clear code */ + output(ClearCode); +} + + +LOCAL void +compress_byte (int c) +/* Accept and compress one 8-bit byte */ +{ + register hash_int i; + register hash_int disp; + + if (first_byte) { /* need to initialize waiting_code */ + waiting_code = c; + first_byte = FALSE; + return; + } + + /* Probe hash table to see if a symbol exists for + * waiting_code followed by c. + * If so, replace waiting_code by that symbol and return. + */ + i = ((hash_int) c << (MAX_LZW_BITS-8)) + waiting_code; + /* i is less than twice 2**MAX_LZW_BITS, therefore less than twice HSIZE */ + if (i >= HSIZE) + i -= HSIZE; + + if (hash_code[i] != 0) { /* is first probed slot empty? */ + if (hash_prefix[i] == waiting_code && hash_suffix[i] == c) { + waiting_code = hash_code[i]; + return; + } + if (i == 0) /* secondary hash (after G. Knott) */ + disp = 1; + else + disp = HSIZE - i; + while (1) { + i -= disp; + if (i < 0) + i += HSIZE; + if (hash_code[i] == 0) + break; /* hit empty slot */ + if (hash_prefix[i] == waiting_code && hash_suffix[i] == c) { + waiting_code = hash_code[i]; + return; + } + } + } + + /* here when hashtable[i] is an empty slot; desired symbol not in table */ + output(waiting_code); + if (free_code < LZW_TABLE_SIZE) { + hash_code[i] = free_code++; /* add symbol to hashtable */ + hash_prefix[i] = waiting_code; + hash_suffix[i] = c; + } else + clear_block(); + waiting_code = c; +} + + +LOCAL void +compress_term (void) +/* Clean up at end */ +{ + /* Flush out the buffered code */ + if (! first_byte) + output(waiting_code); + /* Send an EOF code */ + output(EOFCode); + /* Flush the bit-packing buffer */ + if (cur_bits > 0) { + char_out((int) (cur_accum & 0xFF)); + } + /* Flush the packet buffer */ + flush_packet(); +} + + +/* GIF header construction */ + + +LOCAL void +put_word (UINT16 w) +/* Emit a 16-bit word, LSB first */ +{ + putc(w & 0xFF, dcinfo->output_file); + putc((w >> 8) & 0xFF, dcinfo->output_file); +} + + +LOCAL void +put_3bytes (int val) +/* Emit 3 copies of same byte value --- handy subr for colormap construction */ +{ + putc(val, dcinfo->output_file); + putc(val, dcinfo->output_file); + putc(val, dcinfo->output_file); +} + + +LOCAL void +emit_header (int num_colors, JSAMPARRAY colormap) +/* Output the GIF file header, including color map */ +/* If colormap==NULL, synthesize a gray-scale colormap */ +{ + int BitsPerPixel, ColorMapSize, InitCodeSize, FlagByte; + int i; + + if (num_colors > 256) + ERREXIT(dcinfo->emethods, "GIF can only handle 256 colors"); + /* Compute bits/pixel and related values */ + if (num_colors <= 2) + BitsPerPixel = 1; + else if (num_colors <= 4) + BitsPerPixel = 2; + else if (num_colors <= 8) + BitsPerPixel = 3; + else if (num_colors <= 16) + BitsPerPixel = 4; + else if (num_colors <= 32) + BitsPerPixel = 5; + else if (num_colors <= 64) + BitsPerPixel = 6; + else if (num_colors <= 128) + BitsPerPixel = 7; + else + BitsPerPixel = 8; + ColorMapSize = 1 << BitsPerPixel; + if (BitsPerPixel <= 1) + InitCodeSize = 2; + else + InitCodeSize = BitsPerPixel; + /* + * Write the GIF header. + * Note that we generate a plain GIF87 header for maximum compatibility. + */ + fwrite("GIF87a", 1, 6, dcinfo->output_file); + /* Write the Logical Screen Descriptor */ + put_word((UINT16) dcinfo->image_width); + put_word((UINT16) dcinfo->image_height); + FlagByte = 0x80; /* Yes, there is a global color table */ + FlagByte |= (BitsPerPixel-1) << 4; /* color resolution */ + FlagByte |= (BitsPerPixel-1); /* size of global color table */ + putc(FlagByte, dcinfo->output_file); + putc(0, dcinfo->output_file); /* Background color index */ + putc(0, dcinfo->output_file); /* Reserved in GIF87 (aspect ratio in GIF89) */ + /* Write the Global Color Map */ + for (i=0; i < ColorMapSize; i++) { + if (i < num_colors) { + if (colormap != NULL) { + if (dcinfo->out_color_space == CS_RGB) { + /* Normal case: RGB color map */ + putc(GETJSAMPLE(colormap[0][i]), dcinfo->output_file); + putc(GETJSAMPLE(colormap[1][i]), dcinfo->output_file); + putc(GETJSAMPLE(colormap[2][i]), dcinfo->output_file); + } else { + /* Grayscale "color map": possible if quantizing grayscale image */ + put_3bytes(GETJSAMPLE(colormap[0][i])); + } + } else { + /* Create a gray-scale map of num_colors values, range 0..255 */ + put_3bytes((i * 255 + (num_colors-1)/2) / (num_colors-1)); + } + } else { + /* fill out the map to a power of 2 */ + put_3bytes(0); + } + } + /* Write image separator and Image Descriptor */ + putc(',', dcinfo->output_file); /* separator */ + put_word((UINT16) 0); /* left/top offset */ + put_word((UINT16) 0); + put_word((UINT16) dcinfo->image_width); /* image size */ + put_word((UINT16) dcinfo->image_height); + /* flag byte: not interlaced, no local color map */ + putc(0x00, dcinfo->output_file); + /* Write Initial Code Size byte */ + putc(InitCodeSize, dcinfo->output_file); + + /* Initialize for LZW compression of image data */ + compress_init(InitCodeSize+1); +} + + + +/* + * Initialize for GIF output. + */ + +METHODDEF void +output_init (decompress_info_ptr cinfo) +{ + dcinfo = cinfo; /* save for use by local routines */ + if (cinfo->final_out_comps != 1) /* safety check */ + ERREXIT(cinfo->emethods, "GIF output got confused"); + /* Allocate space for hash table */ + hash_code = (code_int FAR *) (*cinfo->emethods->alloc_medium) + (HSIZE * SIZEOF(code_int)); + hash_prefix = (code_int FAR *) (*cinfo->emethods->alloc_medium) + (HSIZE * SIZEOF(code_int)); + hash_suffix = (UINT8 FAR *) (*cinfo->emethods->alloc_medium) + (HSIZE * SIZEOF(UINT8)); + /* + * If we aren't quantizing, put_color_map won't be called, + * so emit the header now. This only happens with gray scale output. + * (If we are quantizing, wait for the color map to be provided.) + */ + if (! cinfo->quantize_colors) + emit_header(256, (JSAMPARRAY) NULL); +} + + +/* + * Write the color map. + */ + +METHODDEF void +put_color_map (decompress_info_ptr cinfo, int num_colors, JSAMPARRAY colormap) +{ + emit_header(num_colors, colormap); +} + + +/* + * Write some pixel data. + */ + +METHODDEF void +put_pixel_rows (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE pixel_data) +{ + register JSAMPROW ptr; + register long col; + register long width = cinfo->image_width; + register int row; + + for (row = 0; row < num_rows; row++) { + ptr = pixel_data[0][row]; + for (col = width; col > 0; col--) { + compress_byte(GETJSAMPLE(*ptr)); + ptr++; + } + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +output_term (decompress_info_ptr cinfo) +{ + /* Flush LZW mechanism */ + compress_term(); + /* Write a zero-length data block to end the series */ + putc(0, cinfo->output_file); + /* Write the GIF terminator mark */ + putc(';', cinfo->output_file); + /* Make sure we wrote the output file OK */ + fflush(cinfo->output_file); + if (ferror(cinfo->output_file)) + ERREXIT(cinfo->emethods, "Output file write error"); + /* Free space */ + (*cinfo->emethods->free_medium) ((void FAR *) hash_code); + (*cinfo->emethods->free_medium) ((void FAR *) hash_prefix); + (*cinfo->emethods->free_medium) ((void FAR *) hash_suffix); +} + + +/* + * The method selection routine for GIF format output. + * This should be called from d_ui_method_selection if GIF output is wanted. + */ + +GLOBAL void +jselwgif (decompress_info_ptr cinfo) +{ + cinfo->methods->output_init = output_init; + cinfo->methods->put_color_map = put_color_map; + cinfo->methods->put_pixel_rows = put_pixel_rows; + cinfo->methods->output_term = output_term; + + if (cinfo->out_color_space != CS_GRAYSCALE && + cinfo->out_color_space != CS_RGB) + ERREXIT(cinfo->emethods, "GIF output must be grayscale or RGB"); + + /* Force quantization if color or if > 8 bits input */ + if (cinfo->out_color_space == CS_RGB || cinfo->data_precision > 8) { + /* Force quantization to at most 256 colors */ + cinfo->quantize_colors = TRUE; + if (cinfo->desired_number_of_colors > 256) + cinfo->desired_number_of_colors = 256; + } +} + +#endif /* GIF_SUPPORTED */ diff --git a/jwrjfif.c b/jwrjfif.c new file mode 100644 index 0000000..cc379ac --- /dev/null +++ b/jwrjfif.c @@ -0,0 +1,468 @@ +/* + * jwrjfif.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write standard JPEG file headers/markers. + * The file format created is a raw JPEG data stream with (optionally) an + * APP0 marker per the JFIF spec. This will handle baseline and + * JFIF-convention JPEG files, although there is currently no provision + * for inserting a thumbnail image in the JFIF header. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. However, the changes to write to something + * else are localized in the macros appearing just below. + * + * These routines are invoked via the methods write_file_header, + * write_scan_header, write_jpeg_data, write_scan_trailer, and + * write_file_trailer. + */ + +#include "jinclude.h" + +#ifdef JFIF_SUPPORTED + + +/* + * To output to something other than a stdio stream, you'd need to redefine + * these macros. + */ + +/* Write a single byte */ +#define emit_byte(cinfo,x) putc((x), cinfo->output_file) + +/* Write some bytes from a (char *) buffer */ +#define WRITE_BYTES(cinfo,dataptr,datacount) \ + { if (fwrite((dataptr), 1, (datacount), cinfo->output_file) != (datacount)) \ + ERREXIT(cinfo->emethods, "Output file write error"); } + +/* Clean up and verify successful output */ +#define CHECK_OUTPUT(cinfo) \ + { fflush(cinfo->output_file); \ + if (ferror(cinfo->output_file)) \ + ERREXIT(cinfo->emethods, "Output file write error"); } + + +/* End of stdio-specific code. */ + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +LOCAL void +emit_marker (compress_info_ptr cinfo, JPEG_MARKER mark) +/* Emit a marker code */ +{ + emit_byte(cinfo, 0xFF); + emit_byte(cinfo, mark); +} + + +LOCAL void +emit_2bytes (compress_info_ptr cinfo, int value) +/* Emit a 2-byte integer; these are always MSB first in JPEG files */ +{ + emit_byte(cinfo, (value >> 8) & 0xFF); + emit_byte(cinfo, value & 0xFF); +} + + +LOCAL int +emit_dqt (compress_info_ptr cinfo, int index) +/* Emit a DQT marker */ +/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */ +{ + QUANT_TBL_PTR data = cinfo->quant_tbl_ptrs[index]; + int prec = 0; + int i; + + for (i = 0; i < DCTSIZE2; i++) { + if (data[i] > 255) + prec = 1; + } + + emit_marker(cinfo, M_DQT); + + emit_2bytes(cinfo, prec ? DCTSIZE2*2 + 1 + 2 : DCTSIZE2 + 1 + 2); + + emit_byte(cinfo, index + (prec<<4)); + + for (i = 0; i < DCTSIZE2; i++) { + if (prec) + emit_byte(cinfo, data[i] >> 8); + emit_byte(cinfo, data[i] & 0xFF); + } + + return prec; +} + + +LOCAL void +emit_dht (compress_info_ptr cinfo, int index, boolean is_ac) +/* Emit a DHT marker */ +{ + HUFF_TBL * htbl; + int length, i; + + if (is_ac) { + htbl = cinfo->ac_huff_tbl_ptrs[index]; + index += 0x10; /* output index has AC bit set */ + } else { + htbl = cinfo->dc_huff_tbl_ptrs[index]; + } + + if (! htbl->sent_table) { + emit_marker(cinfo, M_DHT); + + length = 0; + for (i = 1; i <= 16; i++) + length += htbl->bits[i]; + + emit_2bytes(cinfo, length + 2 + 1 + 16); + emit_byte(cinfo, index); + + for (i = 1; i <= 16; i++) + emit_byte(cinfo, htbl->bits[i]); + + for (i = 0; i < length; i++) + emit_byte(cinfo, htbl->huffval[i]); + + htbl->sent_table = TRUE; + } +} + + +LOCAL void +emit_dac (compress_info_ptr cinfo) +/* Emit a DAC marker */ +/* Since the useful info is so small, we want to emit all the tables in */ +/* one DAC marker. Therefore this routine does its own scan of the table. */ +{ + char dc_in_use[NUM_ARITH_TBLS]; + char ac_in_use[NUM_ARITH_TBLS]; + int length, i; + + for (i = 0; i < NUM_ARITH_TBLS; i++) + dc_in_use[i] = ac_in_use[i] = 0; + + for (i = 0; i < cinfo->num_components; i++) { + dc_in_use[cinfo->comp_info[i].dc_tbl_no] = 1; + ac_in_use[cinfo->comp_info[i].ac_tbl_no] = 1; + } + + length = 0; + for (i = 0; i < NUM_ARITH_TBLS; i++) + length += dc_in_use[i] + ac_in_use[i]; + + emit_marker(cinfo, M_DAC); + + emit_2bytes(cinfo, length*2 + 2); + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + if (dc_in_use[i]) { + emit_byte(cinfo, i); + emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4)); + } + if (ac_in_use[i]) { + emit_byte(cinfo, i + 0x10); + emit_byte(cinfo, cinfo->arith_ac_K[i]); + } + } +} + + +LOCAL void +emit_dri (compress_info_ptr cinfo) +/* Emit a DRI marker */ +{ + emit_marker(cinfo, M_DRI); + + emit_2bytes(cinfo, 4); /* fixed length */ + + emit_2bytes(cinfo, (int) cinfo->restart_interval); +} + + +LOCAL void +emit_sof (compress_info_ptr cinfo, JPEG_MARKER code) +/* Emit a SOF marker */ +{ + int i; + + emit_marker(cinfo, code); + + emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */ + + emit_byte(cinfo, cinfo->data_precision); + emit_2bytes(cinfo, (int) cinfo->image_height); + emit_2bytes(cinfo, (int) cinfo->image_width); + + emit_byte(cinfo, cinfo->num_components); + + for (i = 0; i < cinfo->num_components; i++) { + emit_byte(cinfo, cinfo->comp_info[i].component_id); + emit_byte(cinfo, (cinfo->comp_info[i].h_samp_factor << 4) + + cinfo->comp_info[i].v_samp_factor); + emit_byte(cinfo, cinfo->comp_info[i].quant_tbl_no); + } +} + + +LOCAL void +emit_sos (compress_info_ptr cinfo) +/* Emit a SOS marker */ +{ + int i; + + emit_marker(cinfo, M_SOS); + + emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */ + + emit_byte(cinfo, cinfo->comps_in_scan); + + for (i = 0; i < cinfo->comps_in_scan; i++) { + emit_byte(cinfo, cinfo->cur_comp_info[i]->component_id); + emit_byte(cinfo, (cinfo->cur_comp_info[i]->dc_tbl_no << 4) + + cinfo->cur_comp_info[i]->ac_tbl_no); + } + + emit_byte(cinfo, 0); /* Spectral selection start */ + emit_byte(cinfo, DCTSIZE2-1); /* Spectral selection end */ + emit_byte(cinfo, 0); /* Successive approximation */ +} + + +LOCAL void +emit_jfif_app0 (compress_info_ptr cinfo) +/* Emit a JFIF-compliant APP0 marker */ +{ + /* + * Length of APP0 block (2 bytes) + * Block ID (4 bytes - ASCII "JFIF") + * Zero byte (1 byte to terminate the ID string) + * Version Major, Minor (2 bytes - 0x01, 0x01) + * Units (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm) + * Xdpu (2 bytes - dots per unit horizontal) + * Ydpu (2 bytes - dots per unit vertical) + * Thumbnail X size (1 byte) + * Thumbnail Y size (1 byte) + */ + + emit_marker(cinfo, M_APP0); + + emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */ + + emit_byte(cinfo, 'J'); /* Identifier */ + emit_byte(cinfo, 'F'); + emit_byte(cinfo, 'I'); + emit_byte(cinfo, 'F'); + emit_byte(cinfo, 0); + emit_byte(cinfo, 1); /* Major version */ + emit_byte(cinfo, 1); /* Minor version */ + emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */ + emit_2bytes(cinfo, (int) cinfo->X_density); + emit_2bytes(cinfo, (int) cinfo->Y_density); + emit_byte(cinfo, 0); /* No thumbnail image */ + emit_byte(cinfo, 0); +} + + +/* + * Write the file header. + */ + + +METHODDEF void +write_file_header (compress_info_ptr cinfo) +{ + char qt_in_use[NUM_QUANT_TBLS]; + int i, prec; + boolean is_baseline; + + emit_marker(cinfo, M_SOI); /* first the SOI */ + + if (cinfo->write_JFIF_header) /* next an optional JFIF APP0 */ + emit_jfif_app0(cinfo); + + /* Emit DQT for each quantization table. */ + /* Note that doing it here means we can't adjust the QTs on-the-fly. */ + /* If we did want to do that, we'd have a problem with checking precision */ + /* for the is_baseline determination. */ + + for (i = 0; i < NUM_QUANT_TBLS; i++) + qt_in_use[i] = 0; + + for (i = 0; i < cinfo->num_components; i++) + qt_in_use[cinfo->comp_info[i].quant_tbl_no] = 1; + + prec = 0; + for (i = 0; i < NUM_QUANT_TBLS; i++) { + if (qt_in_use[i]) + prec += emit_dqt(cinfo, i); + } + /* now prec is nonzero iff there are any 16-bit quant tables. */ + + if (cinfo->restart_interval) + emit_dri(cinfo); + + /* Check for a non-baseline specification. */ + /* Note we assume that Huffman table numbers won't be changed later. */ + is_baseline = TRUE; + if (cinfo->arith_code || (cinfo->data_precision != 8)) + is_baseline = FALSE; + for (i = 0; i < cinfo->num_components; i++) { + if (cinfo->comp_info[i].dc_tbl_no > 1 || cinfo->comp_info[i].ac_tbl_no > 1) + is_baseline = FALSE; + } + if (prec && is_baseline) { + is_baseline = FALSE; + /* If it's baseline except for quantizer size, warn the user */ + TRACEMS(cinfo->emethods, 0, + "Caution: quantization tables are too coarse for baseline JPEG"); + } + + + /* Emit the proper SOF marker */ + if (cinfo->arith_code) + emit_sof(cinfo, M_SOF9); /* SOF code for arithmetic coding */ + else if (is_baseline) + emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */ + else + emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */ +} + + +/* + * Write the start of a scan (everything through the SOS marker). + */ + +METHODDEF void +write_scan_header (compress_info_ptr cinfo) +{ + int i; + + if (cinfo->arith_code) { + /* Emit arith conditioning info. We will have some duplication + * if the file has multiple scans, but it's so small it's hardly + * worth worrying about. + */ + emit_dac(cinfo); + } else { + /* Emit Huffman tables. Note that emit_dht takes care of + * suppressing duplicate tables. + */ + for (i = 0; i < cinfo->comps_in_scan; i++) { + emit_dht(cinfo, cinfo->cur_comp_info[i]->dc_tbl_no, FALSE); + emit_dht(cinfo, cinfo->cur_comp_info[i]->ac_tbl_no, TRUE); + } + } + + emit_sos(cinfo); +} + + +/* + * Write some bytes of compressed data within a scan. + */ + +METHODDEF void +write_jpeg_data (compress_info_ptr cinfo, char *dataptr, int datacount) +{ + WRITE_BYTES(cinfo, dataptr, datacount); +} + + +/* + * Finish up after a compressed scan (series of write_jpeg_data calls). + */ + +METHODDEF void +write_scan_trailer (compress_info_ptr cinfo) +{ + /* no work needed in this format */ +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +write_file_trailer (compress_info_ptr cinfo) +{ + emit_marker(cinfo, M_EOI); + /* Make sure we wrote the output file OK */ + CHECK_OUTPUT(cinfo); +} + + +/* + * The method selection routine for standard JPEG header writing. + * This should be called from c_ui_method_selection if appropriate. + */ + +GLOBAL void +jselwjfif (compress_info_ptr cinfo) +{ + cinfo->methods->write_file_header = write_file_header; + cinfo->methods->write_scan_header = write_scan_header; + cinfo->methods->write_jpeg_data = write_jpeg_data; + cinfo->methods->write_scan_trailer = write_scan_trailer; + cinfo->methods->write_file_trailer = write_file_trailer; +} + +#endif /* JFIF_SUPPORTED */ diff --git a/jwrppm.c b/jwrppm.c new file mode 100644 index 0000000..41687fe --- /dev/null +++ b/jwrppm.c @@ -0,0 +1,167 @@ +/* + * jwrppm.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in PPM format. + * The PBMPLUS library is required (well, it will be in the real version). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + * + * These routines are invoked via the methods put_pixel_rows, put_color_map, + * and output_init/term. + */ + +#include "jinclude.h" + +#ifdef PPM_SUPPORTED + + +static JSAMPARRAY color_map; /* saves color map passed by quantizer */ + + +/* + * Write the file header. + */ + +METHODDEF void +output_init (decompress_info_ptr cinfo) +{ + if (cinfo->out_color_space == CS_GRAYSCALE) { + /* emit header for raw PGM format */ + fprintf(cinfo->output_file, "P5\n%ld %ld\n%d\n", + cinfo->image_width, cinfo->image_height, 255); + } else if (cinfo->out_color_space == CS_RGB) { + /* emit header for raw PPM format */ + fprintf(cinfo->output_file, "P6\n%ld %ld\n%d\n", + cinfo->image_width, cinfo->image_height, 255); + } else { + ERREXIT(cinfo->emethods, "PPM output must be grayscale or RGB"); + } +} + + +/* + * Write some pixel data. + */ + +METHODDEF void +put_pixel_rows (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE pixel_data) +{ + register FILE * outfile = cinfo->output_file; + register JSAMPROW ptr0, ptr1, ptr2; + register long col; + register long width = cinfo->image_width; + register int row; + + if (cinfo->out_color_space == CS_GRAYSCALE) { + for (row = 0; row < num_rows; row++) { + ptr0 = pixel_data[0][row]; + for (col = width; col > 0; col--) { + putc(GETJSAMPLE(*ptr0), outfile); + ptr0++; + } + } + } else { + for (row = 0; row < num_rows; row++) { + ptr0 = pixel_data[0][row]; + ptr1 = pixel_data[1][row]; + ptr2 = pixel_data[2][row]; + for (col = width; col > 0; col--) { + putc(GETJSAMPLE(*ptr0), outfile); + ptr0++; + putc(GETJSAMPLE(*ptr1), outfile); + ptr1++; + putc(GETJSAMPLE(*ptr2), outfile); + ptr2++; + } + } + } +} + + +/* + * Write some pixel data when color quantization is in effect. + */ + +METHODDEF void +put_demapped_rows (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE pixel_data) +{ + register FILE * outfile = cinfo->output_file; + register JSAMPROW ptr; + register long col; + register long width = cinfo->image_width; + register int row; + + if (cinfo->out_color_space == CS_GRAYSCALE) { + for (row = 0; row < num_rows; row++) { + ptr = pixel_data[0][row]; + for (col = width; col > 0; col--) { + putc(GETJSAMPLE(color_map[0][GETJSAMPLE(*ptr)]), outfile); + ptr++; + } + } + } else { + for (row = 0; row < num_rows; row++) { + ptr = pixel_data[0][row]; + for (col = width; col > 0; col--) { + register int pixval = GETJSAMPLE(*ptr); + + putc(GETJSAMPLE(color_map[0][pixval]), outfile); + putc(GETJSAMPLE(color_map[1][pixval]), outfile); + putc(GETJSAMPLE(color_map[2][pixval]), outfile); + ptr++; + } + } + } +} + + +/* + * Write the color map. + * For PPM output, we just demap the output data! + */ + +METHODDEF void +put_color_map (decompress_info_ptr cinfo, int num_colors, JSAMPARRAY colormap) +{ + color_map = colormap; /* save for use in output */ + cinfo->methods->put_pixel_rows = put_demapped_rows; +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +output_term (decompress_info_ptr cinfo) +{ + /* No work except to make sure we wrote the output file OK */ + fflush(cinfo->output_file); + if (ferror(cinfo->output_file)) + ERREXIT(cinfo->emethods, "Output file write error"); +} + + +/* + * The method selection routine for PPM format output. + * This should be called from d_ui_method_selection if PPM output is wanted. + */ + +GLOBAL void +jselwppm (decompress_info_ptr cinfo) +{ + cinfo->methods->output_init = output_init; + cinfo->methods->put_color_map = put_color_map; + cinfo->methods->put_pixel_rows = put_pixel_rows; + cinfo->methods->output_term = output_term; +} + +#endif /* PPM_SUPPORTED */ diff --git a/makcjpeg.cf b/makcjpeg.cf new file mode 100644 index 0000000..ea93ce4 --- /dev/null +++ b/makcjpeg.cf @@ -0,0 +1,5 @@ +L jcmain.mix jerror.mix jcdeflts.mix jrdgif.mix jrdppm.mix jwrjfif.mix +L jcarith.mix jccolor.mix jcexpand.mix jchuff.mix jcmaster.mix jcmcu.mix +L jcpipe.mix jcsample.mix jfwddct.mix jutils.mix jvirtmem.mix +fa; +b cjpeg,8K,48K, diff --git a/makcjpeg.lnk b/makcjpeg.lnk new file mode 100644 index 0000000..23702b2 --- /dev/null +++ b/makcjpeg.lnk @@ -0,0 +1,21 @@ +jcmain.obj + +jerror.obj + +jcdeflts.obj + +jrdgif.obj + +jrdppm.obj + +jwrjfif.obj + +jcarith.obj + +jccolor.obj + +jcexpand.obj + +jchuff.obj + +jcmaster.obj + +jcmcu.obj + +jcpipe.obj + +jcsample.obj + +jfwddct.obj + +jutils.obj + +jvirtmem.obj +cjpeg.exe /NOI +nul.map + +nul.def diff --git a/makdjpeg.cf b/makdjpeg.cf new file mode 100644 index 0000000..968af31 --- /dev/null +++ b/makdjpeg.cf @@ -0,0 +1,6 @@ +L jdmain.mix jerror.mix jrdjfif.mix jwrgif.mix jwrppm.mix +L jbsmooth.mix jdarith.mix jdcolor.mix jdhuff.mix jdmaster.mix jdmcu.mix +L jdpipe.mix jdsample.mix jquant1.mix jquant2.mix jrevdct.mix jutils.mix +L jvirtmem.mix +fa; +b djpeg,8K,48K, diff --git a/makdjpeg.lnk b/makdjpeg.lnk new file mode 100644 index 0000000..6e9107c --- /dev/null +++ b/makdjpeg.lnk @@ -0,0 +1,22 @@ +jdmain.obj + +jerror.obj + +jrdjfif.obj + +jwrgif.obj + +jwrppm.obj + +jbsmooth.obj + +jdarith.obj + +jdcolor.obj + +jdhuff.obj + +jdmaster.obj + +jdmcu.obj + +jdpipe.obj + +jdsample.obj + +jquant1.obj + +jquant2.obj + +jrevdct.obj + +jutils.obj + +jvirtmem.obj /NOI +djpeg.exe +nul.map + +nul.def diff --git a/makefile.amiga b/makefile.amiga new file mode 100644 index 0000000..2fde93a --- /dev/null +++ b/makefile.amiga @@ -0,0 +1,143 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is suitable for Amiga systems using Manx Aztec C ver 5.x. +# Thanks to D.J. James for this version. + +# See README and edit jconfig.h before saying "make" !! + +CC= cc + +# You may need to adjust these cc options: +CFLAGS= -MC -MD -DTWO_FILE_COMMANDLINE +LDFLAGS= +LDLIBS= -lml -lcl + +# miscellaneous OS-dependent stuff +LN= ln # linker +RM= delete quiet # file deletion command +AR= lb # library (.lib) file creation command + + +# source files +INCLUDES= jinclude.h jconfig.h jpegdata.h +SOURCES= jbsmooth.c jcarith.c jccolor.c jcdeflts.c jcexpand.c \ + jchuff.c jcmain.c jcmaster.c jcmcu.c jcpipe.c jcsample.c \ + jdarith.c jdcolor.c jdhuff.c jdmain.c jdmaster.c jdmcu.c \ + jdpipe.c jdsample.c jerror.c jfwddct.c jquant1.c jquant2.c \ + jrdjfif.c jrdgif.c jrdppm.c jrevdct.c jutils.c jvirtmem.c \ + jwrjfif.c jwrgif.c jwrppm.c egetopt.c +DOCS= README architecture codingrules +MAKEFILES= makefile.unix makefile.amiga \ + makefile.mc5 makefile.mc6 makcjpeg.lnk makdjpeg.lnk \ + makefile.pwc makcjpeg.cf makdjpeg.cf makljpeg.cf +TESTFILES= testorig.jpg testimg.ppm testimg.jpg +DISTFILES= $(DOCS) $(MAKEFILES) ansi2knr.c $(SOURCES) $(INCLUDES) $(TESTFILES) + +# compression objectfiles +COBJECTS = jcmain.o jcmaster.o jcdeflts.o jcarith.o jccolor.o jcexpand.o \ + jchuff.o jcmcu.o jcpipe.o jcsample.o jfwddct.o \ + jrdgif.o jrdppm.o jwrjfif.o \ + jutils.o jvirtmem.o jerror.o +# decompression objectfiles +DOBJECTS = jdmain.o jdmaster.o jbsmooth.o jdarith.o jdcolor.o jdhuff.o \ + jdmcu.o jdpipe.o jdsample.o jquant1.o jquant2.o jrevdct.o \ + jrdjfif.o jwrgif.o jwrppm.o \ + jutils.o jvirtmem.o jerror.o +# These objectfiles are included in libjpeg.lib (all but jcmain.o, jdmain.o) +LIBOBJECTS = jcmaster.o jcdeflts.o jcarith.o jccolor.o jcexpand.o \ + jchuff.o jcmcu.o jcpipe.o jcsample.o jfwddct.o \ + jrdgif.o jrdppm.o jwrjfif.o \ + jdmaster.o jbsmooth.o jdarith.o jdcolor.o jdhuff.o \ + jdmcu.o jdpipe.o jdsample.o jquant1.o jquant2.o jrevdct.o \ + jrdjfif.o jwrgif.o jwrppm.o \ + jutils.o jvirtmem.o jerror.o + + +all: cjpeg djpeg +# By default, libjpeg.lib is not built unless you explicitly request it. + + +# If you have a C compiler that doesn't understand function prototypes, +# uncomment the 5 lines below and make sure PROTO is not defined by jconfig.h. +# Then say "make ansi2knr" before "make". + +#.c.o: +# ./ansi2knr $*.c tmpansi.c +# $(CC) $(CFLAGS) -c tmpansi.c +# mv tmpansi.o $*.o +# $(RM) tmpansi.c + +ansi2knr: ansi2knr.c + $(CC) -o ansi2knr ansi2knr.c +# You may need to add one of -DBSD, -DVMS, or -DMSDOS to the line above. + + +cjpeg: $(COBJECTS) + $(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) $(LDLIBS) + +djpeg: $(DOBJECTS) + $(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) $(LDLIBS) + +# libjpeg.lib is useful if you are including the JPEG software in a larger +# program; you'd include it in your link, rather than the individual modules. +libjpeg.lib: $(LIBOBJECTS) + -$(RM) libjpeg.lib + $(AR) libjpeg.lib $(LIBOBJECTS) + +# Use the following to test the built library +#cjpeg: jcmain.o libjpeg.lib +# $(LN) $(LDFLAGS) -o cjpeg jcmain.o -llibjpeg $(LDLIBS) +# +#djpeg: jdmain.o libjpeg.lib +# $(LN) $(LDFLAGS) -o djpeg jdmain.o -llibjpeg $(LDLIBS) + +clean: + -$(RM) *.o cjpeg djpeg libjpeg.lib ansi2knr core tmpansi.* testout.ppm testout.jpg + +distribute: + -$(RM) jpegsrc.tar* + tar cvf jpegsrc.tar $(DISTFILES) + list jpegsrc.tar + compress -v jpegsrc.tar + list jpegsrc.tar* + +test: cjpeg djpeg + -$(RM) testout.ppm testout.jpg + ./djpeg testorig.jpg testout.ppm + ./cjpeg testimg.ppm testout.jpg + cmp testimg.ppm testout.ppm + cmp testimg.jpg testout.jpg + + +jbsmooth.o : jbsmooth.c jinclude.h jconfig.h jpegdata.h +jcarith.o : jcarith.c jinclude.h jconfig.h jpegdata.h +jccolor.o : jccolor.c jinclude.h jconfig.h jpegdata.h +jcdeflts.o : jcdeflts.c jinclude.h jconfig.h jpegdata.h +jcexpand.o : jcexpand.c jinclude.h jconfig.h jpegdata.h +jchuff.o : jchuff.c jinclude.h jconfig.h jpegdata.h +jcmain.o : jcmain.c jinclude.h jconfig.h jpegdata.h egetopt.c +jcmaster.o : jcmaster.c jinclude.h jconfig.h jpegdata.h +jcmcu.o : jcmcu.c jinclude.h jconfig.h jpegdata.h +jcpipe.o : jcpipe.c jinclude.h jconfig.h jpegdata.h +jcsample.o : jcsample.c jinclude.h jconfig.h jpegdata.h +jdarith.o : jdarith.c jinclude.h jconfig.h jpegdata.h +jdcolor.o : jdcolor.c jinclude.h jconfig.h jpegdata.h +jdhuff.o : jdhuff.c jinclude.h jconfig.h jpegdata.h +jdmain.o : jdmain.c jinclude.h jconfig.h jpegdata.h egetopt.c +jdmaster.o : jdmaster.c jinclude.h jconfig.h jpegdata.h +jdmcu.o : jdmcu.c jinclude.h jconfig.h jpegdata.h +jdpipe.o : jdpipe.c jinclude.h jconfig.h jpegdata.h +jdsample.o : jdsample.c jinclude.h jconfig.h jpegdata.h +jerror.o : jerror.c jinclude.h jconfig.h jpegdata.h +jfwddct.o : jfwddct.c jinclude.h jconfig.h jpegdata.h +jquant1.o : jquant1.c jinclude.h jconfig.h jpegdata.h +jquant2.o : jquant2.c jinclude.h jconfig.h jpegdata.h +jrdjfif.o : jrdjfif.c jinclude.h jconfig.h jpegdata.h +jrdgif.o : jrdgif.c jinclude.h jconfig.h jpegdata.h +jrdppm.o : jrdppm.c jinclude.h jconfig.h jpegdata.h +jrevdct.o : jrevdct.c jinclude.h jconfig.h jpegdata.h +jutils.o : jutils.c jinclude.h jconfig.h jpegdata.h +jvirtmem.o : jvirtmem.c jinclude.h jconfig.h jpegdata.h +jwrjfif.o : jwrjfif.c jinclude.h jconfig.h jpegdata.h +jwrgif.o : jwrgif.c jinclude.h jconfig.h jpegdata.h +jwrppm.o : jwrppm.c jinclude.h jconfig.h jpegdata.h diff --git a/makefile.mc5 b/makefile.mc5 new file mode 100644 index 0000000..eee9f21 --- /dev/null +++ b/makefile.mc5 @@ -0,0 +1,115 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is for Microsoft C for MS-DOS, version 5.x. + +# See README and edit jconfig.h before saying "make" !! + +# Microsoft's brain-damaged version of make uses nonstandard syntax (a blank +# line is needed to terminate a command list) and it simply scans the rules +# in order, rather than doing a true dependency-tree walk. Furthermore, +# expanded command lines can't exceed 128 chars (this is a DOS bug, not +# make's fault); so we can't just name all the objectfiles in the link steps. +# Instead we shove each objectfile into a library as it is made, and link +# from the library. The objectfiles are also kept separately as timestamps. + +# You may need to adjust these cc options: +CFLAGS= /AS /I. /W3 /Oail /Gs /DMEM_STATS # NB: /Gs turns off stack oflo checks +LDFLAGS= /Fm /F 2000 # /F hhhh sets stack size (in hex) +# In particular: +# Add /DMSDOS if your compiler doesn't automatically #define MSDOS. +# Add /DHAVE_GETOPT if your library includes getopt(3) (see jcmain.c, jdmain.c). +# /DMEM_STATS is optional -- it enables gathering of memory usage statistics. + +# compression objectfiles +COBJECTS = jcmain.obj jcmaster.obj jcdeflts.obj jcarith.obj jccolor.obj jcexpand.obj \ + jchuff.obj jcmcu.obj jcpipe.obj jcsample.obj jfwddct.obj \ + jrdgif.obj jrdppm.obj jwrjfif.obj \ + jutils.obj jvirtmem.obj jerror.obj +# decompression objectfiles +DOBJECTS = jdmain.obj jdmaster.obj jbsmooth.obj jdarith.obj jdcolor.obj jdhuff.obj \ + jdmcu.obj jdpipe.obj jdsample.obj jquant1.obj jquant2.obj jrevdct.obj \ + jrdjfif.obj jwrgif.obj jwrppm.obj \ + jutils.obj jvirtmem.obj jerror.obj + + +# inference rule used for all compilations except jcmain.c, jdmain.c +# notice that objectfile is also inserted into libjpeg.lib +.c.obj: + cl $(CFLAGS) /c $*.c + lib libjpeg -+$*.obj; + +# these two objectfiles are not inserted into libjpeg +# because they have duplicate global symbol names (notably main()). +jcmain.obj: jcmain.c jinclude.h jconfig.h jpegdata.h egetopt.c + cl $(CFLAGS) /c $*.c + +jdmain.obj: jdmain.c jinclude.h jconfig.h jpegdata.h egetopt.c + cl $(CFLAGS) /c $*.c + + +jbsmooth.obj: jbsmooth.c jinclude.h jconfig.h jpegdata.h + +jcarith.obj: jcarith.c jinclude.h jconfig.h jpegdata.h + +jccolor.obj: jccolor.c jinclude.h jconfig.h jpegdata.h + +jcdeflts.obj: jcdeflts.c jinclude.h jconfig.h jpegdata.h + +jcexpand.obj: jcexpand.c jinclude.h jconfig.h jpegdata.h + +jchuff.obj: jchuff.c jinclude.h jconfig.h jpegdata.h + +jcmaster.obj: jcmaster.c jinclude.h jconfig.h jpegdata.h + +jcmcu.obj: jcmcu.c jinclude.h jconfig.h jpegdata.h + +jcpipe.obj: jcpipe.c jinclude.h jconfig.h jpegdata.h + +jcsample.obj: jcsample.c jinclude.h jconfig.h jpegdata.h + +jdarith.obj: jdarith.c jinclude.h jconfig.h jpegdata.h + +jdcolor.obj: jdcolor.c jinclude.h jconfig.h jpegdata.h + +jdhuff.obj: jdhuff.c jinclude.h jconfig.h jpegdata.h + +jdmaster.obj: jdmaster.c jinclude.h jconfig.h jpegdata.h + +jdmcu.obj: jdmcu.c jinclude.h jconfig.h jpegdata.h + +jdpipe.obj: jdpipe.c jinclude.h jconfig.h jpegdata.h + +jdsample.obj: jdsample.c jinclude.h jconfig.h jpegdata.h + +jerror.obj: jerror.c jinclude.h jconfig.h jpegdata.h + +jfwddct.obj: jfwddct.c jinclude.h jconfig.h jpegdata.h + +jquant1.obj: jquant1.c jinclude.h jconfig.h jpegdata.h + +jquant2.obj: jquant2.c jinclude.h jconfig.h jpegdata.h + +jrdjfif.obj: jrdjfif.c jinclude.h jconfig.h jpegdata.h + +jrdgif.obj: jrdgif.c jinclude.h jconfig.h jpegdata.h + +jrdppm.obj: jrdppm.c jinclude.h jconfig.h jpegdata.h + +jrevdct.obj: jrevdct.c jinclude.h jconfig.h jpegdata.h + +jutils.obj: jutils.c jinclude.h jconfig.h jpegdata.h + +jvirtmem.obj: jvirtmem.c jinclude.h jconfig.h jpegdata.h + +jwrjfif.obj: jwrjfif.c jinclude.h jconfig.h jpegdata.h + +jwrgif.obj: jwrgif.c jinclude.h jconfig.h jpegdata.h + +jwrppm.obj: jwrppm.c jinclude.h jconfig.h jpegdata.h + + +cjpeg.exe: $(COBJECTS) + cl /Fecjpeg.exe jcmain.obj libjpeg.lib $(LDFLAGS) + +djpeg.exe: $(DOBJECTS) + cl /Fedjpeg.exe jdmain.obj libjpeg.lib $(LDFLAGS) diff --git a/makefile.mc6 b/makefile.mc6 new file mode 100644 index 0000000..b9ca60f --- /dev/null +++ b/makefile.mc6 @@ -0,0 +1,79 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is for Microsoft C for MS-DOS, version 6.x (use NMAKE). +# Thanks to Alan Wright and Chris Turner of Olivetti Research Ltd. + +# See README and edit jconfig.h before saying "make" !! + +all: cjpeg.exe djpeg.exe + +# compiler flags. -D gives a #define to the sources: +# -O default optimisation +# -W3 warning level 3 +# -Za ANSI conformance, defines__STDC__ but undefines far +# and near! +# -D__STDC__ pretend we have full ANSI compliance. MSC is near +# enough anyway +# -DMSDOS we are on an MSDOS machine +# -DMEM_STATS enable memory usage statistics (optional) +# -DHAVE_GETOPT library has getopt routine to parse cmnd line options +# -c compile, don't link (implicit in inference rules) + +CFLAGS = -c -O -W3 -DMSDOS -D__STDC__ -DMEM_STATS + + +# compression objectfiles +COBJECTS = jcmain.obj jcmaster.obj jcdeflts.obj jcarith.obj jccolor.obj jcexpand.obj \ + jchuff.obj jcmcu.obj jcpipe.obj jcsample.obj jfwddct.obj \ + jrdgif.obj jrdppm.obj jwrjfif.obj \ + jutils.obj jvirtmem.obj jerror.obj +# decompression objectfiles +DOBJECTS = jdmain.obj jdmaster.obj jbsmooth.obj jdarith.obj jdcolor.obj jdhuff.obj \ + jdmcu.obj jdpipe.obj jdsample.obj jquant1.obj jquant2.obj jrevdct.obj \ + jrdjfif.obj jwrgif.obj jwrppm.obj \ + jutils.obj jvirtmem.obj jerror.obj + + +# default rules in nmake will use cflags and compile the list below + +jbsmooth.o : jbsmooth.c jinclude.h jconfig.h jpegdata.h +jcarith.o : jcarith.c jinclude.h jconfig.h jpegdata.h +jccolor.o : jccolor.c jinclude.h jconfig.h jpegdata.h +jcdeflts.o : jcdeflts.c jinclude.h jconfig.h jpegdata.h +jcexpand.o : jcexpand.c jinclude.h jconfig.h jpegdata.h +jchuff.o : jchuff.c jinclude.h jconfig.h jpegdata.h +jcmain.o : jcmain.c jinclude.h jconfig.h jpegdata.h egetopt.c +jcmaster.o : jcmaster.c jinclude.h jconfig.h jpegdata.h +jcmcu.o : jcmcu.c jinclude.h jconfig.h jpegdata.h +jcpipe.o : jcpipe.c jinclude.h jconfig.h jpegdata.h +jcsample.o : jcsample.c jinclude.h jconfig.h jpegdata.h +jdarith.o : jdarith.c jinclude.h jconfig.h jpegdata.h +jdcolor.o : jdcolor.c jinclude.h jconfig.h jpegdata.h +jdhuff.o : jdhuff.c jinclude.h jconfig.h jpegdata.h +jdmain.o : jdmain.c jinclude.h jconfig.h jpegdata.h egetopt.c +jdmaster.o : jdmaster.c jinclude.h jconfig.h jpegdata.h +jdmcu.o : jdmcu.c jinclude.h jconfig.h jpegdata.h +jdpipe.o : jdpipe.c jinclude.h jconfig.h jpegdata.h +jdsample.o : jdsample.c jinclude.h jconfig.h jpegdata.h +jerror.o : jerror.c jinclude.h jconfig.h jpegdata.h +jfwddct.o : jfwddct.c jinclude.h jconfig.h jpegdata.h +jquant1.o : jquant1.c jinclude.h jconfig.h jpegdata.h +jquant2.o : jquant2.c jinclude.h jconfig.h jpegdata.h +jrdjfif.o : jrdjfif.c jinclude.h jconfig.h jpegdata.h +jrdgif.o : jrdgif.c jinclude.h jconfig.h jpegdata.h +jrdppm.o : jrdppm.c jinclude.h jconfig.h jpegdata.h +jrevdct.o : jrevdct.c jinclude.h jconfig.h jpegdata.h +jutils.o : jutils.c jinclude.h jconfig.h jpegdata.h +jvirtmem.o : jvirtmem.c jinclude.h jconfig.h jpegdata.h +jwrjfif.o : jwrjfif.c jinclude.h jconfig.h jpegdata.h +jwrgif.o : jwrgif.c jinclude.h jconfig.h jpegdata.h +jwrppm.o : jwrppm.c jinclude.h jconfig.h jpegdata.h + + +# use linker response files because file list > 128 chars + +cjpeg.exe: $(COBJECTS) + link /STACK:8192 @makcjpeg.lnk + +djpeg.exe: $(DOBJECTS) + link /STACK:8192 @makdjpeg.lnk diff --git a/makefile.pwc b/makefile.pwc new file mode 100644 index 0000000..f41dd48 --- /dev/null +++ b/makefile.pwc @@ -0,0 +1,100 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is for Mix Software's Power C, v2.1.1 +# and Dan Grayson's pd make 2.14 under MS-DOS. +# Thanks to Bob Hardy for this version. + +# See README and edit jconfig.h before saying "make" !! + +# NOTE: make sure you have converted end-of-line markers to CR/LF in this file +# and in the three mak*.cf files; otherwise pd make and the Mix linker will +# choke. Power C doesn't seem to care whether end-of-lines are CR/LF or just +# LF in the *.h and *.c files. If you blindly converted LF to CR/LF in ALL +# the files, then you broke the test*.* files, which contain binary data. + +CC=pc + +# You may need to adjust these cc options: +MODEL=m +CFLAGS=-dMEM_STATS -dMSDOS -m$(MODEL) +LDFLAGS= +# In particular: +# -dMEM_STATS is optional -- it enables gathering of memory usage statistics. +LDLIBS= + +# miscellaneous OS-dependent stuff +# linker +LN=pcl +# file deletion command +RM=del +# library (.mix) file creation command +AR=merge + + +# compression objectfiles +COBJECTS = jcmain.mix jcmaster.mix jcdeflts.mix jcarith.mix jccolor.mix jcexpand.mix jchuff.mix jcmcu.mix jcpipe.mix jcsample.mix jfwddct.mix jrdgif.mix jrdppm.mix jwrjfif.mix jutils.mix jvirtmem.mix jerror.mix +# decompression objectfiles +DOBJECTS = jdmain.mix jdmaster.mix jbsmooth.mix jdarith.mix jdcolor.mix jdhuff.mix jdmcu.mix jdpipe.mix jdsample.mix jquant1.mix jquant2.mix jrevdct.mix jrdjfif.mix jwrgif.mix jwrppm.mix jutils.mix jvirtmem.mix jerror.mix +# These objectfiles are included in libjpeg.mix (all but jcmain, jdmain) +LIBOBJECTS = jcmaster.mix jcdeflts.mix jcarith.mix jccolor.mix jcexpand.mix jchuff.mix jcmcu.mix jcpipe.mix jcsample.mix jfwddct.mix jrdgif.mix jrdppm.mix jwrjfif.mix jdmaster.mix jbsmooth.mix jdarith.mix jdcolor.mix jdhuff.mix jdmcu.mix jdpipe.mix jdsample.mix jquant1.mix jquant2.mix jrevdct.mix jrdjfif.mix jwrgif.mix jwrppm.mix jutils.mix jvirtmem.mix jerror.mix + + +all: cjpeg.exe djpeg.exe test +# By default, libjpeg.mix is not built unless you explicitly request it. + + +cjpeg.exe: $(COBJECTS) + $(LN) $(LDFLAGS) @makcjpeg.cf + +djpeg.exe: $(DOBJECTS) + $(LN) $(LDFLAGS) @makdjpeg.cf + +# libjpeg.mix is useful if you are including the JPEG software in a larger +# program; you'd include it in your link, rather than the individual modules. +libjpeg.mix: $(LIBOBJECTS) + @$(RM) libjpeg.mix + $(AR) libjpeg.mix @makljpeg.cf + +clean: + $(RM) *.mix cjpeg.exe djpeg.exe testout.* + +test: + @$(RM) testout.* + +djpeg testorig.jpg testout.ppm + +cjpeg testimg.ppm testout.jpg + fc testimg.ppm testout.ppm + fc testimg.jpg testout.jpg + + +jbsmooth.mix : jbsmooth.c jinclude.h jconfig.h jpegdata.h +jcarith.mix : jcarith.c jinclude.h jconfig.h jpegdata.h +jccolor.mix : jccolor.c jinclude.h jconfig.h jpegdata.h +jcdeflts.mix : jcdeflts.c jinclude.h jconfig.h jpegdata.h +jcexpand.mix : jcexpand.c jinclude.h jconfig.h jpegdata.h +jchuff.mix : jchuff.c jinclude.h jconfig.h jpegdata.h +jcmain.mix : jcmain.c jinclude.h jconfig.h jpegdata.h egetopt.c +jcmaster.mix : jcmaster.c jinclude.h jconfig.h jpegdata.h +jcmcu.mix : jcmcu.c jinclude.h jconfig.h jpegdata.h +jcpipe.mix : jcpipe.c jinclude.h jconfig.h jpegdata.h +jcsample.mix : jcsample.c jinclude.h jconfig.h jpegdata.h +jdarith.mix : jdarith.c jinclude.h jconfig.h jpegdata.h +jdcolor.mix : jdcolor.c jinclude.h jconfig.h jpegdata.h +jdhuff.mix : jdhuff.c jinclude.h jconfig.h jpegdata.h +jdmain.mix : jdmain.c jinclude.h jconfig.h jpegdata.h egetopt.c +jdmaster.mix : jdmaster.c jinclude.h jconfig.h jpegdata.h +jdmcu.mix : jdmcu.c jinclude.h jconfig.h jpegdata.h +jdpipe.mix : jdpipe.c jinclude.h jconfig.h jpegdata.h +jdsample.mix : jdsample.c jinclude.h jconfig.h jpegdata.h +jerror.mix : jerror.c jinclude.h jconfig.h jpegdata.h +jfwddct.mix : jfwddct.c jinclude.h jconfig.h jpegdata.h +jquant1.mix : jquant1.c jinclude.h jconfig.h jpegdata.h +jquant2.mix : jquant2.c jinclude.h jconfig.h jpegdata.h +jrdjfif.mix : jrdjfif.c jinclude.h jconfig.h jpegdata.h +jrdgif.mix : jrdgif.c jinclude.h jconfig.h jpegdata.h +jrdppm.mix : jrdppm.c jinclude.h jconfig.h jpegdata.h +jrevdct.mix : jrevdct.c jinclude.h jconfig.h jpegdata.h +jutils.mix : jutils.c jinclude.h jconfig.h jpegdata.h +jvirtmem.mix : jvirtmem.c jinclude.h jconfig.h jpegdata.h +jwrjfif.mix : jwrjfif.c jinclude.h jconfig.h jpegdata.h +jwrgif.mix : jwrgif.c jinclude.h jconfig.h jpegdata.h +jwrppm.mix : jwrppm.c jinclude.h jconfig.h jpegdata.h diff --git a/makefile.unix b/makefile.unix new file mode 100644 index 0000000..0f11afa --- /dev/null +++ b/makefile.unix @@ -0,0 +1,152 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is suitable for Unix-like systems. + +# See README and edit jconfig.h before saying "make" !! + +# Comment out this line if you don't have gcc: +CC=gcc + +# You may need to adjust these cc options: +CFLAGS= -O -g -Wall -DHAVE_GETOPT -DMEM_STATS +LDFLAGS= -g +# In particular: +# Remove -g and -Wall if not using gcc. +# Add -DBSD if on a pure BSD system (see jinclude.h). +# Remove -DHAVE_GETOPT if you don't have getopt(3) (see jcmain.c, jdmain.c). +# -DMEM_STATS is optional -- it enables gathering of memory usage statistics. +# You may also want to add -DTWO_FILE_COMMANDLINE or -D switches for other +# symbols listed in jconfig.h, if you prefer not to change jconfig.h. +# If your compiler is non-ANSI, also see the .c.o rule below. + +# On HP-UX (and probably other SysV systems) the alternate malloc(3X) is a lot +# faster than the standard malloc; this makes a noticeable difference in the +# startup time when handling big noninterleaved images. I say "-lmalloc" to +# get the alternate allocator. On most non-SysV systems you can just +# define LDLIBS as empty. +LDLIBS= -lmalloc + +# miscellaneous OS-dependent stuff +LN= $(CC) # linker +RM= rm -f # file deletion command +AR= ar rc # library (.a) file creation command +AR2= ranlib # second step in .a creation (use "touch" if not needed) + + +# source files +INCLUDES= jinclude.h jconfig.h jpegdata.h +SOURCES= jbsmooth.c jcarith.c jccolor.c jcdeflts.c jcexpand.c \ + jchuff.c jcmain.c jcmaster.c jcmcu.c jcpipe.c jcsample.c \ + jdarith.c jdcolor.c jdhuff.c jdmain.c jdmaster.c jdmcu.c \ + jdpipe.c jdsample.c jerror.c jfwddct.c jquant1.c jquant2.c \ + jrdjfif.c jrdgif.c jrdppm.c jrevdct.c jutils.c jvirtmem.c \ + jwrjfif.c jwrgif.c jwrppm.c egetopt.c +DOCS= README architecture codingrules +MAKEFILES= makefile.unix makefile.amiga \ + makefile.mc5 makefile.mc6 makcjpeg.lnk makdjpeg.lnk \ + makefile.pwc makcjpeg.cf makdjpeg.cf makljpeg.cf +TESTFILES= testorig.jpg testimg.ppm testimg.jpg +DISTFILES= $(DOCS) $(MAKEFILES) ansi2knr.c $(SOURCES) $(INCLUDES) $(TESTFILES) + +# compression objectfiles +COBJECTS = jcmain.o jcmaster.o jcdeflts.o jcarith.o jccolor.o jcexpand.o \ + jchuff.o jcmcu.o jcpipe.o jcsample.o jfwddct.o \ + jrdgif.o jrdppm.o jwrjfif.o \ + jutils.o jvirtmem.o jerror.o +# decompression objectfiles +DOBJECTS = jdmain.o jdmaster.o jbsmooth.o jdarith.o jdcolor.o jdhuff.o \ + jdmcu.o jdpipe.o jdsample.o jquant1.o jquant2.o jrevdct.o \ + jrdjfif.o jwrgif.o jwrppm.o \ + jutils.o jvirtmem.o jerror.o +# These objectfiles are included in libjpeg.a (all but jcmain.o, jdmain.o) +LIBOBJECTS = jcmaster.o jcdeflts.o jcarith.o jccolor.o jcexpand.o \ + jchuff.o jcmcu.o jcpipe.o jcsample.o jfwddct.o \ + jrdgif.o jrdppm.o jwrjfif.o \ + jdmaster.o jbsmooth.o jdarith.o jdcolor.o jdhuff.o \ + jdmcu.o jdpipe.o jdsample.o jquant1.o jquant2.o jrevdct.o \ + jrdjfif.o jwrgif.o jwrppm.o \ + jutils.o jvirtmem.o jerror.o + + +all: cjpeg djpeg +# By default, libjpeg.a is not built unless you explicitly request it. + + +# If you have a C compiler that doesn't understand function prototypes, +# uncomment the 5 lines below and make sure PROTO is not defined by jconfig.h. +# Then say "make ansi2knr" before "make". + +#.c.o: +# ./ansi2knr $*.c tmpansi.c +# $(CC) $(CFLAGS) -c tmpansi.c +# mv tmpansi.o $*.o +# $(RM) tmpansi.c + +ansi2knr: ansi2knr.c + $(CC) -o ansi2knr ansi2knr.c +# You may need to add one of -DBSD, -DVMS, or -DMSDOS to the line above. + + +cjpeg: $(COBJECTS) + $(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) $(LDLIBS) + +djpeg: $(DOBJECTS) + $(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) $(LDLIBS) + +# libjpeg.a is useful if you are including the JPEG software in a larger +# program; you'd include it in your link, rather than the individual modules. +libjpeg.a: $(LIBOBJECTS) + $(RM) libjpeg.a + $(AR) libjpeg.a $(LIBOBJECTS) + $(AR2) libjpeg.a + +clean: + $(RM) *.o cjpeg djpeg libjpeg.a ansi2knr core tmpansi.* testout.ppm testout.jpg + +distribute: + $(RM) jpegsrc.tar* + tar cvf jpegsrc.tar $(DISTFILES) + ls -l jpegsrc.tar + compress -v jpegsrc.tar + ls -l jpegsrc.tar* + +test: cjpeg djpeg + $(RM) testout.ppm testout.jpg + ./djpeg testorig.jpg >testout.ppm + ./cjpeg testimg.ppm >testout.jpg + cmp testimg.ppm testout.ppm + cmp testimg.jpg testout.jpg + + +jbsmooth.o : jbsmooth.c jinclude.h jconfig.h jpegdata.h +jcarith.o : jcarith.c jinclude.h jconfig.h jpegdata.h +jccolor.o : jccolor.c jinclude.h jconfig.h jpegdata.h +jcdeflts.o : jcdeflts.c jinclude.h jconfig.h jpegdata.h +jcexpand.o : jcexpand.c jinclude.h jconfig.h jpegdata.h +jchuff.o : jchuff.c jinclude.h jconfig.h jpegdata.h +jcmain.o : jcmain.c jinclude.h jconfig.h jpegdata.h egetopt.c +jcmaster.o : jcmaster.c jinclude.h jconfig.h jpegdata.h +jcmcu.o : jcmcu.c jinclude.h jconfig.h jpegdata.h +jcpipe.o : jcpipe.c jinclude.h jconfig.h jpegdata.h +jcsample.o : jcsample.c jinclude.h jconfig.h jpegdata.h +jdarith.o : jdarith.c jinclude.h jconfig.h jpegdata.h +jdcolor.o : jdcolor.c jinclude.h jconfig.h jpegdata.h +jdhuff.o : jdhuff.c jinclude.h jconfig.h jpegdata.h +jdmain.o : jdmain.c jinclude.h jconfig.h jpegdata.h egetopt.c +jdmaster.o : jdmaster.c jinclude.h jconfig.h jpegdata.h +jdmcu.o : jdmcu.c jinclude.h jconfig.h jpegdata.h +jdpipe.o : jdpipe.c jinclude.h jconfig.h jpegdata.h +jdsample.o : jdsample.c jinclude.h jconfig.h jpegdata.h +jerror.o : jerror.c jinclude.h jconfig.h jpegdata.h +jfwddct.o : jfwddct.c jinclude.h jconfig.h jpegdata.h +jquant1.o : jquant1.c jinclude.h jconfig.h jpegdata.h +jquant2.o : jquant2.c jinclude.h jconfig.h jpegdata.h +jrdjfif.o : jrdjfif.c jinclude.h jconfig.h jpegdata.h +jrdgif.o : jrdgif.c jinclude.h jconfig.h jpegdata.h +jrdppm.o : jrdppm.c jinclude.h jconfig.h jpegdata.h +jrevdct.o : jrevdct.c jinclude.h jconfig.h jpegdata.h +jutils.o : jutils.c jinclude.h jconfig.h jpegdata.h +jvirtmem.o : jvirtmem.c jinclude.h jconfig.h jpegdata.h +jwrjfif.o : jwrjfif.c jinclude.h jconfig.h jpegdata.h +jwrgif.o : jwrgif.c jinclude.h jconfig.h jpegdata.h +jwrppm.o : jwrppm.c jinclude.h jconfig.h jpegdata.h diff --git a/makljpeg.cf b/makljpeg.cf new file mode 100644 index 0000000..3325bf4 --- /dev/null +++ b/makljpeg.cf @@ -0,0 +1,5 @@ +jbsmooth.mix,jcarith.mix,jccolor.mix,jcdeflts.mix,jcexpand.mix,jchuff.mix +jcmaster.mix,jcmcu.mix,jcpipe.mix,jcsample.mix,jdarith.mix,jdcolor.mix +jdhuff.mix,jdmaster.mix,jdmcu.mix,jdpipe.mix,jdsample.mix,jerror.mix +jfwddct.mix,jquant1.mix,jquant2.mix,jrdgif.mix,jrdjfif.mix,jrdppm.mix +jrevdct.mix,jutils.mix,jvirtmem.mix,jwrgif.mix,jwrjfif.mix,jwrppm.mix diff --git a/testimg.jpg b/testimg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b6b68bc7bee62b012c9937c09df2f63819125b0c GIT binary patch literal 3583 zcmbW3dsLIxmcTy*9|%+tQ3+5hU~G9-AVfvWwU%f^s$df!fUJs%B=Jj>S45HATLr6> zvH*dBjCGJlB_9cfN5VUEMII5Nf&_$*Bo~CJ!6XVohx^?T;pEAYq#v$dw88w)Q{^uE^Q6`OHtJZ&u@8u zb&ei+?-g`5^(Whn+qUm;LF`8E`SL68U{nZt-~Izfz6-}3J%&Ag`Uf07CN_?ce2z#u zpF*ajrDtR^E@xf2ej_*U=Fhio7nj^AEi3=Gipu-dHMMoWKd5InHMg|#1#Rsek9r^X z^$!e+o{YX2lZ;QioSd4OeKj|)c>U(B^26fN$K@66s_xStTvmYfKd>z8KfwNl%hAHM z#>U3lX8j*rR%;lRY3*pUcGuo@TMkF9|M8NON8n#JZ2h*ViuYGr&!Fh{&Sz6cHg59@ zp4t835469N{qMkj`hSuA571BZ~LCWOu{(>hU`2)!HfHg3s_o@oWC83*X(paJW8eG)LD}Mw(*F`%WpN zpvX-hvSI2beH8xFF}2@RB)ca9)VJ~uh~_4_DmY$2;@p4gLp|$$JZyI|Y={VNY5|d& zu7_M@Ni4`gs7wgos$#OgOV1LRWXNPk$PlAmna|mccfA4=vM4Z)c?)``XakSLw!sJ} z2%Hl3o++AjK@1!&5wYHVV5>+;UGjIFEX{S0uyl&-!tgeTJGeRXL0<~Vr!>LwsOIJZ zX8tOaxV=!JgZ3Ax|-CN-tr#`%}b(HYY8$oQG6 z>RvBU-=Rc;P#ikV?<+(&GD}@gU2%uvzE*x7fwe|KSWgLaM7j)r=k9D8{&?W? z75c^ov>kGxup)=<&!x&vTec8Y`$oC6(f3;U$Xt zmdggs0eZlYE|YBr9D*AflKs@!`s~r80u2aF(Lc4 zYBSKlT8%N5a$fDc{Dd~L-wYsvnUhNapG2k1zkO{6R&bksYLWBaQoZu|*d7Y&F?HqV z8G#u%O&RsJSlW6|6?H)LJ6mMKDrM%?^>F)UUe!MB*f)OHLq+HvT^^*B8_%juDr%PO ztWo&{IhwzVL;^WcqD8Kn+DPwE!Tb8{kY z^*rMz6O(Kq>1Ot9Uh4g zz4}rU(hQUp7?pFH^fpo#j9?oicZ|BpyXlP^57kBWM~0*7=OP(eLK|xtPM5rh z%ux7GZl}hC<_LSFxNwxG?-9kXH^-s_nW!XJmCL>_}fo;3PweMNSk9;TL^ zlpXrg2NSaQ$L8XY#krz$W`HEv<}BdpJIN2@*kYryaW?VW(D;yoct!o&R90uxK{N39 z)6I$?3@5>m>HAzKztZ?UCs^#sbf%Ion&!)Cn#!tBC$H(-Ar5rvrcaR_YN;XYN=^G1 zXNI(xqtQ~MQ&f2H1$SzG*$g1DU4w)UzwJ)zUb|#%Nf5cuT`hY^OQv^f*;Gu)YRo(o zN%!wCUP8)=m z(~j!<7EL5PClZyMw{r#*_MPHzx+t7I!*I?53Tu>#I~6)yjz$li{vL7WJ6t_8b5Gc; z$deuP`57YTc zNK|pyUgms($>heB)HR9gQeme3EuJQhl|{ptIh=d;-u!MMPcfFYWe)1WL5k-on%dMv#yBgOD$F0qrE z%R2mPXx%hip0S(Qo|b>r@eO`4F#(HyKM~uM6-v2Vvls4%Hmd58pg0b@kai67q_5sm zCi}X(^m5dJtO^{2RAVTm^^q^3v`cYmSUi$m2@TknZ+9GU13iPTNw~K!9rYtOzokYn zku^porlGT(A#SIZjyGr{?Zw)f$_OaW4AfDzR5sW!B9JAmF!N1o ze^}lzSGnIasghg@;)J;jw3z=NPCV91p@6(s>aD_?fdR;0@li@8my;?ng~l>&M%|d- zIpbVvpc&{)^rRs2Se{u$gCpahx*at!B%oND95KCgL>m0tyFB=Zf(l%Z#WJPwgxtH8 z)X!`7IR?d)(@R>Z`@M+wUp9u)2%AzU^`1Sy2w9y9&b-qvp!b9DgJX z(6WE|1@6I3%cW3E^R>MGQ0LZIwX33{XDKGpU7d=jj2{|OIr(JE7q(L^PQAeVQ6H@c zJoiUt;MvJiMz;K2ql~UsR#P)^NdXF?bl%eJ%Ziy-jS}_;Rc<+5?8ammYYUhwWQ1V< zwp!7IrIA`xt{U%Yg;QKo8LRHj5w0y2smzeS-zw^rRZ_;zlUG3^K zX@}+Sy+=ZAQ^?WG7ENq5Enu1J9_H)V2WaLU1a)-JqNjmwmrNA^+j5@;?#9w}OGgHND zG+jS6z{ghhlM%-hZ8y{JJ%Z!aoYT}>ehO;d^bq4x5Jo7)>8KldUFqnm(1_EiDWIb8 zLJ<@bR8J0J1|3B}%w~Lz#8R*Wn`q0sP0Oj+-)?v&Z&MEpmCUn+!OXtXXOwnEWnbIa zH(GJ@{g=P*yN|U*ZV8_~u~8U=!h-fwwWGbCNk}H7zO`y+ZgLxMsd6D>4Ac)Ym=5XR z=AZXn@V^=6{-{Nk>;oos@>zRe%_5Y<]@ _E*_E*VC2S@/N@5OA6J;6G83N<8]KGqZTs\ViLFY<6cS{kᨔéɱƴϪtfcUZHfTȌr찖ؾջжʰʯγҷӸȬͱɭz}~uo~jz{hɨ~h}g|zzszf\ZTJHbPFm[QnWGdM=O8_Hw`tǙΠҥըҧӨөԪӬԭհհҶѵѴϲϮέϪΩǜęzrn~l}kr{nviqdp`qasbtct^pZjReM_FV=vL3mC*_@!cD%cH-bG,XC2T?.O>4P?5G83C4/H62UC?hQKlUOeJCW<5^Oufܢʰ®ɵΨvfcSZGeRĆmᣊѷͳɯĪ§ɮеɭ˯ɭ~}zrlvb}lƥu_~h{{ɽŹ`UQRGCeQFq]RqVEfK:T=iRmƖ˝͟ҥثԩժի׭֯رسٴչԸԷҵұѰҭѬХˠǘ~wuuv}zwtqrsum~iybt]pWhO^EV=kH*nK-lL3hH/ZC3U>.O=3O=3E61?0+@.*I73[D>bKE`E>W<5UCfTʎvߣȭîˢvdbPYDdOcԔxƬŪŪƫʯβͱʮ¦|wp~kr^nģzhsζnefSF@NA;dM?mVHqU@mQ<]Ft]zРϡ̞ҥڭ֫׬خڰٲ۴ܷݸؼ׻׺ոմӲհԯ֫Хʛ“zzÎ|Ő~~|~vrlh{cs[jRbJ|S7}T8wS;oK3_C5W;-N:1N:1G51@.*;)%@.*P93XA;Y@9V=6L8WCvZňlvr{ǝ|vdaO[BfMz\ȇitvϴѶͲγչϳ̰ƪ}¯Ǯ|un}jwcnƥy{ʵnefWNON?8QB;bH7eK:qQ:zZCjSiʚեѣ͟Ѥ٬׬حٯ۱۴޷ߺߺھٽػֹ׶մֱֱ׬Ѧ̝ĕÐ}Ð}Ƒȓ‘ÒxuolhxaoXhQ]D\CYCxN8dB6Z8,N5.N5.J73B/+:'#;($D0)M92S<4S<4J4RdG5dG5uQ7cIybr̜ԤҤϡѤ֩֫׬خ۱ܵ޷໫໫ھٽػֹ׶մֱֱ֫ҧΟșǔƓȓɔÏÏÏĐĐĐőőyvqok|et]mVhQeN^JP*#;' 3$/ ,,. /!J7\I΃l鞇ؾٿ˱{sāgłhɀ_}\zɣs|v˰γyŝ¨˱ͯxtȡyi}mƤ˴һÿ]caGID;=8C5*PB7rM:_LsYpĘƚʞ΢ѧөԫԫϩѫүֳشڶطط޸޸߷޶ݳڰج֪ҤѣϠ̜͞˛͚Λȡɢˡˡ͟˝̘˗˓ɑȍ{ĉwƒqm|jzhvWpQdJP6i@.[2 L.#L.#>*#;' 3$/ ,,-. I7P>pY׌uγպγèǒt|czaxXwWyy~efϵ}hɮͲt{Ûūͳϱyu{vfoǫʮͺľcghLPQ?>:984G5)SA5tN9ePdΛ~Ǜʞ͡ҦԪ֭֬׮ѫӭӰֳشڶططݷݷ޶ݵݳٯج֪ҤѣϠ̜͞͝ϜϜɢɢˡˡ̞ʜ˗ɕ˓ɑȍ{ĉwƒqm|jzhrSlM`FM3e<*W.H*H*=)":&2#.,,-. G6D3^G|eŧΰͰŨ˓rs[mUnNoOynjQlSδ}sγ˰wk~tūͳͯ~vsstdtϻɼ{zooqqqsA<9@;8O9,WA4uM4fMc͛zɝ˟΢ҦԪ֭֭֬ҬԮղ״ٵڶط׶ܶݷݵܴܲٯ׫թҤТϠ͞Ξ͝Нўɢɢˡʠ˝ȚʖȔʒȐnjzÈvp~l{iygoPhI\BI/a8&S*E'D&<(!9%1"-++,-L;D3YDydť˫˫ƦΓpjSaJcDgHzofM]DjxsϴǬwkwšĪ˱ɫ~yrpqueyƪû÷zuyA64D97T:-[A4yR5oRc˙tɝ˟΢ҦөԪԫԫԮְֳصڶڶ׶׶ܶܶݵܴ۱خ֪ԨѣТСΟϟϟҟӠɢɢˡɟʜǙȔƒǏ~Ǝ}ĉwsn|jxfwelMfGZ@|F,_6$Q(B$B$<(!9%0!-**+,RBJ:cNքo̪˩ʩȧҔpeOYC]?eGmiaHoM4|bIpWrZzbʯŪv̤ĪʰȪ{wp}nvyi˯ŭëĿ¼VLT<,,A11R5'_B4\>bǘnϠvʞ̠ϣҦөԪӪӪְزصٶڶڶ׶׶۵۵ܴ۳ڰ׭թԨѣТСϠϟРԡբʣɢˡɟɛŗƒĐČ{Šyto|jxftbsakLeFY?{E+^5#P'A#A#;' 8$0!,))*+PAK=!:-)"!G,@%K1[AybqūɹȪ{fvWmP̓fĘ{q|~{ufuhm`yktuɲȭ{ywɺŹ÷źsmE2,N2&W;/yTA|iÙΤҤӥددٰ۲۵ܷܷܶطٸٹٹظֶҵѴ׬֫ժժԩӨҧҧҧҧѦХϤϤΣΣИϗ̕ɒ~ƍz‰vpoh|ew^rYmSjPhNgMe@^9S4zC$e5!W'E@=!:-)"!B*B*R:fNćt՘ɪͮȷƬoawWŊjk~alhkW`LqWHY?0nXKdNAw`Ryuuȱʯ|xtȹȼĸũlYSJ71I-!^B6dQvʠө֨Ԧ۲۲ܳ޵ݷ߹ߺߺڹۺںںظֶҵѴӨӨѦѦѦҧӨӨҧҧҧҧХϤ̡͢ϗ͕ʓƏ{Êwsmkybw`rYnUiOfLdJdJc>\7Q2zC$e5!X(G!B=!:-)"!@&I/aJzc۞뮜׶ЯDzūvdtS`uXvYohwXD]>*T:+J0!_I<]G:v_Qz}{ǰɮ|yuy~˿¶DZsu_LFS@:G+fJ>r_ͣԪتשܳݴ޵߶߹ລ໨Ἡܻܻܼۻٹ׷ҵгҧѦϤϤϤѦӨժҧӨӨӨѦϤˠɞΖ̔ɒ~čytpj~hu^r[oVjQeKcIbHbHajMwwyZFS4 R8)[A2`J=l_ĭĩ}~ʱοô¶̲wy}xe_Q>8eI=pdŠȞͣש٫ܳܳݴ߶޸߹໨໨߾߾޾ݽں׷ҵгحժҧϤΣѦԩ׬ҧӨժ֫ӨΣɞŚ̔ɑƏ{up~kzdxbqZoXkRhOdJbHaGaG]8W2N/yB#f6"\,L&H"=!:-)"!D$E%F+N3r`ș̬ǧϮҪǟǓ~p[K2H/gJrU~~cOY:&T:+Z@1dNA|o|ì{~Ӻȹĸأn[UO<6uYMuơʥƜʠէت۲۲ܳ޵޸߹ߺߺ࿮࿮߿ݽں׷ҵг۰حԩХϤѦԩ׬ҧԩ֫֫ӨΣȝŚ˓ɑŎzto}jxbv`pYnWkRhOdJbHbHbH\7V1M.yB#f6"\,M'I#=!:-)"!VSWTYR^Wp_uƢүүvhe[g]wj{nvxj_;-U4%hYp`pup|éȮʮųùǯzxkI?mKAj]wjv}‘˛ե֩ثٯ޴߶෣޸޸⽭㾮Ὧ༮ܺٷյӳح֫ԩӨҧҧӨԩ֫ԩҧХ̡ʟǜƛƎ}Č{vrm|iycwar[qZpWmTiOgMeKdJZ;T5M1E)x@'n6[.S&E#?/, ')'&yyw~}}wʧΫv~t{vyvrN@jI:yjtwfsɯƬȬúønljH>iG=obwj}npqv͝ը֩ثۮܱൢḦ仩޹޹ݹݹضִӱѯح׬ժӨҧӨӨԩ֫ժӨХ͢ʟȝǜǏ~ō|‹wsn}jzdxbt]s\qXoVkQhNfLeKZ;T5M1F*yA(p8]0U(F$?/, ')&&ЩϨϩΨʦß~ƣʧĠbT|[Ltuzizé˱Īƪ˹˼Ǥxvx`^rPFzXN{n|ozkufqcugu͞͞Ρҥժ۰߶⹧ٲڳڴٳ׳ձѯϭٮ׬ժԩӨӨԩժ֫ժӨХ͢ˠȝǜɑǏ~čyupl|fzdw`v_t[qXlRiOgMfL[%d7$]0I'B 2.()&%ٿջؽڿеӸòڻҳΫɦǟԮҬݞ}}n~sctd{j~ūԺɯ¨¦Ӻȶӫkig]řĘē{~prdj^g[yfo{Ϝ֥کګ٪׫جٯ۱ٱذׯ֮گٮ׬ժԩժժ֫ح׬ժҧϤ̡ʟɞΖ̔ɒ~čyuqjizcybv]rYmSjPgMeK[TC^Mm]}m~ɕΜОҢեרة֪֪ܱگح׬֫֫׬حٮح֫ӨХΣˠʟӛљΗʓƍz‰vpnxav_sZnUhNdJ`F^D[+O-!G%7 0)*&$ѽǪæʩѰϩĜ׵ضǦʪxz[FgqäʫʫƦ¢¦ǾҸ~afejnhrl‰~}Ƅv€r|lwgqbn_YRTMJ@FbSmГ͔јѠԣϤХЫӮبק֦֦֦ק٩ڪ֦֦֦֦ԤҢϟΞљϗ̕ǐ|Êwslk{dxasZmTgMcI`F_EYSDjXweŠyϗРѡ͡΢ףףףؤף֢աԠҞѝϛ͙˗ʖʖʖ˓ɑƏ{Ìxtpjiybv_pWiPaG\BX>W=YyTN]WxwpfX^PXEdQva…pɏ{ϕқԝʐ|̒~ϕЖΔɏ{Ċvrl}ixds_r^s_vbxdwfvet`r^o\lYjTiSmVkTgNdK`F^D]C]CYcEE\>>ZAGbIOsYXml}ywol^j\]NeVvdńrʑј͜͜˙xȖuɒsȑȑsNJn€hyauanZfSaNdNfPfPeOcSdTeSeScPaN_J^IeOeOdMbK^F\D\A[@S>R=O8J3|F*v@$l=i:[8T1?)5$ +#  !"ϷѶػˮɨέɦǗԫլǧĤɯҸ͸ιкͷͱͱӳ׷ظҲĬôȿĖɿupscfV[RVMpPQgGHcJPjQWoUTedtq{xrjkcdVdVaRiZygdžtʑϖɘɘ˙xȖuɐsǎqɋrÅl|fu_lXdP\HUAT?S>S>~Q{P?}R?}R?M8O:P:O9~K0wD)l?"h;\7U0C*9 +) ( #$ ˳zsŨȫƥŤ}yÓد෱ͭūؾ˶̷ͷʴʮȬήѱͭ׷׿{Ѷ˻͵ǡӢ~}opgh_`b{WYwYaaionrqolkh`X\T[M^PbSk\|jʉw͔Зɘǖ̔yȐuÊoj~iu`iWaOR@I7s@-j7$]4 Z1R/O,E*#E*#F)!H+#K-%N0(R1(T3*W5)Z8,`<.eA3jE5kF6lE6lE6pA-sD0xH2zJ4zH/vD+m?%i;![5V0E*-f7%_0U2T1M1J.G,%F+$E( E( G)!H*"M,#O.%S1%V4(]9+a=/d?/c>.c<-a:+`5"d9&k<(o@,rB+qA*m?'j<$[5 V0G*?"1.))ӻ~Ѩ弶ٹƦ¨ѷɴʵʴưũçȨ˫µӳ˳͵ͤżDzooƛ͢Л͘|{npimfkojns|}zspd\\TTFQC[LfW{i͌zӚ֝Ϟ̒͜|ŋuoyfn]aPSDI:r=-k6&Z1V-P1R3L6!J4P/&O.%L,!K+ L*N, T0"W3%\7'`;+f?.jC2nC2lA0h=*f;(]4"_6$b7$d9&h;&i<'h;&h;&]4"X/J*C#62-,̴Ǭ{{w{™߶ݽʪéϵ͸ιθʴȬƪ˫ήٹϯƽ¥IJ|}͡ϣӛҚ{ymoilfmqnrx~zwnfd\XJRD^OiZ}kώ|ԛ՜̛ɘ͐}ƉvnuchYZKL>|A3i5'c/!R+O(I.L1F5!E4 U/"S- Q,Q,T-X1 _6$c:(k@-oD1xI5}N:P:~N8zJ3wG0c>,b=+b9'`7%b5 c6!c6!e8#\2"Y/L* F$9 4.-սԹĩģ~ssosoٰ޾ήĪͳѼҽҼͷ̰ɭήѱƦʪĵ¹~{΢͡ҚΖxujlficjnkovyqog`RWIbSm^oѐ~ӚӚɘŔ̏}Ɖw~lsaeVVGG9x=/b1#\+M(J%D+G.A2@1U+S)S*S*X-_4!h;&l?*vF0{K5R;XA[CZBWPJJ@KAP@YIaHaH]=Y9VW=T:}M6uE.n;(e2[,W(L%M&D(C'7'2"( %ؿŰ}ǩۻ̬ ŕ~t{q˟ʜҬѰֵ׺׺Ҹδ˴̵̬Ȩʲи~{|¼Ȼڟय़ߡؚΛȕ}rqih`\]YZ`WaXd[jarh{qyÉ~ÊʑӝܦܨףϛɕɄtzjlZ\JR=wC.c9#Y/N(O)P)R+W-Y/!\0#^2%`;)e@.wQDgZphmeickenhe_[NUHUAWCZ@[AW/pK.qL/tL2rJ0rE0l?*f8(c5%V,T*J(E#9!5/-ҵƩ¤ĦȨĤɧѯϫ˧׳ЬžЬֲֲܸܸϫʦȤƦ˫ɺlchȚ͟ڙ٘ܜߟҡҡʤȢ̜ȘϏ͍ˋˋʊɉĈ~Ç}ˆ}|ʑјآިު֢͙ƒwgiYWEF4r>)i5 ]3Y/X2_9&hA0oH7qG9kA3d8+^2%Z20]53dECuVTq[]gQS\LM\LMsa_n\ZoSOkOKpH@iA9h6+a/$`? cB#hE)kH,nD.kA+i;+e7'\2$Y/!P+"J%>":43ؿˮťʨ̪ұ¡âЯέßʦѭڴܶزҬͧ˥ϯ̬͵ȹ~zqv|Ǿ˛˛ۗޚߜߜѢСȣǢ̞̞ӘӘՕёˋƆ}†|Ĉ~Ǎʐҙ؟ݧ᫟ުԠɕn^`PM;|=+j6!d0Z0X.X2`:'mF5vO>zPBuK=mA4f:-lEFjCDkMOtVXgWXYIJJABI@A]QQYMM\DBYA?b;6^72_-&Z(!P3U8^< dB&kB,jA+j<,g9)]1$Z.!Q+"L&B$@";";"׾ֽ¥yovɩ̪ǥٹǧͬЯȤĠ̨ױ۵ڲխѩШں˫иɿ|mjxotxu|εÑٓ✚㠗ߜѢϠǢŠȜɝԙ՚Ғˋx{r{qyɏЖڡড়㭡寣߫ӟƒ}gWYIF4u6$d0a-X.W-U/_9&nG6zSBVH|RDtH;l@3}VYsLOeHLeHLWHKPADJFGRNORIJMDEO:9K65V0-V0-[($Y&"H+ N1V7_@#gA*gA*h=,e:)\0#Y- Q+"L&F%F%C(!C(!ϺnkpmʤФʞدͤɡ̥֮Ƥ̪ҳԵҴϱ˱̲ŷ}~yz|rdsv׻γèȗȗߘ㜖ٓҞҞˡʠϛ̘ԑҏɄuȃtÁuÁuċēȗ٬ڭܰݱ۬Οv}heQS?qA+g7!d:"f<$a<"]8d?%c>$pF.X@`J\FWCXDcP\I|VKrLA`LMaMNYS]\V`iis]]gQKM?9;>+$:' A'C)6! :%E*L1X4$[7'`6*a7+a2*_0(Z.%V*!O) M'I'J(̷˥ϣ˟׮Ϧ˜ĜШˤţʨбӴѳΰ˱˱ǵ˹zpbqē۔ߘߙܖӟӟˡɟ̘Ȕό̉ȃtȃt‚vÃwÊʑ˚Ϟ٬ۮ߰߰کʙpva_KP)h5 f9"h;$b=#_: d?%c>$rE.YBcNaL^J`LjWdQ^T}UKlWVmXWh^fkaipmvdajWNQE$?%9$<'D)J/U1#Y5'_5)`6*`1'^/%Z.%W+"Q+ P*L*L*ϺŰʤѫԨФӪѨƜĜƟ Ȧίҳвΰ˱̲ͻvfqwix¶ğwՎْݗݗӟӟʠȞʖƒ̉ʇɇwɇwŇzlj|ǐϘѢ֧ܯݰ౧ޯ٦Ɠ{gjVUBI6p<'j6!f9"i<%f>%c;"h@'g?&tG0[DfQgRdQgTp_kZf]aXcbfe~msqw~syrgmcUUPBBE1*<(!>"=!<'=(B'E*O+T0"\2&^4(\-#\-#Y-"X,!S- S- O.O.Կιǫͧױڮӧ̣Ϧǝĝţ̭Ѳвΰ̲ͳ˹w|lw}q»³Љԍٓݗѝѝʠɟ͙ʖюόϒΑʐˑ˖ҝզ٪ᴮ೭䲩߭֡|q^`MK9~C1q:&n7#j:$m='i?'h>&mC+kA)xH2ZDeQeQcQfTm_k]i^h]kipnyy}}vxlno[Z\HGO61C*%?#< ;%;%>"?#H$M)W,#Z/&X)X)W+X,T/T/P/P/Կȳѫج΢ěˢǝ{ĝĢ̭ѲѳвϵжIJótuscnuiwtƼǺψъ֐ڔΚϛʠˡҞѝۘڗמ՜ϚΙ͛ҠӦת縲䵯䯧ܧїsiWXFE3}@.t;(r9&o<'q>)m@)m@)tG0qD-{H3YDaNaN_McQgZfYf\f\kdpiwu{yrojgv]YeLHW<5J/(C&?"8"7!;<E J%S(W,#V(W)X-Z/V1V1Q1P0ιwtvϣƚȟǝ~ƟĢͮӴԶԶӹջñºƳxhiuep}o~u·ъԎ֐̘͙ɟ̢ա֢ߜܥ٢Ӡў͞ѢӦת縲Წݦњlj|uh^NO?@/~?.y>,x=+t@+t@+qC,qC,yK4uG0~J5YD`N_M^McRe[dZbYaXc[e]ickec]^XuTOiHCY:5N/*E("A$56;>!H#M("U*#W,%Z,\.!]2!_4#\8 [7U6S4͸DzvsriɝǛɠʠǠʣţϰն׹׹׽ٿ˹Ƹļ~pbqr§·ԍՏԎ̘͙ɟˡӟӟݚܙإ֣ѠПСԥתۮ䳮۪ӚŌymg[SDG8?/@0C1B0yB.xA-sC-tD.|L6wG1K7ZFcQeSdTiYkdhac[]UZQWNVLUKzOHwLElG?d?7W61N-(D'#@#57@#F)%Q+(U/,[0)\1*c5(e7*g<)i>+eA'b>$[<Y:Ѽũqhɝ΢ÚˢͣśȠΧΧƤбַغٻٿ´̻~vuvp{oap}Ǭ͆֏בԎ͙ΚɟʠМϛؕהբӠΟϠϣթۮ೭߮դ˒znb^RL=B3?/B2F4E3{D0yB.vC.wD/~K6yF1K7\HgUkYl\qarkngf_\USILB{G1nC0pE2lI-hE)`A"]>ؽؽֽռѽмͼͼϺɴƭŠæŤģşְƪͱ˸Ѿ˻֥}t_fltvahwhmɽǻːієӖӘ֛՝՝ҞҞޠڜ՛؞קݭݱ޲ᱥԤȐ}njW[HK4C,D/G2J5J5E0C.C.E0G2J5O:S>WB^IhSp[vmqhh_]TTII>xC5t?1rC3m>.b9']4"X3 U0N.J*L(L(O*S.]3#g=-sF3yL9}M7|L6}K2M4L2}G-v>#o7ؽؽֽռѽмͼͼѼDzΩ¥ŤŤşկ˰׼ƹ˾ëlswbit|nu||Œ̑іӖԗԙל֞ןԠӟޠ۝՝ؠئݫݮݮԤǗso`^KQ>E-?'F1I4K6I4E0B-B-D/J5N9R=VAYDaLkVr]vktioch\`RVHO@J;yH7tC2j?,f;(a;&_9$Z7!V3W0!V/ U.X1 b7&lA0xK6~Q"n8ؽؽֽռѽмͼͼԿɴytͨĥäȤ˧ƠÞЫ¡ʹĽ۶ɰ~rvxcjnu}zckmtŶ|uy|Ď̑͒ԗ֛֙ٞؠ١֢աڡ؟֞١ڥީ۩٧˗tfbTT@K7E+A'H3J5L7I4D/}@+~A,D/M8QN9K0H-J5K6L7H3B-|?*~A,D/N9QO:N2L0J5K6J5F1~A,}@+C.F1M8P;T?VAYD_JhSoZr_vc{hllzgvbr^nZgS_JWBR=L7{G1vB,L0~H,yC'wA%yC)I/R7W<\AWO8L-{H)G2G2F1C.~A,C.I4N9QJ:~C3v>1t/s@/vC2zE5~I9K;M=TBXF]J`M`LcOhUlYvfyi|jmm}kydwbs]r\oXlUiPgNeLdK^D]C\BZ@X?V=U=T.q6&k3&i1$e4%e4%f3"j7&r=-{F6M=SCXF\JaNdQdPgSlYp]~nononm|g{fwau_r[nWkRhOeLdK`F^D[AV.s8(n6)l4'd3$b1"b/e2!n9)zE5N>VFZH_MdQfSgSjVn[s`ppnnm}k|g{fwav`r[nWjQfMcJbI_E^DZ@U;Q8L3J2H0yC+v@(m='h8"a4^1[1Z0ͷͷ˶ʵŶŶµµƷDZ˵ϱñɻȷóͣaKWpXet\isr{u~}}͋}яχyҊ|яӑϕԚ֤ݫ㶱߲ڪ͝yse`NUCR.v>1u=0i8)d3$a.b/j5%xC3QAZJ^LcQhUkXkWnZr_wdpo}k{iygxfxcxcu_s]nWjSeL`G]D[BS9Q7N4J0G.C*z@(y?'o9!m7d4`0Z-X+U+U+ϹϹ͸͸ȹǸŸķĮů˳ݤjT`pZfrZglyzr~yist~ɕ̘Ґ̊|Ԍ~ؐؖٗЖϕ˙͛{zpj\_QUCP>H2F0D/B-{@0y>.w?2w?2k:+f5&b/b/j5%xC3QA[K_MdRiVlYlXo[s`xepo|jygwevdvawbs]q[mVhQcJ^E[BY@L2K1G-D*A(|>%v<$u;#k5i3`0\,V)T'Q'Q'ø·ĵôȱɲϱвɩήвϱĭ»ҿ亰tjrywgqzfqoz{jtrakv~riwҍҍԎؒנϘĔǗԘӗԉ|nwfm[`NUEM=J1s?2sB4uD6iE9^:.Y.Y.m9$|H3P9U>bHgMlToWp^r`wh|mzczczcybw`t]qZoXpYkTeNaJ_H[DU>P9F*D(B(>$}=$y9 p8!o7 b/a.Y.W,R+P)L(K'÷¶ijòɯʰΰϱ˫˫ǬȭŰȳǶȷ¾ÿǷҟvltueop{ualm\fnxzpx΋юՑؔқϘș͞؞Ҙ̓urhUcP[JQ@I8@/w<,t9)q<,o:*j9*h7(g9*j<-k?2mA4fB6[7+V+W,l8#|H3Q:V?cIhNlTnVo]q_vgzkybybxaw`u^r[oXnWlUgPaJ]F[DW@Q:L5F)D'A&>#y;"v8o7 n6_/^.Y.W,P+N)L(K'³ð¯Ƭǭ̬ͭҴ˭éɶ˾ͼ~rblt`kjVawfp{xnvu}ˋА̘͙֒ؔ͠ԧݥҚȁ}qmWDS@L:~C1s;*k3"c0`-_0 ^/Y/Y/Y4$]8(`<.c?1`<0V2&R'T)k7"}I4S,e4#^-Z,Y+P)P)N*O+O/ T4%W:,Z=/Z6*Q-!P%U*n:%M8W@\EfLiOlTmUkYkYn_rcr[r[r[qZoXkTiRgPcL^GXAT=R;N7H1C,@&?%}=$y9 q7!m3g3e1[-Z,S,Q*K)H&F&E%§ĤťƦǧͯȪ˶ľ¾ÿ¾״ófV`UALzfqujrvksДҖӕϑ̜ΞͤѨڦ֢ڗԑyik[VErA0a2"[,X-Z/N)M(J(K)K. O2$S7+V:.S/#N*Q&\1!vB-U@^GbKhNkQmUlTiWhVj[m^nWnWnWmVkTgPeNcLaJ\EV?R;P9L5F/A*~>%|<#x:#t6m4 i0b/a.W,V+Q+N(H(F&B$A#¡âģŤ¯ѾíſοҴبgWa{grkvzisrakujrЖїіϔ˞̟ɣ˥ӢԣޝޝŠ}zmbT}H:g6(^-[- ]/"S+!R* N) M(K+ N.#O1'Q3)N*M)V+f;+N9`KfOgPiOlRmUkSfTdRfWhYjSjSjSiRgPdMaJ_H]FXAR;O8L5I2C,>'y;$w9"t7"p3i2e.],\+U+T*L*J(E'B$@#?"žâèɸÿӸЇwzjt|hskZdyhr}͔̓ҙ֝ɜ˞ȤɥϠΟٚٚ̐xncWLyC9l6,b0'`.%Z.%X,#Q)!N&K&L'L)#M*$K'N*\1!qF6ZEkVmVlUkQmSmUjReSbPcTeVgPgPgPfOdMaJ^G\EXAS#="ǬϴļپȾtdnwcntcmãȏɐӚݤÙȞȤɥΟʛђђёȈxod[QI{@8k4-e.'_.)],'U(#P#J!J!J#J#J&N*`5%wL(t:&r8$l5!j3d1a.[-Z,T-T-P0#I)B'C(:&35">+%ÝƠģʵǾĿ½®Єyj_gpclxrblǷİȴ˯ƠȢ͞ƗϗƎ}Ŋz̑Ж͓̓Зؗ֕LjwradR_MXGN=t@2f2$Y)\,^2%_3&d:,nD6O?WG`NfTfTfTgRhSmWkUgPcL`G^E]D]D^?[ZFZJ^NcQeSdRdRfQiThRfPbK`I^E^E^E^EZ;W8T7R5R7O4I/C)G.E,C+|@(v<&r8"p6"n4 i2h1a._,X*W)R+R+H(H(F+"E*!5!-4!D1+ĩʷĿŽȽŒ]PYy{ĵŗ}{kjZ]PeXmekcc]_Yrm|Ώԕٚܝ՗ɋuffW[JYHXCS>R>WCZJ^NbPdRcQdRgRkVfPeOaJ`I^E^E^E_F[(t:$r8$p6"h1g0a.^+W)V(Q*Q*J*H(D) E*!A-&N:3p]Wy¨ж½¾½ÿüܩmae{os}nsdUZģ{qp^aO^QoblhTP>A:=F?MFXQg`rhtjpgjaRESFVEXGYGZH\J\J^F`HaG`F^E_FdIhMdGeHeF`AZ:X8Y9\<\@[?Z>V:T9O4J1H/{E-zD,uA,s?*n;&l9$j7$h5"\2$[1#Y.W,X*W)V*V*M(T/&J0/?%$:+2ZKRuʳվĿſÿњ}quo`egX]±xu|jucqdylvrhdVYMP90:1?5E;LCKBGPCTGZL\NV>ZB^F`H_FbIgLkPcGeIcG`DZ:W7Y9[;[?[?Y=V:S8O4J1H/{E-zD,uA,s?*n;&l9$j7$h5"]3%[1#Z/X-X*X*V*V*DL'E+*@&%=.5TELi^lujxDzº½ĽʿÈ}¶\MRo`eɸòvyÄrȉw΄w~q{wzvorbe@4<08-6+8-6+3)z-#v3+u2*n3+p5-p>7wE>}LGQLQY=XB7@6<2:26.q0*n-'f,(e+'d3/k:6oAAuGGN:S?YE\HZFYE[E]G_FaHcH`E[?W;W;X0I9RBXG]LaO`N[EU?R;=::45/2*2*~8,=1H6M;WA^HbG`EZ?W9 #R96E9J>L:P>[D`IbH_EZ?WF=I@QDWJR?VC^GaJcI_E[@W,g9)b4$g7#c3^/[,V,Y/!W5,Z8/I,(dGCnpsw`MQ?075&-ĿſǸ³ܤƭƅxhrzйѲyŠ}ˌ{ņur_aNVDP>H:G9OH[Teajfa]WSRHOEI7=+;$A*?8B;FS:R9T-m>,k<*e7'a3#b3`1^0 \.T-T-N-$N-$K/+kOKqrpq`PS<,/- '3&-½ýŶȳȲxtu~vaV^w͸̮Ø~Žʍ{ÆtuafR\FS=E4?.@7F=KFNIQKGAC7D8D.='?%F,~>4B8F:HYAU=R9R9S;R:O9K5{H5wD1p?.m<+l=+j;)d6&_1!\/^1\3!\3!U0 O*C%> 3R;5hVVaOO>24, "1&,?4:½üĵ¾ƴÿ¾rlv^T\{khÒēɎ|‡u}hu`cKZBM:D1<3;27351?;626+:/>(z9#y=!E)|B6G;K=M?M?N@TCXGVBXD\E^G^E\CZAY@W?S;P7P7Q9P8M7}I3zG4uB/o>-l;*j;)h9'b4$^0 Z0[1Z4!Y3 R1 L+A%=!A-&VB;^NNP@@4*+* !,#(1(-ĿſǸ¾ڽÿ׿nktndlkgŖǘɐ}ŌyƉtƉtyarZdS[JPJGA<;5485|1.v3*{8/u<(p7#k< rC'{F8K=O?P@M>L=O>RAT?VAXA[D\C\C[BZAU=Q9N5M4O7N6~J4zF0yF3tA.m<+k:)i:(g8&a3#]/]4\3V1T/O.O.K0%L1&s_Xt`Y`RQE761'(/%&*$(%#ʿ¼ʻôýݾĠ涳olu}v}|wz|xxƗɚ˒ȏ|ϒ}֙ǐ{upxikg^ZOQEGAB;<~?8D={H5tA.lD*qI/yE7}I;MU>YBZA[BZBZBS;O7L3K2M5L4}I3yE/xE2tA.m<+j9(i:(g8&a3#\.`:#[5S.O*K,R3!V;0\A6}v~kdVHG4&%*!":12?9=:48Ǿ㫢¹涭̶ǾԶԽ˽þѭ½ʛӦwecñq^`xzb_ƚמΕޞؘʢˣˠǜ{xmpeaTYLOAI;J;M>M?M?L9I6F3C0C/D0F1H3K5L6O8Q:T+l=+i:(e7'b4$^3#^3#_3&`4'c-#c-#V.&M%6"8$92,E>8NMI651'"+&"<+$;*#<#<#̗żѤ¹żǾ¹־µ½Ӯʚڬ^NQhf֞љ㥐ݟխذܱ޳߰۬ڦ֢՝͕Ŋ|rvgm^bT[MXEUBP=J7H4F2G2H3F0G1I2J3L4M5N6O7{G1xD.t@+s?*s@-r?,l;*h7&f8(d6&`5%^3#]1$]1$]3']3'b3)\-#K) F$:'!?,&?74F>;40/($#&-%#7(#3$0.żĻӱĻθغһȽ簫եȺ▇aRWrvyxĨ™֡ќ䧔ݠӫխ۰ݲ౧߰ଡު՝И͒nj~ąv{loagYaN^KWDP=L8I5I4I4H2H2J3J3K3L4L4L4yF1uB-q>+p=*n=,l;*g8(c4$b7'a6&^4&^4&Z2&Z2&Z2(Z2(T2&K)>!?"@.*J84LBANDC0*,-')/%&2()7(%1"-(ԞѭǧѮͷϸŮþĹޔ봯؁v|shnkZ`ѷȡĝ֢ѝ⧕۠ҪԬحٮܭګܨۧӛИΓʏʋ|svhn`iVeR^KWDR>M9M8M8M7M7N7M6N6M5M5M5xG6tC2p?.n=,m>.k<,c8(_4$`6(`6(]5+]5+Z4)Y3(W1(V0'E. ;$14 <-*F74H<@F:>-"(,!',!%+ $0"!1#",%ȿŽΞҵǾ˧ůɫ̎ЩȾ|rzΞ_PWȥӡϝਗؠԬխحح٪ةڦ٥١՝і͒ˌ}ƒtwioao\kXdQ\IWCS?R=R=R.j?/h=-a7)]3%\4*\4*[5,Z4+V1(S.%N,#L*!6)0#*,2$#7)(4'.1$+$ %!#$/!!8**3%$(ا˺ŜúƨƽαԻ̻ԪЧĿĿŦĻ}ِbU^ġϟ̜ਙןӫӫժժר֧٥ؤؠԜϔʏȉzsxjrds`o\gT`M[GWCWBVAS=S=R;P9P8M5L4K3vH8rD4m?0j<-h.f;+d:,b8*Z2&V."S-$S-$R-%P+#I& C <9"#-)1-"6,-6,-8(27'1L:FM;GH8BK;EXLP`TXKA@-#"ĥ͛ۜʻͳþҶ§Ĺɾ̸ɿǽŵåi^d͹riСy㫔Қݤۢ٠מ֜֜ככ̍~ʋ|ɇwŃs~mziwfudmWkUgQbL_IZDWBU@UCQ?NQ>L9}J7{H5zI8xG6rD4n@0vB4o;-c3%]-W-!X."U3)V4*A&?$5".##&-#!0$(4(,6*.=15PDHbVZ\PTK?CnbfthlXLP:.2<04=157+/=15іִߧ۟ەЬܺ}y䘎ӛ~yܮqgoŻʆsujMI֣ǔ̓˒ʑɐȎǍNjƊƒts}myiudq`n]l[fPdNaM\HVDQ?P=M:K9|G5uD3sB1qC3oA1i>.e:*i=0f:-`6*[1%R-$O*!J,$J,$=$;"=+)D204)''0&'G=>UIMTHLI=AG;?dX\w{xlpVJNVJNbVZL@D-!%''0$(G;?ܶڊ㌀ӏŖɹĿź̺vqwĺ‘ȿĩʠyyjou[Z}ȚƍƍƍŌĊˆ}zyp}nyiueq`l[iXgVdObM^KYFUBP=M;K9xG6tC2k@/j?.g@/e>-`;+\7'T0$X4(Y7-X6,O1)F( ;"9 =('C.-ZJKueffZ^E9=A8=WNSswswg[_L@DVJNwkoxlp_SW:.2G;?8,0#$%0$(L@D¦ȇ{Ͽ檛ڙզȻ|źȟ㜒ꨟķqdk}vq‰Êʈ}zvuzkyjtdp`l[hWdScRaM_K\HWCR@M;{J9yH7pE4lA0e>-c<+a=-_;+Y8)U4%H+#K.&L1*J/(E.(G0*L76S>=@01N>?uhoi^fQGPXNWtx~rvYMQH<@VJN_SWYMQ/#'5)-)!"."&, $, $?37ŧձۢ䘉ϔУþīɺuuĢ͏ԏ͸tnr٫mclͺqphg~yzvxyzw~synwlsdqbm]iYeT`O]L\K[IYGWDR?|M;wH6qF5nC2hA0d=,\;*Z9(Y9*W7(P4&L0"F2+C/(<)#7$<*(R@>p`axyVJNaUYvmbrbWg`TXsgkznrfZ^L@DA59B6:E9=2&*2&*%%6*.-!%"-!%Ѱϵʿãϗȹ;åĿŵ¸Ⱥ~{ζĦ}؟nfqʻ|cfhk~~ritkvmxovkrgmbj_j[hYdT`P\KWFTCRAUAS?~O=yJ8sE5n@0e>-c<+_;+[7'T4%R2#O3%N2$H.!D*=0*22ZNNswpemmbjshv{zpgzVJNVJN[OS_SWRFJ<041%)4(,1%)/#'#&5)-)!+#ᢞȱƺҬԢ笧ުĿź}ru¸ؤ~៙tnzu_bqth_jamdnembi^cX_TcTbS]MYIUDQ@MnZ8=`4TP@=Snq}CL%r>YV{Q)=uX)JS4iEmdj>jU{TSRH;(? zzScZdTWP5!WGtO7RG(V9p=f!XnRn*AkMF(zIro0~-!H#&_xby?fa?Is17hN0qLShV z#igK<((>vsc{w?G6halQZlHrR($~?`HL-TJGck9z(ABfQM0Ebylj=u3eU=^>>>c6i zL-hherKIF#u0%*y8E+{(?%FD|)PdcUmvK}ADjQ*%peTYE>(@BX1sDUmsKIY}G6UT>n($mlEL;5cwAL5H>h*?i;fAwIh7di# z*8Pj>+J)PFek_riTkfvmGUlQ=qxSI_Tz`uQ8`za`Z$=!j7H}u>VBbQnJw&g2mE2?# zHTW*jL$asjA5jle4*I5@uPJ_TRzzzeC6IXZRJk32=Td<2G1gKev!dG`vP8>oDIQQV zg0-#qsQQNP1hTX!=hND|@Bgl!PK?{CJkbz>-JP=7EIQ_siRObm1_@N z8S)_8-N}y^&qcN?VEE6c^<+s@nLMKYcgn~|iue^;d7zI2vvFL&S`p3ApLL)q%95-O zi8=X4-=DbputVboO=|X$Vt?xA1+jFF?}*J(oOkZl;10Q(<+hkwL!nR0;%eu^g3!UZ z<*9|P6xgeu8{2kAgkRqI9_5>GX<;VOBk_t~xy-XtBH^*XUAaLUm6sDParvT1+piVq zL7Q^lq`t{LFUq;CN%R>@T3@7)(LG4vUC@2=;J~y#) z>&n(_D+@ToMpGn4igp|;0E&)Zc1QWqqGLhkEjk;hw@9lk<>LVO?2BZOOYB&S$*Kcx zxU8NwzO8yBf;wKkK4&ngJOi`BJP`yqLB{h^%$swE#+9Z%q3^ zaG-c_FwIE?+GnP*hG+qP>OS%P%~;HGhnEMRZ~JZha7|3*`4u0n{!2C>^>gfS9Gd4ciZGwCPkUWwG@fDrBd@&%*`INX!@c?6{Pka)zC#&16-H^o42#m z^{uMP;yh8P2vc%RUYtAmSg5f^cr;(RS!TnkydLaC1J8^F%_okIH*tH-5$DuTLtZte zG(5`|t~ULJ)I6pMc@cd5`xtMu)C!_{!zvVRoFM#ls-EBPlBKC5{SXi%Osk~(spvbz zQ*a}>?=qzDLt%|Vo0X5i!6ALhdCzFAinq(L+&Za(opJMF#(aCa%J&s7{ne>Lt*3r= zBV109fn;fQ%BO~>?Xq|>&S0`vwE|~|<@RGbL-}SWM`8jff#%_oIp|Gj6lgKb)4g-8j>f)2lTgyPf#L8cUl*9`j1yKsiG?5r*e|3|pvh?_Yv? zDlXK|5ZG0xzulQXe62|-@H|QPa{E9akJGOy+&gSC3*{+bT z^w4&93s|g6R{HgcE;Mr#5V9kxT$Pm7sk3qYm!p|s#jF;?Ru4xl5&qp3VOnYv7wXCgwsfsS zz?51Ifh?HD8FlzU`+Qe!ld^Z%9u})23TL_TV!l=b z9#b{4+jPFO>9bShtDJO+S0qcuLy2yQ_qOcz1B+|)p3D3VCXr;AWZ0%NDe;^mmOo zmCCkq1j1;+iTp)Bgvl!`W$yzT3`j7w&qliz*pUqTZ5Rm7n;3?s7UYAUkUPX zSTvN~#NKv$t+vfc+Hstj%^$v)T--r2F**`eI0~4=5R}*pWE*w7PuQW!ov4KHyi&d- z{k@ABQ(+}advW7UH8!0g=*Q$xkDMS>-Aulrb+g*pG-m|jFc}^Gji$(q2lfkM%D(-1Ta)Z zt&a=Zp&A9UlsYr?5Ai52)gn30p3LqiUmj4eDhtM%%b5*x?>EP>ew*7)moScS&)6G# zXAC4AkKdgW`@CXsXQT-Y5n4o))wWK*XjIhH7BLEW{Qv?x`Rmv0g`m|eTXyWwo3D`y zM##-?XOC*wbwYhiKRpI|tv#hhlt3%)GZT&sHReB`DVXGp>$;-jDYu;1pU5Vsc?GAE z^Dv4oDXE-wdk4+I1!{iHC*TvTzd{SXL0~sY500{a!CYr3;%u-L7vy!rnPV((U~8sM zt8wp(f0z<$Bw38gi8=MXDq6DHBuCzB5Poj?>S<)xg5oq|DR^UH57TQFfU>nps~Awg zoxR{JRen@xR4H1@4zL5zsAp>{JQeTbEZDYs#XomcvrKz>L**=jb2yexR1I;2=VJN& z;bfZ{t7`X=CVTG7D4vG4!DqZV!JLkmCqPd^)}qJ><2ly4c}(P;Je`>qmaVELE3~;) brDBbQ8YN>1E@e3vpGLftG~`KL-T&=hT}>#F literal 0 HcmV?d00001