The Independent JPEG Group's JPEG software v1
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 <stdio.h>
+#include <ctype.h>
+
+#ifdef BSD
+# include <strings.h>
+# define strchr index
+#else
+# ifdef VMS
+ extern char *strcat(), *strchr(), *strcpy(), *strupr();
+ extern int strcmp(), strlen(), strncmp();
+# else
+# include <string.h>
+# endif
+#endif
+
+#ifdef MSDOS
+# include <malloc.h>
+#else
+# ifdef VMS
+ extern char *malloc();
+ extern void free();
+# else
+# ifdef BSD
+ extern char *malloc();
+# else
+# include <malloc.h>
+# 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 <stdlib.h> /* to declare exit() */
+#endif
+
+#ifdef THINK_C
+#include <console.h> /* 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 <stdlib.h> /* to declare exit() */
+#endif
+
+#ifdef THINK_C
+#include <console.h> /* 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 <stdlib.h> /* 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.
+ */
+
+
+/*
+ * <stdio.h> 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 <stdio.h>
+
+/*
+ * We need the size_t typedef, which defines the parameter type of malloc().
+ * In an ANSI-conforming implementation this is provided by <stdio.h>,
+ * but on non-ANSI systems it's more likely to be in <sys/types.h>.
+ */
+
+#ifndef __STDC__ /* shouldn't need this if __STDC__ */
+#include <sys/types.h>
+#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 <string.h>.
+ * 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 <string.h>
+#define MEMZERO(voidptr,size) memset((voidptr), 0, (size))
+#else /* not STDC */
+#ifdef BSD
+#include <strings.h>
+#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 <string.h>
+#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<<MAX_LZW_BITS) /* # of possible LZW symbols */
+
+/* Macros for extracting header data --- note we assume chars may be signed */
+
+#define LM_to_uint(a,b) ((((b)&0xFF) << 8) | ((a)&0xFF))
+
+#define BitSet(byte, bit) ((byte) & (bit))
+#define INTERLACE 0x40 /* mask for bit signifying interlaced image */
+#define COLORMAPFLAG 0x80 /* mask for bit signifying colormap presence */
+
+#define ReadOK(file,buffer,len) (fread(buffer, 1, len, file) == (len))
+
+/* Static vars for GetCode and LZWReadByte */
+
+static char code_buf[256+4]; /* current input data block */
+static int last_byte; /* # of bytes in code_buf */
+static int last_bit; /* # of bits in code_buf */
+static int cur_bit; /* next bit index to read */
+static boolean out_of_blocks; /* TRUE if hit terminator data block */
+
+static int input_code_size; /* codesize given in GIF file */
+static int clear_code,end_code; /* values for Clear and End codes */
+
+static int code_size; /* current actual code size */
+static int limit_code; /* 2^code_size */
+static int max_code; /* first unused code value */
+static boolean first_time; /* flags first call to LZWReadByte */
+
+/* LZW decompression tables:
+ * symbol_head[K] = prefix symbol of any LZW symbol K (0..LZW_TABLE_SIZE-1)
+ * symbol_tail[K] = suffix byte of any LZW symbol K (0..LZW_TABLE_SIZE-1)
+ * Note that entries 0..end_code of the above tables are not used,
+ * since those symbols represent raw bytes or special codes.
+ *
+ * The stack represents the not-yet-used expansion of the last LZW symbol.
+ * In the worst case, a symbol could expand to as many bytes as there are
+ * LZW symbols, so we allocate LZW_TABLE_SIZE bytes for the stack.
+ * (This is conservative since that number includes the raw-byte symbols.)
+ *
+ * The tables are allocated from FAR heap space since they would use up
+ * rather a lot of the near data space in a PC.
+ */
+
+static UINT16 FAR *symbol_head; /* => 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 <stdlib.h> /* 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 <alloc.h> /* 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 <malloc.h> /* 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 <mgardi@watdscu.waterloo.edu>.
+ * 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 0000000..b6b68bc
--- /dev/null
+++ b/testimg.jpg
Binary files differ
diff --git a/testimg.ppm b/testimg.ppm
new file mode 100644
index 0000000..c7dab37
--- /dev/null
+++ b/testimg.ppm
Binary files differ
diff --git a/testorig.jpg b/testorig.jpg
new file mode 100644
index 0000000..1a628fc
--- /dev/null
+++ b/testorig.jpg
Binary files differ