commit 2cbeb8abd92d5ad8a1bd415b51b3816213b15f31 Author: Thomas G. Lane Date: Mon Oct 7 00:00:00 1991 +0000 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 +#include + +#ifdef BSD +# include +# define strchr index +#else +# ifdef VMS + extern char *strcat(), *strchr(), *strcpy(), *strupr(); + extern int strcmp(), strlen(), strncmp(); +# else +# include +# endif +#endif + +#ifdef MSDOS +# include +#else +# ifdef VMS + extern char *malloc(); + extern void free(); +# else +# ifdef BSD + extern char *malloc(); +# else +# include +# endif +# endif +#endif + +/* Usage: + ansi2knr input_file output_file + * If no output_file is supplied, output goes to stdout. + * There are no error messages. + * + * ansi2knr recognizes functions by seeing a non-keyword identifier + * at the left margin, followed by a left parenthesis, + * with a right parenthesis as the last character on the line. + * It will recognize a multi-line header if the last character + * on each line but the last is a left parenthesis or comma. + * These algorithms ignore whitespace and comments, except that + * the function name must be the first thing on the line. + * The following constructs will confuse it: + - Any other construct that starts at the left margin and + follows the above syntax (such as a macro or function call). + - Macros that tinker with the syntax of the function header. + */ + +/* Scanning macros */ +#define isidchar(ch) (isalnum(ch) || (ch) == '_') +#define isidfirstchar(ch) (isalpha(ch) || (ch) == '_') + +main(argc, argv) + int argc; + char *argv[]; +{ FILE *in, *out; +#define bufsize 500 /* arbitrary size */ + char buf[bufsize]; + char *line; + switch ( argc ) + { + default: + printf("Usage: ansi2knr input_file [output_file]\n"); + exit(0); + case 2: + out = stdout; break; + case 3: + out = fopen(argv[2], "w"); + if ( out == NULL ) + { fprintf(stderr, "Cannot open %s\n", argv[2]); + exit(1); + } + } + in = fopen(argv[1], "r"); + if ( in == NULL ) + { fprintf(stderr, "Cannot open %s\n", argv[1]); + exit(1); + } + fprintf(out, "#line 1 \"%s\"\n", argv[1]); + line = buf; + while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL ) + { switch ( test1(buf) ) + { + case 1: /* a function */ + convert1(buf, out); + break; + case -1: /* maybe the start of a function */ + line = buf + strlen(buf); + continue; + default: /* not a function */ + fputs(buf, out); + break; + } + line = buf; + } + if ( line != buf ) fputs(buf, out); + fclose(out); + fclose(in); + return 0; +} + +/* Skip over space and comments, in either direction. */ +char * +skipspace(p, dir) + register char *p; + register int dir; /* 1 for forward, -1 for backward */ +{ for ( ; ; ) + { while ( isspace(*p) ) p += dir; + if ( !(*p == '/' && p[dir] == '*') ) break; + p += dir; p += dir; + while ( !(*p == '*' && p[dir] == '/') ) + { if ( *p == 0 ) return p; /* multi-line comment?? */ + p += dir; + } + p += dir; p += dir; + } + return p; +} + +/* + * Write blanks over part of a string. + */ +void +writeblanks(start, end) + char *start; + char *end; +{ char *p; + for ( p = start; p < end; p++ ) *p = ' '; +} + +/* + * Test whether the string in buf is a function definition. + * The string may contain and/or end with a newline. + * Return as follows: + * 0 - definitely not a function definition; + * 1 - definitely a function definition; + * -1 - may be the beginning of a function definition, + * append another line and look again. + */ +test1(buf) + char *buf; +{ register char *p = buf; + char *bend; + char *endfn; + int contin; + if ( !isidfirstchar(*p) ) + return 0; /* no name at left margin */ + bend = skipspace(buf + strlen(buf) - 1, -1); + switch ( *bend ) + { + case ')': contin = 1; break; + case '(': + case ',': contin = -1; break; + default: return 0; /* not a function */ + } + while ( isidchar(*p) ) p++; + endfn = p; + p = skipspace(p, 1); + if ( *p++ != '(' ) + return 0; /* not a function */ + p = skipspace(p, 1); + if ( *p == ')' ) + return 0; /* no parameters */ + /* Check that the apparent function name isn't a keyword. */ + /* We only need to check for keywords that could be followed */ + /* by a left parenthesis (which, unfortunately, is most of them). */ + { static char *words[] = + { "asm", "auto", "case", "char", "const", "double", + "extern", "float", "for", "if", "int", "long", + "register", "return", "short", "signed", "sizeof", + "static", "switch", "typedef", "unsigned", + "void", "volatile", "while", 0 + }; + char **key = words; + char *kp; + int len = endfn - buf; + while ( (kp = *key) != 0 ) + { if ( strlen(kp) == len && !strncmp(kp, buf, len) ) + return 0; /* name is a keyword */ + key++; + } + } + return contin; +} + +convert1(buf, out) + char *buf; + FILE *out; +{ char *endfn = strchr(buf, '(') + 1; + register char *p; + char **breaks; + unsigned num_breaks = 2; /* for testing */ + char **btop; + char **bp; + char **ap; +top: p = endfn; + breaks = (char **)malloc(sizeof(char *) * num_breaks * 2); + if ( breaks == 0 ) + { /* Couldn't allocate break table, give up */ + fprintf(stderr, "Unable to allocate break table!\n"); + fputs(buf, out); + return -1; + } + btop = breaks + num_breaks * 2 - 2; + bp = breaks; + /* Parse the argument list */ + do + { int level = 0; + char *end = NULL; + if ( bp >= btop ) + { /* Filled up break table. */ + /* Allocate a bigger one and start over. */ + free((char *)breaks); + num_breaks <<= 1; + goto top; + } + *bp++ = p; + /* Find the end of the argument */ + for ( ; end == NULL; p++ ) + { switch(*p) + { + case ',': if ( !level ) end = p; break; + case '(': level++; break; + case ')': if ( --level < 0 ) end = p; break; + case '/': p = skipspace(p, 1) - 1; break; + default: ; + } + } + p--; /* back up over terminator */ + /* Find the name being declared. */ + /* This is complicated because of procedure and */ + /* array modifiers. */ + for ( ; ; ) + { p = skipspace(p - 1, -1); + switch ( *p ) + { + case ']': /* skip array dimension(s) */ + case ')': /* skip procedure args OR name */ + { int level = 1; + while ( level ) + switch ( *--p ) + { + case ']': case ')': level++; break; + case '[': case '(': level--; break; + case '/': p = skipspace(p, -1) + 1; break; + default: ; + } + } + if ( *p == '(' && *skipspace(p + 1, 1) == '*' ) + { /* We found the name being declared */ + while ( !isidfirstchar(*p) ) + p = skipspace(p, 1) + 1; + goto found; + } + break; + default: goto found; + } + } +found: if ( *p == '.' && p[-1] == '.' && p[-2] == '.' ) + { p++; + if ( bp == breaks + 1 ) /* sole argument */ + writeblanks(breaks[0], p); + else + writeblanks(bp[-1] - 1, p); + bp--; + } + else + { while ( isidchar(*p) ) p--; + *bp++ = p+1; + } + p = end; + } + while ( *p++ == ',' ); + *bp = p; + /* Make a special check for 'void' arglist */ + if ( bp == breaks+2 ) + { p = skipspace(breaks[0], 1); + if ( !strncmp(p, "void", 4) ) + { p = skipspace(p+4, 1); + if ( p == breaks[2] - 1 ) + { bp = breaks; /* yup, pretend arglist is empty */ + writeblanks(breaks[0], p + 1); + } + } + } + /* Put out the function name */ + p = buf; + while ( p != endfn ) putc(*p, out), p++; + /* Put out the declaration */ + for ( ap = breaks+1; ap < bp; ap += 2 ) + { p = *ap; + while ( isidchar(*p) ) putc(*p, out), p++; + if ( ap < bp - 1 ) fputs(", ", out); + } + fputs(") ", out); + /* Put out the argument declarations */ + for ( ap = breaks+2; ap <= bp; ap += 2 ) (*ap)[-1] = ';'; + fputs(breaks[0], out); + free((char *)breaks); + return 0; +} diff --git a/architecture b/architecture new file mode 100644 index 0000000..78587cd --- /dev/null +++ b/architecture @@ -0,0 +1,1106 @@ + + JPEG SYSTEM ARCHITECTURE 3-OCT-91 + + +This file provides an overview of the "architecture" of the portable JPEG +software; that is, the functions of the various modules in the system and the +interfaces between modules. For more precise details about any data structure +or calling convention, see the header files. + +Important note: when I say "module" I don't mean "a C function", which is what +some people seem to think the term means. A separate C source file is closer +to the mark. Also, it is frequently the case that several different modules +present a common interface to callers; the term "object" or "method" refers to +this common interface (see "Poor man's object-oriented programming", below). + +JPEG-specific terminology follows the JPEG R9 draft: + A "component" means a color channel, e.g., Red or Luminance. + A "sample" is a pixel component value (i.e., one number in the image data). + A "coefficient" is a frequency coefficient (a DCT transform output number). + The term "block" refers to an 8x8 group of samples or coefficients. + "MCU" (minimum coded unit) is the same as "MDU" of the R8 draft; i.e., an + interleaved set of blocks of size determined by the sampling factors, + or a single block in a noninterleaved scan. + + +*** System requirements *** + +We must support compression and decompression of both Huffman and +arithmetic-coded JPEG files. Any set of compression parameters allowed by the +JPEG spec should be readable for decompression. (We can be more restrictive +about what formats we can generate.) (Note: for legal reasons no arithmetic +coding implementation is currently included in the publicly available sources. +However, the architecture still supports it.) + +We need to be able to handle both raw JPEG files (more specifically, the JFIF +format) and JPEG-in-TIFF (C-cubed's format, and perhaps Kodak's). Even if we +don't implement TIFF ourselves, other people will want to use our code for +that. This means that generation and scanning of the file header has to be +separated out. + +Perhaps we should be prepared to support the JPEG lossless mode (also referred +to in the spec as spatial DPCM coding). A lot of people seem to believe they +need this... whether they really do is debatable, but the customer is always +right. On the other hand, there will not be much sharable code between the +lossless and lossy modes! At best, a lossless program could be derived from +parts of the lossy version. For now we will only worry about the lossy mode. + +I see no real value in supporting the JPEG progressive modes (note that +spectral selection and successive approximation are two different progressive +modes). These are only of interest when painting the decompressed image in +real-time, which nobody is going to do with a pure software implementation. + +There is some value in supporting the hierarchical mode, which allows for +successive frames of higher resolution. This could be of use for including +"thumbnail" representations. Also, Storm's JPEG++ files probably use the +hierarchical mode (I haven't looked). However, this appears to add a lot more +complexity than it is worth. + +A variety of uncompressed image file formats and user interfaces must be +supported. These aspects therefore have to be kept separate from the rest of +the system. A particularly important issue is whether color quantization of +the output is needed (i.e., whether a colormap is used). We should be able to +support both adaptive quantization (which requires two or more passes over the +image) and nonadaptive (quantization to a prespecified colormap, which can be +done in one pass). + +Memory usage is an important concern, since we will port this code to 80x86 +and other limited-memory machines. For large intermediate structures, we +should be able to use either virtual memory or temporary files. + +It should be possible to build programs that handle compression only, +decompression only, or both, without much duplicate or unused code in any +version. (In particular, a decompression-only version should have no extra +baggage.) + + +*** Compression overview *** + +The *logical* steps needed in (non-lossless) JPEG compression are: + +1. Conversion from incoming image format to a standardized internal form + (either RGB or greyscale). + +2. Color space conversion (e.g., RGB to YCbCr). This is a null step for + greyscale (unless we support mapping color inputs to greyscale, which + would most easily be done here). Gamma adjustment may also be needed here. + +3. Subsampling (reduction of number of samples in some color components). + This step operates independently on each color component. + +4. MCU extraction (creation of a single sequence of 8x8 sample blocks). + This step and the following ones are performed once for each scan + in the output JPEG file, i.e., once if making an interleaved file and more + than once for a noninterleaved file. + Note: both this step and the previous one must deal with edge conditions + for pictures that aren't a multiple of the MCU dimensions. Alternately, + we could expand the picture to a multiple of an MCU before doing these + two steps. (The latter seems better and has been adopted below.) + +5. DCT transformation of each 8x8 block. + +6. Quantization scaling and zigzag reordering of the elements in each 8x8 + block. + +7. Huffman or arithmetic encoding of the transformed block sequence. + +8. Output of the JPEG file with whatever headers/markers are wanted. + +Of course, the actual implementation will combine some of these logical steps +for efficiency. The trick is to keep these logical functions as separate as +possible without losing too much performance. + +In addition to these logical pipeline steps, we need various modules that +aren't part of the data pipeline. These are: + +A. Overall control (sequencing of other steps & management of data passing). + +B. User interface; this will determine the input and output files, and supply + values for some compression parameters. Note that this module is highly + platform-dependent. + +C. Compression parameter selection: some parameters should be chosen + automatically rather than requiring the user to find a good value. + The prototype only does this for the back-end (Huffman or arithmetic) + parameters, but further in the future, more might be done. A + straightforward approach to selection is to try several values; this + requires being able to repeatedly apply some portion of the pipeline and + inspect the results (without actually outputting them). Probably only + entropy encoding parameters can reasonably be done this way; optimizing + earlier steps would require too much data to be reprocessed (not to mention + the problem of interactions between parameters for different steps). + What other facilities do we need to support automatic parameter selection? + +D. A memory management module to deal with small-memory machines. This must + create the illusion of virtual memory for certain large data structures + (e.g., the subsampled image or the transformed coefficients). + The interface to this must be defined to minimize the overhead incurred, + especially on virtual-memory machines where the module won't do much. + +In many cases we can arrange things so that a data stream is produced in +segments by one module and consumed by another without the need to hold it all +in (virtual) memory. This is obviously not possible for any data that must be +scanned more than once, so it won't work everywhere. + +The major variable at this level of detail is whether the JPEG file is to be +interleaved or not; that affects the order of processing so fundamentally that +the central control module must know about it. Some of the other modules may +need to know it too. It would simplify life if we didn't need to support +noninterleaved images, but that is not reasonable. + +Many of these steps operate independently on each color component; the +knowledge of how many components there are, and how they are interleaved, +ought to be confined to the central control module. (Color space conversion +and MCU extraction probably have to know it too.) + + +*** Decompression overview *** + +Decompression is roughly the inverse process from compression, but there are +some additional steps needed to produce a good output image. + +The *logical* steps needed in (non-lossless) JPEG decompression are: + +1. Scanning of the JPEG file, decoding of headers/markers etc. + +2. Huffman or arithmetic decoding of the coefficient sequence. + +3. Quantization descaling and zigzag reordering of the elements in each 8x8 + block. + +4. MCU disassembly (conversion of a possibly interleaved sequence of 8x8 + blocks back to separate components in pixel map order). + +5. (Optional) Cross-block smoothing per JPEG section 13.10 or a similar + algorithm. (Steps 5-8 operate independently on each component.) + +6. Inverse DCT transformation of each 8x8 block. + +7. De-subsampling. At this point a pixel image of the original dimensions + has been recreated. + +8. Post-subsampling smoothing. This can be combined with de-subsampling, + by using a convolution-like calculation to generate each output pixel + directly from one or more input pixels. + +9. Cropping to the original pixel dimensions (throwing away duplicated + pixels at the edges). It is most convenient to do this now, as the + preceding steps are simplified by not having to worry about odd picture + sizes. + +10. Color space reconversion (e.g., YCbCr to RGB). This is a null step for + greyscale. (Note that if we support mapping color JPEG to greyscale, + it could be done as part of this step.) Gamma adjustment may also be + needed here. + +11. Color quantization (only if a colormapped output format is requested). + NOTE: it might be better to do this on the internal color space instead of + RGB? If so, it would need to be performed one step earlier. + +12. Writing of the desired image format. + +As before, some of these will be combined into single steps. When dealing +with a noninterleaved JPEG file, steps 2-9 will be performed once for each +scan; the resulting data will need to be buffered up so that step 10 can +process all the color components together. + +The same auxiliary modules are needed as before, except for compression +parameter selection. Note that rerunning a pipeline stage should never be +needed during decompression. This may allow a simpler control module. The +user interface might also be simpler since it need not supply any compression +parameters. + +As before, not all of these steps require the whole image to be stored. +Actually, two-pass color quantization is the only step that logically requires +this; everything else could be done a few raster lines at a time (at least for +interleaved images). We might want to make color quantization be a separate +program because of this fact. + +Again, many of the steps should be able to work on one color component in +ignorance of the other components. + + +*** Implications of noninterleaved formats *** + +Much of the work can be done in a single pass if an interleaved JPEG file +format is used. With a noninterleaved JPEG file, separating or recombining +the components will force use of virtual memory (on a small-memory machine, +we probably would want one temp file per color component). + +If any of the image formats we read or write are noninterleaved, the opposite +condition might apply: processing a noninterleaved JPEG file would be more +efficient. Offhand, though, I can't think of any popular image formats that +work that way; besides the win would only come if the same color space were +used in JPEG and non-JPEG files. It's not worth the complexity to make the +system design accommodate that case efficiently. + +An argument against interleaving is that it makes the decompressor need more +memory for cross-block smoothing (since the minimum processable chunk of the +image gets bigger). With images more than 1000 pixels across, 80x86 machines +are likely to have difficulty in handling this feature. + +Another argument against interleaving is that the noninterleaved format allows +a wider range of sampling factors, since the limit of ten blocks per MCU no +longer applies. We could get around this by blithely ignoring the spec's +limit of ten blocks, but that seems like a bad idea (especially since it makes +the above problem worse). + +The upshot is that we need to support both interleaved and noninterleaved JPEG +formats, since for any given machine and picture size one may be much more +efficient than the other. However, the non-JPEG format we convert to or from +will be assumed to be an interleaved format (i.e., it produces or stores all +the components of a pixel together). + +I do not think it is necessary for the compressor to be able to output +partially-interleaved formats (multiple scans, some of which interleave a +subset of the components). However, the decompressor must be able to read +such files to conform to the spec. + + +*** Data formats *** + +Pipeline steps that work on pixel sample values will use the following data +structure: + + typedef something JSAMPLE; a pixel component value, 0..MAXJSAMPLE + typedef JSAMPLE *JSAMPROW; ptr to a row of samples + typedef JSAMPROW *JSAMPARRAY; ptr to a list of rows + typedef JSAMPARRAY *JSAMPIMAGE; ptr to a list of color-component arrays + +The basic element type JSAMPLE will be one of unsigned char, (signed) char, or +unsigned short. Unsigned short will be used if samples wider than 8 bits are +to be supported (this is a compile-time option). Otherwise, unsigned char is +used if possible. If the compiler only supports signed chars, then it is +necessary to mask off the value when reading. Thus, all reads of sample +values should be coded as "GETJSAMPLE(value)", where the macro will be defined +as "((value)&0xFF)" on signed-char machines and "(value)" elsewhere. + +With these conventions, JSAMPLE values can be assumed to be >= 0. This should +simplify correct rounding during subsampling, etc. The JPEG draft's +specification that sample values run from -128..127 will be accommodated by +subtracting 128 just as the sample value is copied into the source array for +the DCT step (this will be an array of signed shorts or longs). Similarly, +during decompression the output of the IDCT step will be immediately shifted +back to 0..255. (NB: different values are required when 12-bit samples are in +use. The code should be written in terms of MAXJSAMPLE and CENTERJSAMPLE, +which will be #defined as 255 and 128 respectively in an 8-bit implementation, +and as 4095 and 2048 in a 12-bit implementation.) + +On compilers that don't support "unsigned short", signed short can be used for +a 12-bit implementation. To support lossless coding (which allows up to +16-bit data precision) masking with 0xFFFF in GETJSAMPLE might be necessary. +(But if "int" is 16 bits then using "unsigned int" is the best solution.) + +Notice that we use a pointer per row, rather than a two-dimensional JSAMPLE +array. This choice costs only a small amount of memory and has several +benefits: + +* Code using the data structure doesn't need to know the allocated width of +the rows. This will simplify edge expansion/compression, since we can work +in an array that's wider than the logical picture width. + +* The rows forming a component array may be allocated at different times +without extra copying. This will simplify working a few scanlines at a time, +especially in smoothing steps that need access to the previous and next rows. + +* Indexing doesn't require multiplication; this is a performance win on many +machines. + +Note that each color component is stored in a separate array; we don't use the +traditional structure in which the components of a pixel are stored together. +This simplifies coding of steps that work on each component independently, +because they don't need to know how many components there are. Furthermore, +we can read or write each component to a temp file independently, which is +helpful when dealing with noninterleaved JPEG files. + +A specific sample value will be accessed by code such as + GETJSAMPLE(image[colorcomponent][row][col]) +where col is measured from the image left edge, but row is measured from the +first sample row currently in memory. Either of the first two indexings can +be precomputed by copying the relevant pointer. + + +Pipeline steps that work on frequency-coefficient values will use the +following data structure: + + typedef short JCOEF; a 16-bit signed integer + typedef JCOEF JBLOCK[64]; an 8x8 block of coefficients + typedef JBLOCK *JBLOCKROW; ptr to one horizontal row of 8x8 blocks + typedef JBLOCKROW *JBLOCKARRAY; ptr to a list of such rows + typedef JBLOCKARRAY *JBLOCKIMAGE; ptr to a list of color component arrays + +The underlying type is always a 16-bit signed integer (this is "short" on all +machines of interest, but let's use the typedef name anyway). These are +grouped into 8x8 blocks (we should use #defines DCTSIZE and DCTSIZE2 rather +than "8" and "64"). The contents of a block may be either in "natural" or +zigzagged order, and may be true values or divided by the quantization +coefficients, depending on where the block is in the pipeline. + +Notice that the allocation unit is now a row of 8x8 blocks, corresponding to +eight rows of samples. Otherwise the structure is much the same as for +samples, and for the same reasons. + +On machines where malloc() can't handle a request bigger than 64Kb, this data +structure limits us to rows of less than 512 JBLOCKs, which would be a picture +width of 4000 pixels. This seems an acceptable restriction. + + +On 80x86 machines, the bottom-level pointer types (JSAMPROW and JBLOCKROW) +must be declared as "far" pointers, but the upper levels can be "near" +(implying that the pointer lists are allocated in the DS segment). +To simplify sharing code, we'll have a #define symbol FAR, which expands to +the "far" keyword when compiling on 80x86 machines and to nothing elsewhere. + + +The data arrays used as input and output of the DCT transform subroutine will +be declared using a separate typedef; they could be arrays of "short", "int" +or "long" independently of the above choices. This would depend on what is +needed to make the compiler generate correct and efficient multiply/add code +in the DCT inner loops. No significant speed or memory penalty will be paid +to have a different representation than is used in the main image storage +arrays, since some additional value-by-value processing is done at the time of +creation or extraction of the DCT data anyway (e.g., add/subtract 128). + + +*** Poor man's object-oriented programming *** + +It should be pretty clear by now that we have a lot of quasi-independent +steps, many of which have several possible behaviors. To avoid cluttering the +code with lots of switch statements, we'll use a simple form of object-style +programming to separate out the different possibilities. + +For example, Huffman and arithmetic coding will be implemented as two separate +modules that present the same external interface; at runtime, the calling code +will access the proper module indirectly through an "object". + +We can get the limited features we need while staying within portable C. The +basic tool is a function pointer. An "object" is just a struct containing one +or more function pointer fields, each of which corresponds to a method name in +real object-oriented languages. During initialization we fill in the function +pointers with references to whichever module we have determined we need to use +in this run. Then invocation of the module is done by indirecting through a +function pointer; on most architectures this is no more expensive (and +possibly cheaper) than a switch, which would be the only other way of making +the required run-time choice. The really significant benefit, of course, is +keeping the source code clean and well structured. + +For example, the interface for entropy decoding (Huffman or arithmetic +decoding) might look like this: + + struct function_ptr_struct { + ... + /* Entropy decoding methods */ + void (*prepare_for_scan) (); + void (*get_next_mcu) (); + ... + }; + + typedef struct function_ptr_struct * function_ptrs; + +The struct pointer is what will actually be passed around. A call site might +look like this: + + some_function (function_ptrs fptrs) + { + ... + (*fptrs->get_next_mcu) (...); + ... + } + +(It might be worth inventing some specialized macros to hide the rather ugly +syntax for method definition and call.) Note that the caller doesn't know how +many different get_next_mcu procedures there are, what their real names are, +nor how to choose which one to call. + +An important benefit of this scheme is that it is easy to provide multiple +versions of any method, each tuned to a particular case. While a lot of +precalculation might be done to select an optimal implementation of a method, +the cost per invocation is constant. For example, the MCU extraction step +might have a "generic" method, plus one or more "hardwired" methods for the +most popular sampling factors; the hardwired methods would be faster because +they'd use straight-line code instead of for-loops. The cost to determine +which method to use is paid only once, at startup, and the selection criteria +are hidden from the callers of the method. + +This plan differs a little bit from usual object-oriented structures, in that +only one instance of each object class will exist during execution. The +reason for having the class structure is that on different runs we may create +different instances (choose to execute different modules). + +To minimize the number of object pointers that have to be passed around, it +will be easiest to have just a few big structs containing all the method +pointers. We'll actually use two such structs, one for "globally" defined +methods (applicable to the whole file or to all components of the current +scan) and one for methods applicable to a single component. There'll be one +copy of the second kind of struct for each component of the current scan. +This is necessary so that preselection of an optimal method can be done based +on component-specific information (like sampling ratios...) + +Because of this choice, it's best not to think of an "object" as a specific +data structure. Rather, an "object" is just a group of related methods. +There would typically be one or more C modules (source files) providing +concrete implementations of those methods. You can think of the term +"method" as denoting the common interface presented by some set of functions, +and "object" as denoting a group of common method interfaces, or the total +shared interface behavior of a group of modules. + + +*** Data chunk sizes *** + +To make the cost of this object-oriented style really minimal, we should make +sure that each method call does a fair amount of computation. To do that we +should pass large chunks of data around; for example, the colorspace +conversion method should process much more than one pixel per call. + +For many steps, the most natural unit of data seems to be an "MCU row". +This consists of one complete horizontal strip of the image, as high as an +MCU. In a noninterleaved scan, an MCU row is always eight samples high (when +looking at samples) or one 8x8 block high (when looking at coefficients). In +an interleaved scan, an MCU row consists of all the data for one horizontal +row of MCUs; this may be from one to four blocks high (eight to thirty-two +samples) depending on the sampling factors. The height and width of an MCU +row may be different in each component. (Note that the height and width of an +MCU row changes at the subsampling and de-subsampling steps. An unsubsampled +image has the same size in each component. The preceding statements apply to +the subsampled dimensions.) + +For example, consider a 1024-pixel-wide image using (2h:2v)(1h:1v)(1h:1v) +subsampling. In the noninterleaved case, an MCU row of Y would contain 8x1024 +samples or the same number of frequency coefficients, so it would occupy +8K bytes (samples) or 16K bytes (coefficients). An MCU row of Cb or Cr would +contain 8x512 samples and occupy half as much space. In the interleaved case, +an MCU row would contain 16x1024 Y samples, 8x512 Cb and 8x512 Cr samples, so +a total of 24K (samples) or 48K (coefficients) would be needed. This is a +reasonable amount of data to expect to retain in memory at one time. (Bear in +mind that we'll usually need to have several MCU rows resident in memory at +once, at the inputs and outputs to various pipeline steps.) + +The worst case is probably (2h:4v)(1h:1v)(1h:1v) interleaving (this uses 10 +blocks per MCU, which is the maximum allowed by the spec). An MCU will then +contain 32 sample rows worth of Y, so it would occupy 40K or 80K bytes for a +1024-pixel-wide image. The most memory-intensive step is probably cross-block +smoothing, for which we'd need 3 MCU rows of coefficients as input and another +one as output; that would be 320K of working storage. Anything much larger +would not fit in an 80x86 machine. (To decompress wider pictures on an 80x86, +we'll have to skip cross-block smoothing or else use temporary files.) + +This unit is thus a reasonable-sized chunk for passing through the pipeline. +Of course, its major advantage is that it is a natural chunk size for the MCU +assembly and disassembly steps to work with. + +For the entropy (Huffman or arithmetic) encoding/decoding steps, the most +convenient chunk is a single MCU: one 8x8 block if not interleaved, three to +ten such blocks if interleaved. The advantage of this is that when handling +interleaved data, the blocks have the same sequence of component membership on +each call. (For example, Y,Y,Y,Y,Cb,Cr when using (2h:2v)(1h:1v)(1h:1v) +subsampling.) The code needs to know component membership so that it can +apply the right set of compression coefficients to each block. A prebuilt +array describing this membership can be used during each call. This chunk +size also makes it easy to handle restart intervals: just count off one MCU +per call and reinitialize when the count reaches zero (restart intervals are +specified in numbers of MCU). + +For similar reasons, one MCU is also the best chunk size for the frequency +coefficient quantization and dequantization steps. + +For subsampling and desubsampling, the best chunk size is to have each call +transform Vk sample rows from or to Vmax sample rows (Vk = this component's +vertical sampling factor, Vmax = largest vertical sampling factor). There are +eight such chunks in each MCU row. Using a whole MCU row as the chunk size +would reduce function call overhead a fraction, but would imply more buffering +to provide context for cross-pixel smoothing. + + +*** Compression object structure *** + +I propose the following set of objects for the compressor. Here an "object" +is the common interface for one or more modules having comparable functions. + +Most of these objects can be justified as information-hiding modules. +I've indicated what information is private to each object/module. + +Note that in all cases, the caller of a method is expected to have allocated +any storage needed for it to return its result. (Typically this storage can +be re-used in successive calls, so malloc'ing and free'ing once per call is +not reasonable.) Also, much of the context required (compression parameters, +image size, etc) will be passed around in large common data structures, which +aren't described here; see the header files. Notice that any object that +might need to allocate working storage receives an "init" and a "term" call; +"term" should be careful to free all allocated storage so that the JPEG system +can be used multiple times during a program run. (For the same reason, +depending on static initialization of variables is a no-no.) + +1. Input file conversion to standardized form. This provides these methods: + input_init: read the file header, report image size & component count. + get_input_row: read one pixel row, return it in our standard format. + input_term: finish up at the end. + In implementations that support multiple input formats, input_init could + set up an appropriate get_input_row method depending on the format it + finds. Note that in most applications, the selection and opening of the + input file will be under the control of the user interface module; and + indeed the user interface may have already read the input header, so that + all that input_init may have to do is return previously saved values. The + behind-the-scenes interaction between this object and the user interface is + not specified by this architecture. + (Hides format of input image and mechanism used to read it. This code is + likely to vary considerably from one implementation to another. Note that + the color space and number of color components of the source are not hidden; + but they are used only by the next object.) + +2. Gamma and color space conversion. This provides three methods: + colorin_init: initialization. + get_sample_rows: read, convert, and return a specified number of pixel + rows (not more than remain in the picture). + colorin_term: finish up at the end. + The most efficient approach seems to be for this object to call + get_input_row directly, rather than being passed the input data; that way, + any intermediate storage required can be local to this object. + (get_sample_rows might tell get_input_row to read directly into its own + output area and then convert in place; or it may do something different. + For example, conversion in place wouldn't work if it is changing the number + of color components.) The output of this step is in the standardized + sample array format shown previously. + (Hides all knowledge of color space semantics and conversion. Remaining + modules only need to know the number of JPEG components.) + +3. Edge expansion: needs only a single method. + edge_expand: Given an NxM sample array, expand to a desired size (a + multiple of the MCU dimensions) by duplicating the last + row or column. Repeat for each component. + Expansion will occur in place, so the caller must have pre-allocated enough + storage. (I'm assuming that it is easier and faster to do this expansion + than it is to worry about boundary conditions in the next two steps. + Notice that vertical expansion will occur only once, at the bottom of the + picture, so only horizontal expansion by a few pixels is speed-critical.) + (This doesn't really hide any information, so maybe it could be a simple + subroutine instead of a method. Depends on whether we want to be able to + use alternative, optimized methods.) + +4. Subsampling: this will be applied to one component at a time. + subsample_init: initialize (precalculate convolution factors, for + example). This will be called once per scan. + subsample: Given a sample array, reduce it to a smaller number of + samples using specified sampling factors. + subsample_term: clean up at the end of a scan. + If the current component has vertical sampling factor Vk and the largest + sampling factor is Vmax, then the input is always Vmax sample rows (whose + width is a multiple of Hmax) and the output is always Vk sample rows. + Vmax additional rows above and below the nominal input rows are also passed + for use by partial-pixel-averaging sampling methods. (Is this necessary?) + At the top and bottom of the image, these extra rows are copies of the + first or last actual input row. + (This hides whether and how cross-pixel averaging occurs.) + +5. MCU extraction (creation of a single sequence of 8x8 sample blocks). + extract_init: initialize as needed. This will be called once per scan. + extract_MCUs: convert a sample array to a sequence of MCUs. + extract_term: clean up at the end of a scan. + Given one or more MCU rows worth of image data, extract sample blocks in the + appropriate order; pass these off to subsequent steps one MCU at a time. + The input must be a multiple of the MCU dimensions. It will probably be + most convenient for the DCT transform, frequency quantization, and zigzag + reordering of each block to be done as simple subroutines of this step. + Once a transformed MCU has been completed, it'll be passed off to a + method call, which will be passed as a parameter to extract_MCUs. + That routine might either encode and output the MCU immediately, or buffer + it up for later output if we want to do global optimization of the entropy + encoding coefficients. Note: when outputting a noninterleaved file this + object will be called separately for each component. Direct output could + be done for the first component, but the others would have to be buffered. + (Again, an object mainly on the grounds that multiple instantiations might + be useful.) + +6. DCT transformation of each 8x8 block. This probably doesn't have to be a + full-fledged method, but just a plain subroutine that will be called by MCU + extraction. One 8x8 block will be processed per call. + +7. Quantization scaling and zigzag reordering of the elements in each 8x8 + block. (This can probably be a plain subroutine called once per block by + MCU extraction; hard to see a need for multiple instantiations here.) + +8. Entropy encoding (Huffman or arithmetic). + entropy_encoder_init: prepare for one scan. + entropy_encode: accepts an MCU's worth of quantized coefficients, + encodes and outputs them. + entropy_encoder_term: finish up at end of a scan (dump any buffered + bytes, for example). + The data output by this module will be sent to the entropy_output method + provided by the pipeline controller. (It will probably be worth using + buffering to pass multiple bytes per call of the output method.) The + output method could be just write_jpeg_data, but might also be a dummy + routine that counts output bytes (for use during cut-and-try coefficient + optimization). + (This hides which entropy encoding method is in use.) + +9. JPEG file header construction. This will provide these methods: + write_file_header: output the initial header. + write_scan_header: output scan header (called once per component + if noninterleaved mode). + write_jpeg_data: the actual data output method for the preceding step. + write_scan_trailer: finish up after one scan. + write_file_trailer: finish up at end of file. + Note that compressed data is passed to the write_jpeg_data method, in case + a simple fwrite isn't appropriate for some reason. + (This hides which variant JPEG file format is being written. Also, the + actual mechanism for writing the file is private to this object and the + user interface.) + +10. Pipeline control. This object will provide the "main loop" that invokes + all the pipeline objects. Note that we will need several different main + loops depending on the situation (interleaved output or not, global + optimization of encoding parameters or not, etc). This object will do + most of the memory allocation, since it will provide the working buffers + that are the inputs and outputs of the pipeline steps. + (An object mostly to support multiple instantiations; however, overall + memory management and sequencing of operations are known only here.) + +11. Overall control. This module will provide at least two routines: + jpeg_compress: the main entry point to the compressor. + per_scan_method_selection: called by pipeline controllers for + secondary method selection passes. + jpeg_compress is invoked from the user interface after the UI has selected + the input and output files and obtained values for all compression + parameters that aren't dynamically determined. jpeg_compress performs + basic initialization (e.g., calculating the size of MCUs), does the + "global" method selection pass, and finally calls the selected pipeline + control object. (Per-scan method selections will be invoked by the + pipeline controller.) + Note that jpeg_compress can't be a method since it is invoked prior to + method selection. + +12. User interface; this is the architecture's term for "the rest of the + application program", i.e., that which invokes the JPEG compressor. In a + standalone JPEG compression program the UI need be little more than a C + main() routine and argument parsing code; but we can expect that the JPEG + compressor may be incorporated into complex graphics applications, wherein + the UI is much more complex. Much of the UI will need to be written + afresh for each non-Unix-like platform the compressor is ported to. + The UI is expected to supply input and output files and values for all + non-automatically-chosen compression parameters. (Hence defaults are + determined by the UI; we should probably provide helpful routines to fill + in recommended defaults.) The UI must also supply error handling + routines and some mechanism for trace messages. + (This module hides the user interface provided --- command line, + interactive, etc. Except for error/message handling, the UI calls the + portable JPEG code, not the other way around.) + +13. (Optional) Compression parameter selection control. + entropy_optimize: given an array of MCUs ready to be fed to entropy + encoding, find optimal encoding parameters. + The actual optimization algorithm ought to be separated out as an object, + even though a special pipeline control method will be needed. (The + pipeline controller only has to understand that the output of extract_MCUs + must be built up as a virtual array rather than fed directly to entropy + encoding and output. This pipeline behavior may also be useful for future + implementation of hierarchical modes, etc.) + To minimize the amount of control logic in the optimization module, the + pipeline control doesn't actually hand over big-array pointers, but rather + an "iterator": a function which knows how to scan the stored image. + (This hides the details of the parameter optimization algorithm.) + + The present design doesn't allow for multiple passes at earlier points + in the pipeline, but allowing that would only require providing some + new pipeline control methods; nothing else need change. + +14. A memory management object. This will provide methods to allocate "small" + things and "big" things. Small things have to fit in memory and you get + back direct pointers (this could be handled by direct calls to malloc, but + it's cleaner not to assume malloc is the right routine). "Big" things + mean buffered images for multiple passes, noninterleaved output, etc. + In this case the memory management object will give you room for a few MCU + rows and you have to ask for access to the next few; dumping and reloading + in a temporary file will go on behind the scenes. (All big objects are + image arrays containing either samples or coefficients, and will be + scanned top-to-bottom some number of times, so we can apply this access + model easily.) On a platform with virtual memory, the memory manager can + treat small and big things alike: just malloc up enough virtual memory for + the whole image, and let the operating system worry about swapping the + image to disk. + + Most of the actual calls on the memory manager will be made from pipeline + control objects; changing any data item from "small" to "big" status would + require a new pipeline control object, since it will contain the logic to + ask for a new chunk of a big thing. Thus, one way in which pipeline + controllers will vary is in which structures they treat as big. + + The memory manager will need to be told roughly how much space is going to + be requested overall, so that it can figure out how big a buffer is safe + to allocate for a "big" object. (If it happens that you are dealing with + a small image, you'd like to decide to keep it all in memory!) The most + flexible way of doing this is to divide allocation of "big" objects into + two steps. First, there will be one or more "request" calls that indicate + the desired object sizes; then an "instantiate" call causes the memory + manager to actually construct the objects. The instantiation must occur + before the contents of any big object can be accessed. + + For 80x86 CPUs, we would like the code to be compilable under small or + medium model, meaning that pointers are 16 bits unless explicitly declared + FAR. Hence space allocated by the "small" allocator must fit into the + 64Kb default data segment, along with stack space and global/static data. + For normal JPEG operations we seem to need only about 32Kb of such space, + so we are within the target (and have a reasonable slop for the needs of + a surrounding application program). However, some color quantization + algorithms need 64Kb or more of all-in-memory space in order to create + color histograms. For this purpose, we will also support "medium" size + things. These are semantically the same as "small" things but are + referenced through FAR pointers. + + The following methods will be needed: + alloc_small: allocate an object of given size; use for any random + data that's not an image array. + free_small: release same. + alloc_medium: like alloc_small, but returns a FAR pointer. + free_medium: release same. + alloc_small_sarray: construct an all-in-memory image sample array. + free_small_sarray: release same. + alloc_small_barray, + free_small_barray: ditto for block (coefficient) arrays. + request_big_sarray: request a virtual image sample array. The size + of the in-memory buffer will be determined by the + memory manager, but it will always be a multiple + of the passed-in MCU height. + request_big_barray: ditto for block (coefficient) arrays. + alloc_big_arrays: instantiate all the big arrays previously requested. + This call will also pass some info about future + memory demands, so that the memory manager can + figure out how much space to leave unallocated. + access_big_sarray: obtain access to a specified portion of a virtual + image sample array. + access_big_barray: ditto for block (coefficient) arrays. + free_big_sarray: release a virtual sample array. + free_big_barray: ditto for block (coefficient) arrays. + + alloc_big_arrays will be called by the pipeline controller, which does + most of the memory allocation anyway. The only reason for having separate + request calls is to allow some of the other modules to get big arrays. + The pipeline controller is required to give an upper bound on total future + small-array requests, so that this space can be discounted. (A fairly + conservative estimate will be adequate.) Future small-object requests + aren't counted; the memory manager has to use a slop factor for those. + 10K or so seems to be sufficient. (In an 80x86, small objects aren't an + issue anyway, since they don't compete for far-heap space. "Medium"-size + objects will have to be counted separately.) + + The distinction between sample and coefficient array routines is annoying, + but it has to be maintained for machines in which "char *" is represented + differently from "int *"... on byte-addressable machines some of these + methods could point to the same code. + + The array routines will operate on only 2-D arrays (one component at a + time), since different components may require different-size arrays. + + (This object hides the knowledge of whether virtual memory is available, + as well as the actual interface to OS and library support routines.) + +Note that any given implementation will presumably contain only one +instantiation of input file header reading, overall control, user interface, +and memory management. Thus these could be called as simple subroutines, +without bothering with an object indirection. This is essential for overall +control (which has to initialize the object structure); I'm undecided whether +to impose objectness on the other three. + + +*** Decompression object structure *** + +I propose the following set of objects for decompression. The general +comments at the top of the compression object section also apply here. + +1. JPEG file scanning. This will provide these methods: + read_file_header: read the file header, determine which variant + JPEG format is in use, read everything through SOF. + read_scan_header: read scan header (up through SOS). This is called + after read_file_header and again after each scan; + it returns TRUE if it finds SOS, FALSE if EOI. + read_jpeg_data: fetch data for entropy decoder. + read_scan_trailer: finish up after one scan, prepare for another call + of read_scan_header (may be a no-op). + read_file_trailer: finish up at end of file (probably a no-op). + The entropy decoder must deal with restart markers, but all other JPEG + marker types will be handled in this object; useful data from the markers + will be extracted into data structures available to subsequent routines. + Note that on exit from read_file_header, only the SOF-marker data should be + assumed valid (image size, component IDs, sampling factors); other data + such as Huffman tables may not appear until after the SOF. The overall + image size and colorspace can be determined after read_file_header, but not + whether or how the data is interleaved. (This hides which variant JPEG + file format is being read. In particular, for JPEG-in-TIFF the read_header + routines might not be scanning standard JPEG markers at all; they could + extract the data from TIFF tags. The user interface will already have + opened the input file and possibly read part of the header before + read_file_header is called.) + + NOTE: for JFIF/raw-JPEG file format, the read_jpeg_data routine is actually + supplied by the user interface; the jrdjfif module uses read_jpeg_data + internally to scan the input stream. This makes it possible for the user + interface module to single-handedly implement special applications like + reading from a non-stdio source. For JPEG-in-TIFF format, the need for + random access will make it impossible for this to work; hence the TIFF + header module will probably override the UI read_jpeg_data routine. + Non-stdio input from a TIFF file will require extensive surgery to the TIFF + header module, if indeed it is practical at all. + +2. Entropy (Huffman or arithmetic) decoding of the coefficient sequence. + entropy_decoder_init: prepare for one scan. + entropy_decode: decodes and returns an MCU's worth of quantized + coefficients per call. + entropy_decoder_term: finish up after a scan (may be a no-op). + This will read raw data by calling the read_jpeg_data method (I don't see + any reason to provide a further level of indirection). + (This hides which entropy encoding method is in use.) + +3. Quantization descaling and zigzag reordering of the elements in each 8x8 + block. (This can probably be a plain subroutine called once per block; + hard to see a need for multiple instantiations here.) + +4. MCU disassembly (conversion of a possibly interleaved sequence of 8x8 + blocks back to separate components in pixel map order). + disassemble_init: initialize. This will be called once per scan. + disassemble_MCU: Given an MCU's worth of dequantized blocks, + distribute them into the proper locations in a + coefficient image array. + disassemble_term: clean up at the end of a scan. + Probably this should be called once per MCU row and should call the + preceding two objects repeatedly to obtain the row's data. The output is + always a multiple of an MCU's dimensions. + (An object on the grounds that multiple instantiations might be useful.) + +5. Cross-block smoothing per JPEG section 13.10 or a similar algorithm. + smooth_coefficients: Given three block rows' worth of a single + component, emit a smoothed equivalent of the + middle row. The "above" and "below" pointers + may be NULL if at top/bottom of image. + The pipeline controller will do the necessary buffering to provide the + above/below context. Smoothing will be optional since a good deal of + extra memory is needed to buffer the additional block rows. + (This object hides the details of the smoothing algorithm.) + +6. Inverse DCT transformation of each 8x8 block. (This can be a plain + subroutine processing one block per call.) + +7. De-subsampling and smoothing: this will be applied to one component at a + time. Note that cross-pixel smoothing, which was a separate step in the + prototype code, will now be performed simultaneously with expansion. + unsubsample_init: initialize (precalculate convolution factors, for + example). This will be called once per scan. + unsubsample: Given a sample array, enlarge it by specified sampling + factors. + unsubsample_term: clean up at the end of a scan. + If the current component has vertical sampling factor Vk and the largest + sampling factor is Vmax, then the input is always Vk sample rows (whose + width is a multiple of Hk) and the output is always Vmax sample rows. + Vk additional rows above and below the nominal input rows are also passed + for use in cross-pixel smoothing. At the top and bottom of the image, + these extra rows are copies of the first or last actual input row. + (This hides whether and how cross-pixel smoothing occurs.) + +8. Cropping to the original pixel dimensions (throwing away duplicated + pixels at the edges). This won't be a separate object, just an + adjustment of the nominal image size in the pipeline controller. + +9. Color space reconversion and gamma adjustment. + colorout_init: initialization. This will be passed the component + data from read_file_header, and will determine the + number of output components. + color_convert: convert a specified number of pixel rows. Input and + output are image arrays of same size but possibly + different numbers of components. + colorout_term: cleanup (probably a no-op except for memory dealloc). + In practice will always be given an MCU row's worth of pixel rows, except + at the bottom where a smaller number of rows may be left over. Note that + this object works on all the components at once. + (Hides all knowledge of color space semantics and conversion. Remaining + modules only need to know the number of JPEG and output components.) + +10. Color quantization (used only if a colormapped output format is requested). + We use two different strategies depending on whether one-pass (on-the-fly) + or two-pass quantization is requested. Note that the two-pass interface + is actually designed to let the quantizer make any number of passes. + color_quant_init: initialization, allocate working memory. In 1-pass + quantization, should call put_color_map. + color_quantize: convert a specified number of pixel rows. Input + and output are image arrays of same size, but input + is N coefficients and output is only one. (Used only + in 1-pass quantization.) + color_quant_prescan: prescan a specified number of pixel rows in + 2-pass quantization. + color_quant_doit: perform multi-pass color quantization. Input is a + "big" sample image, output is via put_color_map and + put_pixel_rows. (Used only in 2-pass quantization.) + color_quant_term: cleanup (probably a no-op except for memory dealloc). + For one-pass quantization the image is simply processed by color_quantize, + a few rows at a time. For two-pass quantization, the pipeline controller + accumulates the output of color_convert into a "big" sample image. The + color_quant_prescan method is invoked during this process so that the + quantizer can accumulate statistics. At the end of the image, + color_quant_doit is called; it must rescan the "big" image and pass + converted data to the output module. Additional scans of the image could + be made before the output pass is done (in fact, prescan could be a no-op). + As with entropy parameter optimization, the pipeline controller actually + passes an iterator function rather than direct access to the big image. + NOTE: it might be better to do this on the internal color space instead of + RGB? If so, it would need to be performed one step earlier. + (Hides color quantization algorithm.) + +11. Writing of the desired image format. + output_init: produce the file header given data from read_file_header. + put_color_map: output colormap, if any (called by color quantizer). + put_pixel_rows: output image data in desired format. + output_term: finish up at the end. + Note that whether colormapping is needed will be determined by the user + interface object prior to method selection. In implementations that + support multiple output formats, the actual output format will also be + determined by the user interface. + (Hides format of output image and mechanism used to write it. Note that + several other objects know the color model used by the output format. The + actual mechanism for writing the file is private to this object and the + user interface.) + +12. Pipeline control. This object will provide the "main loop" that invokes + all the pipeline objects. Note that we will need several different main + loops depending on the situation (interleaved input or not, whether to + apply cross-block smoothing or not, etc). We may want to divvy up the + pipeline controllers into two levels, one that retains control over the + whole file and one that is invoked per scan. + This object will do most of the memory allocation, since it will provide + the working buffers that are the inputs and outputs of the pipeline steps. + (An object mostly to support multiple instantiations; however, overall + memory management and sequencing of operations are known only here.) + +13. Overall control. This module will provide at least two routines: + jpeg_decompress: the main entry point to the decompressor. + per_scan_method_selection: called by pipeline controllers for + secondary method selection passes. + jpeg_decompress is invoked from the user interface after the UI has + selected the input and output files and obtained values for all + user-specified options (e.g., output file format, whether to do block + smoothing). jpeg_decompress calls read_file_header, performs basic + initialization (e.g., calculating the size of MCUs), does the "global" + method selection pass, and finally calls the selected pipeline control + object. (Per-scan method selections will be invoked by the pipeline + controller.) + Note that jpeg_decompress can't be a method since it is invoked prior to + method selection. + +14. User interface; this is the architecture's term for "the rest of the + application program", i.e., that which invokes the JPEG decompressor. + The UI is expected to supply input and output files and values for all + operational parameters. The UI must also supply error handling routines. + At the moment I can't think of any nonfatal errors the JPEG code is likely + to report, so a single report-this-error-and-exit method should be + sufficient. + (This module hides the user interface provided --- command line, + interactive, etc. Except for error handling, the UI calls the portable + JPEG code, not the other way around.) + +15. A memory management object. This will be identical to the memory + management for compression (and will be the same code, in combined + programs). See above for details. + + +*** Initial method selection *** + +The main ugliness in this design is the portion of startup that will select +which of several instantiations should be used for each of the objects. (For +example, Huffman or arithmetic for entropy encoding; one of several pipeline +controllers depending on interleaving, the size of the image, etc.) It's not +really desirable to have a single chunk of code that knows the names of all +the possible instantiations and the conditions under which to select each one. + +The best approach seems to be to provide a selector function for each object +(group of related method calls). This function knows about each possible +instantiation of its object and how to choose the right one; but it doesn't +know about any other objects. + +Note that there will be several rounds of method selection: at initial startup, +after overall compression parameters are determined (after the file header is +read, if decompressing), and one in preparation for each scan (this occurs +more than once if the file is noninterleaved). Each object method will need +to be clearly identified as to which round sets it up. + + +*** Implications of DNL marker *** + +Some JPEG files may use a DNL marker to postpone definition of the image +height (this would be useful for a fax-like scanner's output, for instance). +In these files the SOF marker claims the image height is 0, and you only +find out the true image height at the end of the first scan. + +We could handle these files as follows: +1. Upon seeing zero image height, replace it by 65535 (the maximum allowed). +2. When the DNL is found, update the image height in the global image + descriptor. +This implies that pipeline control objects must avoid making copies of the +image height, and must re-test for termination after each MCU row. This is +no big deal. + +In situations where image-size data structures are allocated, this approach +will result in very inefficient use of virtual memory or +much-larger-than-necessary temporary files. This seems acceptable for +something that probably won't be a mainstream usage. People might have to +forgo use of memory-hogging options (such as two-pass color quantization or +noninterleaved JPEG files) if they want efficient conversion of such files. +(One could improve efficiency by demanding a user-supplied upper bound for the +height, less than 65536; in most cases it could be much less.) + +Alternately, we could insist that DNL-using files be preprocessed by a +separate program that reads ahead to the DNL, then goes back and fixes the SOF +marker. This is a much simpler solution and is probably far more efficient. +Even if one wants piped input, buffering the first scan of the JPEG file +needs a lot smaller temp file than is implied by the maximum-height method. +For this approach we'd simply treat DNL as a no-op in the decompressor (at +most, check that it matches the SOF image height). + +We will not worry about making the compressor capable of outputting DNL. Note +that something similar to the first scheme above could be applied if anyone +ever wants to make that work. + + +*** Notes for MS-DOS implementors *** + +The standalone cjpeg and djpeg applications can be compiled in "small" memory +model, at least at the moment; as the code grows we may be forced to switch to +"medium" model. (Small = both code and data pointers are near by default; +medium = far code pointers, near data pointers.) Medium model will slow down +calls through method pointers, but I don't think this will amount to any +significant speed penalty. + +When integrating the JPEG code into a larger application, it's a good idea to +stay with a small-data-space model if possible. An 8K stack is much more than +sufficient for the JPEG code, and its static data requirements are less than +1K. When executed, it will typically malloc about 10K worth of near heap +space (and lots of far heap, but that doesn't count in this calculation). +This figure will vary depending on image size and other factors, but figuring +20K should be more than sufficient. Thus you have about 35K available for +other modules' static data and near heap requirements before you need to go to +a larger memory model. The C library's static data will account for several K +of this, but that still leaves a good deal for your needs. (If you are tight +on space, you could reduce JPEG_BUF_SIZE from 4K to 1K to save 3K of near heap +space.) + +As the code is improved, we will endeavor to hold the near data requirements +to the range given above. This does imply that certain data structures will +be allocated as FAR although they would fit in near space if we assumed the +JPEG code is stand-alone. (The LZW tables in jrdgif/jwrgif are examples.) +To make an optimal implementation, you might want to move these structures +back to near heap if you know there is sufficient space. + + +*** Potential optimizations *** + +For colormapped input formats it might be worthwhile to merge the input file +reading and the colorspace conversion steps; in other words, do the colorspace +conversion by hacking up the colormap before inputting the image body, rather +than doing the conversion on each pixel independently. Not clear if this is +worth the uglification involved. In the above design for the compressor, only +the colorspace conversion step ever sees the output of get_input_row, so this +sort of thing could be done via private agreement between those two modules. + +Level shift from 0..255 to -128..127 may be done either during colorspace +conversion, or at the moment of converting an 8x8 sample block into the format +used by the DCT step (which will be signed short or long int). This could be +selectable by a compile-time flag, so that the intermediate steps can work on +either signed or unsigned chars as samples, whichever is most easily handled +by the platform. However, making sure that rounding is done right will be a +lot easier if we can assume positive values. At the moment I think that +benefit is worth the overhead of "& 0xFF" when reading out sample values on +signed-char-only machines. diff --git a/codingrules b/codingrules new file mode 100644 index 0000000..fd6f700 --- /dev/null +++ b/codingrules @@ -0,0 +1,99 @@ + + JPEG SYSTEM CODING RULES 27-SEP-91 + +Since numerous people will be contributing code and bug fixes, it's important +to establish a common coding style. The goal of using similar coding styles +is much more important than the details of just what that style is. + +I suggest we follow the recommendations of "Recommended C Style and Coding +Standards" revision 6.1 (Cannon et al. as modified by Spencer, Keppel and +Brader). I have placed a copy of this document in the jpeg FTP archive (see +jpeg/doc/cstyle.ms.tbl.Z, or cstyle.txt.Z for those without nroff/tbl). + +Unless someone has a real strong objection, let's do block comments thusly: + +/* + * Block comments in this style. + */ + +and indent statements in K&R style, e.g., + + if (test) { + then-part; + } else { + else-part; + } + +I suggest that multi-word names be written in the style multi_word_name +rather than multiWordName, but I am open to argument on this. + + +I would like to use function prototypes everywhere, and rely on automatic +source code transformation to feed non-ANSI C compilers. The best tool +I have so far found for this is 'ansi2knr.c', which is part of Ghostscript. +ansi2knr is not very bright, so it imposes a format requirement on function +declarations: the function name MUST BEGIN IN COLUMN 1. Thus all functions +should be written in the following style: + +static int * +function_name (int a, char *b) +{ + code... +} + +ansi2knr won't help with method declarations (function pointers in structs). +I suggest we use a macro to declare method pointers, something like this: + +#ifdef PROTO +#define METHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define METHOD(type,methodname,arglist) type (*methodname) () +#endif + +which is used like this: + +struct function_pointers { + METHOD(void, init_entropy_encoder, (functptrs fptrs, jparms *jp)); + METHOD(void, term_entropy_encoder, (void)); +}; + +Note the set of parentheses surrounding the parameter list. + +A similar solution is used for external function declarations (see the PP +macro in jpegdata.h). + +If the code is to work on non-ANSI compilers, you cannot rely on a prototype +declaration to coerce actual parameters into the right types. Therefore, use +explicit casts on actual parameters whenever the actual parameter type is not +identical to the formal parameter. Beware of implicit conversions to "int". + +It seems there are some non-ANSI compilers in which the sizeof() operator +is defined to return int, while size_t is defined as long. Needless to say, +this is brain-damaged. Always use the SIZEOF() macro in place of sizeof(), +so that the result is guaranteed to be of type size_t. + + +We can expect that the JPEG compressor and decompressor will be incorporated +into larger programs. Therefore, the following rules are important: + +1. Avoid direct use of any file I/O, "malloc", error report printouts, etc; +pass these through the common routines provided. + +2. Assume that the JPEG code may be invoked more than once per program run; +therefore, do not rely on static initialization of variables, and be careful +to release all allocated storage at the end of processing. + +3. Minimize global namespace pollution. Functions should be declared static +wherever possible. (Note that our method-based calling conventions help this +a lot: in many modules only the method-selector function will ever need to be +called directly, so only that function need be externally visible.) All +global function names should begin with "j", and should be unique in the first +six characters for portability reasons. +Don't use global variables at all; anything that must be used in another +module should be put into parameters (there'll be some large structs passed +around for this purpose). + +4. Source file names should also begin with "j"; remember to keep them to +eight characters (plus ".c" or ".h", etc) to make life easy for MS-DOSers. +Do not put code for both compression and decompression into the same source +file. diff --git a/egetopt.c b/egetopt.c new file mode 100644 index 0000000..8183d35 --- /dev/null +++ b/egetopt.c @@ -0,0 +1,276 @@ +/* + * egetopt.c -- Extended 'getopt'. + * + * A while back, a public-domain version of getopt() was posted to the + * net. A bit later, a gentleman by the name of Keith Bostic made some + * enhancements and reposted it. + * + * In recent weeks (i.e., early-to-mid 1988) there's been some + * heated discussion in comp.lang.c about the merits and drawbacks + * of getopt(), especially with regard to its handling of '?'. + * + * In light of this, I have taken Mr. Bostic's public-domain getopt() + * and have made some changes that I hope will be considered to be + * improvements. I call this routine 'egetopt' ("Extended getopt"). + * The default behavior of this routine is the same as that of getopt(), + * but it has some optional features that make it more useful. These + * options are controlled by the settings of some global variables. + * By not setting any of these extra global variables, you will have + * the same functionality as getopt(), which should satisfy those + * purists who believe getopt() is perfect and can never be improved. + * If, on the other hand, you are someone who isn't satisfied with the + * status quo, egetopt() may very well give you the added capabilities + * you want. + * + * Look at the enclosed README file for a description of egetopt()'s + * new features. + * + * The code was originally posted to the net as getopt.c by ... + * + * Keith Bostic + * ARPA: keith@seismo + * UUCP: seismo!keith + * + * Current version: added enhancements and comments, reformatted code. + * + * Lloyd Zusman + * Master Byte Software + * Los Gatos, California + * Internet: ljz@fx.com + * UUCP: ...!ames!fxgrp!ljz + * + * May, 1988 + */ + +/* + * If you want, include stdio.h or something where EOF and NULL are defined. + * However, egetopt() is written so as not to need stdio.h, which should + * make it significantly smaller on some systems. + */ + +#ifndef EOF +# define EOF (-1) +#endif /* ! EOF */ + +#ifndef NULL +# define NULL (char *)0 +#endif /* ! NULL */ + +/* + * None of these constants are referenced in the executable portion of + * the code ... their sole purpose is to initialize global variables. + */ +#define BADCH (int)'?' +#define NEEDSEP (int)':' +#define MAYBESEP (int)'\0' +#define ERRFD 2 +#define EMSG "" +#define START "-" + +/* + * Here are all the pertinent global variables. + */ +int opterr = 1; /* if true, output error message */ +int optind = 1; /* index into parent argv vector */ +int optopt; /* character checked for validity */ +int optbad = BADCH; /* character returned on error */ +int optchar = 0; /* character that begins returned option */ +int optneed = NEEDSEP; /* flag for mandatory argument */ +int optmaybe = MAYBESEP;/* flag for optional argument */ +int opterrfd = ERRFD; /* file descriptor for error text */ +char *optarg; /* argument associated with option */ +char *optstart = START; /* list of characters that start options */ + + +/* + * Macros. + */ + +/* + * Conditionally print out an error message and return (depends on the + * setting of 'opterr' and 'opterrfd'). Note that this version of + * TELL() doesn't require the existence of stdio.h. + */ +#define TELL(S) { \ + if (opterr && opterrfd >= 0) { \ + char option = optopt; \ + write(opterrfd, *nargv, strlen(*nargv)); \ + write(opterrfd, (S), strlen(S)); \ + write(opterrfd, &option, 1); \ + write(opterrfd, "\n", 1); \ + } \ + return (optbad); \ +} + +/* + * This works similarly to index() and strchr(). I include it so that you + * don't need to be concerned as to which one your system has. + */ +static char * +_sindex(string, ch) +char *string; +int ch; +{ + if (string != NULL) { + for (; *string != '\0'; ++string) { + if (*string == (char)ch) { + return (string); + } + } + } + + return (NULL); +} + +/* + * Here it is: + */ +int +egetopt(nargc, nargv, ostr) +int nargc; +char **nargv; +char *ostr; +{ + static char *place = EMSG; /* option letter processing */ + register char *oli; /* option letter list index */ + register char *osi = NULL; /* option start list index */ + + if (nargv == (char **)NULL) { + return (EOF); + } + + if (nargc <= optind || nargv[optind] == NULL) { + return (EOF); + } + + if (place == NULL) { + place = EMSG; + } + + /* + * Update scanning pointer. + */ + if (*place == '\0') { + place = nargv[optind]; + if (place == NULL) { + return (EOF); + } + osi = _sindex(optstart, *place); + if (osi != NULL) { + optchar = (int)*osi; + } + if (optind >= nargc || osi == NULL || *++place == '\0') { + return (EOF); + } + + /* + * Two adjacent, identical flag characters were found. + * This takes care of "--", for example. + */ + if (*place == place[-1]) { + ++optind; + return (EOF); + } + } + + /* + * If the option is a separator or the option isn't in the list, + * we've got an error. + */ + optopt = (int)*place++; + oli = _sindex(ostr, optopt); + if (optopt == optneed || optopt == optmaybe || oli == NULL) { + /* + * If we're at the end of the current argument, bump the + * argument index. + */ + if (*place == '\0') { + ++optind; + } + TELL(": illegal option -- "); /* byebye */ + } + + /* + * If there is no argument indicator, then we don't even try to + * return an argument. + */ + ++oli; + if (*oli == '\0' || (*oli != optneed && *oli != optmaybe)) { + /* + * If we're at the end of the current argument, bump the + * argument index. + */ + if (*place == '\0') { + ++optind; + } + optarg = NULL; + } + /* + * If we're here, there's an argument indicator. It's handled + * differently depending on whether it's a mandatory or an + * optional argument. + */ + else { + /* + * If there's no white space, use the rest of the + * string as the argument. In this case, it doesn't + * matter if the argument is mandatory or optional. + */ + if (*place != '\0') { + optarg = place; + } + /* + * If we're here, there's whitespace after the option. + * + * Is it a mandatory argument? If so, return the + * next command-line argument if there is one. + */ + else if (*oli == optneed) { + /* + * If we're at the end of the argument list, there + * isn't an argument and hence we have an error. + * Otherwise, make 'optarg' point to the argument. + */ + if (nargc <= ++optind) { + place = EMSG; + TELL(": option requires an argument -- "); + } + else { + optarg = nargv[optind]; + } + } + /* + * If we're here it must have been an optional argument. + */ + else { + if (nargc <= ++optind) { + place = EMSG; + optarg = NULL; + } + else { + optarg = nargv[optind]; + if (optarg == NULL) { + place = EMSG; + } + /* + * If the next item begins with a flag + * character, we treat it like a new + * argument. This is accomplished by + * decrementing 'optind' and returning + * a null argument. + */ + else if (_sindex(optstart, *optarg) != NULL) { + --optind; + optarg = NULL; + } + } + } + place = EMSG; + ++optind; + } + + /* + * Return option letter. + */ + return (optopt); +} diff --git a/jbsmooth.c b/jbsmooth.c new file mode 100644 index 0000000..ad2138d --- /dev/null +++ b/jbsmooth.c @@ -0,0 +1,120 @@ +/* + * jbsmooth.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains cross-block smoothing routines. + * These routines are invoked via the smooth_coefficients method. + */ + +#include "jinclude.h" + +#ifdef BLOCK_SMOOTHING_SUPPORTED + + +/* + * Cross-block coefficient smoothing. + */ + +METHODDEF void +smooth_coefficients (decompress_info_ptr cinfo, + jpeg_component_info *compptr, + JBLOCKROW above, + JBLOCKROW currow, + JBLOCKROW below, + JBLOCKROW output) +{ + QUANT_TBL_PTR Qptr = cinfo->quant_tbl_ptrs[compptr->quant_tbl_no]; + long blocks_in_row = compptr->subsampled_width / DCTSIZE; + long col; + + /* First, copy the block row as-is. + * This takes care of the first & last blocks in the row, the top/bottom + * special cases, and the higher-order coefficients in each block. + */ + jcopy_block_row(currow, output, blocks_in_row); + + /* Now apply the smoothing calculation, but not to any blocks on the + * edges of the image. + */ + + if (above != NULL && below != NULL) { + for (col = 1; col < blocks_in_row-1; col++) { + + /* See section 13.10 of JPEG-8-R8, or K.8 of JPEG-9-R6. + * + * As I understand it, this produces approximations + * for the low frequency AC components, based on the + * DC values of the block and its eight neighboring blocks. + * (Thus it can't be used for blocks on the image edges.) + */ + + /* The layout of these variables corresponds to + * the text in 13.10 + */ + + JCOEF DC1, DC2, DC3; + JCOEF DC4, DC5, DC6; + JCOEF DC7, DC8, DC9; + + long AC01, AC02; + long AC10, AC11; + long AC20; + + DC1 = above [col-1][0]; + DC2 = above [col ][0]; + DC3 = above [col+1][0]; + DC4 = currow[col-1][0]; + DC5 = currow[col ][0]; + DC6 = currow[col+1][0]; + DC7 = below [col-1][0]; + DC8 = below [col ][0]; + DC9 = below [col+1][0]; + +#define DIVIDE_256(x) x = ( (x) < 0 ? -((128-(x))/256) : ((x)+128)/256 ) + + AC01 = (36 * (DC4 - DC6)); + DIVIDE_256(AC01); + AC10 = (36 * (DC2 - DC8)); + DIVIDE_256(AC10); + AC20 = (9 * (DC2 + DC8 - 2*DC5)); + DIVIDE_256(AC20); + AC11 = (5 * ((DC1 - DC3) - (DC7 - DC9))); + DIVIDE_256(AC11); + AC02 = (9 * (DC4 + DC6 - 2*DC5)); + DIVIDE_256(AC02); + + /* I think that this checks to see if the quantisation + * on the transmitting side would have produced this + * answer. If so, then we use our (hopefully better) + * estimate. + */ + +#define ABS(x) ((x) < 0 ? -(x) : (x)) + +#define COND_ASSIGN(_ac,_n,_z) if ((ABS(output[col][_n] - (_ac))<<1) <= Qptr[_z]) output[col][_n] = (_ac) + + COND_ASSIGN(AC01, 1, 1); + COND_ASSIGN(AC02, 2, 5); + COND_ASSIGN(AC10, 8, 2); + COND_ASSIGN(AC11, 9, 4); + COND_ASSIGN(AC20, 16, 3); + } + } +} + + +/* + * The method selection routine for cross-block smoothing. + */ + +GLOBAL void +jselbsmooth (decompress_info_ptr cinfo) +{ + /* just one implementation for now */ + cinfo->methods->smooth_coefficients = smooth_coefficients; +} + +#endif /* BLOCK_SMOOTHING_SUPPORTED */ diff --git a/jcarith.c b/jcarith.c new file mode 100644 index 0000000..1949459 --- /dev/null +++ b/jcarith.c @@ -0,0 +1,42 @@ +/* + * jcarith.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains arithmetic entropy encoding routines. + * These routines are invoked via the methods entropy_encode, + * entropy_encoder_init/term, and entropy_optimize. + */ + +#include "jinclude.h" + +#ifdef ARITH_CODING_SUPPORTED + + +/* + * The arithmetic coding option of the JPEG standard specifies Q-coding, + * which is covered by patents held by IBM (and possibly AT&T and Mitsubishi). + * At this time it does not appear to be legal for the Independent JPEG + * Group to distribute software that implements arithmetic coding. + * We have therefore removed arithmetic coding support from the + * distributed source code. + * + * We're not happy about it either. + */ + + +/* + * The method selection routine for arithmetic entropy encoding. + */ + +GLOBAL void +jselcarithmetic (compress_info_ptr cinfo) +{ + if (cinfo->arith_code) { + ERREXIT(cinfo->emethods, "Sorry, there are legal restrictions on arithmetic coding"); + } +} + +#endif /* ARITH_CODING_SUPPORTED */ diff --git a/jccolor.c b/jccolor.c new file mode 100644 index 0000000..7fd198c --- /dev/null +++ b/jccolor.c @@ -0,0 +1,203 @@ +/* + * jccolor.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains input colorspace conversion routines. + * These routines are invoked via the methods get_sample_rows + * and colorin_init/term. + */ + +#include "jinclude.h" + + +static JSAMPARRAY pixel_row; /* Workspace for a pixel row in input format */ + + +/* + * Initialize for colorspace conversion. + */ + +METHODDEF void +colorin_init (compress_info_ptr cinfo) +{ + /* Allocate a workspace for the result of get_input_row. */ + pixel_row = (*cinfo->emethods->alloc_small_sarray) + (cinfo->image_width, (long) cinfo->input_components); +} + + +/* + * Fetch some rows of pixels from get_input_row and convert to the + * JPEG colorspace. + * This version handles RGB -> YCbCr conversion. + * YCbCr is defined per CCIR 601-1, except that Cb and Cr are + * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + */ + +METHODDEF void +get_rgb_ycc_rows (compress_info_ptr cinfo, + int rows_to_read, JSAMPIMAGE image_data) +{ + register INT32 r, g, b; + register JSAMPROW inptr0, inptr1, inptr2; + register JSAMPROW outptr0, outptr1, outptr2; + register long col; + long width = cinfo->image_width; + int row; + + for (row = 0; row < rows_to_read; row++) { + /* Read one row from the source file */ + (*cinfo->methods->get_input_row) (cinfo, pixel_row); + /* Convert colorspace */ + inptr0 = pixel_row[0]; + inptr1 = pixel_row[1]; + inptr2 = pixel_row[2]; + outptr0 = image_data[0][row]; + outptr1 = image_data[1][row]; + outptr2 = image_data[2][row]; + for (col = width; col > 0; col--) { + r = GETJSAMPLE(*inptr0++); + g = GETJSAMPLE(*inptr1++); + b = GETJSAMPLE(*inptr2++); + /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations + * must be too; do not need an explicit range-limiting operation. + */ + /* Y */ + *outptr0++ = ( 306*r + 601*g + 117*b + (INT32) 512) >> 10; + /* Cb */ + *outptr1++ = ((-173)*r - 339*g + 512*b + (INT32) 512*(MAXJSAMPLE+1)) >> 10; + /* Cr */ + *outptr2++ = ( 512*r - 429*g - 83*b + (INT32) 512*(MAXJSAMPLE+1)) >> 10; + } + } +} + + +/* + * Fetch some rows of pixels from get_input_row and convert to the + * JPEG colorspace. + * This version handles grayscale (no conversion). + */ + +METHODDEF void +get_grayscale_rows (compress_info_ptr cinfo, + int rows_to_read, JSAMPIMAGE image_data) +{ + int row; + + for (row = 0; row < rows_to_read; row++) { + /* Read one row from the source file */ + (*cinfo->methods->get_input_row) (cinfo, pixel_row); + /* Convert colorspace (gamma mapping needed here) */ + jcopy_sample_rows(pixel_row, 0, image_data[0], row, + 1, cinfo->image_width); + } +} + + +/* + * Fetch some rows of pixels from get_input_row and convert to the + * JPEG colorspace. + * This version handles multi-component colorspaces without conversion. + */ + +METHODDEF void +get_noconvert_rows (compress_info_ptr cinfo, + int rows_to_read, JSAMPIMAGE image_data) +{ + int row, ci; + + for (row = 0; row < rows_to_read; row++) { + /* Read one row from the source file */ + (*cinfo->methods->get_input_row) (cinfo, pixel_row); + /* Convert colorspace (gamma mapping needed here) */ + for (ci = 0; ci < cinfo->input_components; ci++) { + jcopy_sample_rows(pixel_row, ci, image_data[ci], row, + 1, cinfo->image_width); + } + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +colorin_term (compress_info_ptr cinfo) +{ + /* Release the workspace. */ + (*cinfo->emethods->free_small_sarray) + (pixel_row, (long) cinfo->input_components); +} + + +/* + * The method selection routine for input colorspace conversion. + */ + +GLOBAL void +jselccolor (compress_info_ptr cinfo) +{ + /* Make sure input_components agrees with in_color_space */ + switch (cinfo->in_color_space) { + case CS_GRAYSCALE: + if (cinfo->input_components != 1) + ERREXIT(cinfo->emethods, "Bogus input colorspace"); + break; + + case CS_RGB: + if (cinfo->input_components != 3) + ERREXIT(cinfo->emethods, "Bogus input colorspace"); + break; + + case CS_CMYK: + if (cinfo->input_components != 4) + ERREXIT(cinfo->emethods, "Bogus input colorspace"); + break; + + default: + ERREXIT(cinfo->emethods, "Unsupported input colorspace"); + break; + } + + /* Check num_components, set conversion method based on requested space */ + switch (cinfo->jpeg_color_space) { + case CS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo->emethods, "Bogus JPEG colorspace"); + if (cinfo->in_color_space == CS_GRAYSCALE) + cinfo->methods->get_sample_rows = get_grayscale_rows; + else + ERREXIT(cinfo->emethods, "Unsupported color conversion request"); + break; + + case CS_YCbCr: + if (cinfo->num_components != 3) + ERREXIT(cinfo->emethods, "Bogus JPEG colorspace"); + if (cinfo->in_color_space == CS_RGB) + cinfo->methods->get_sample_rows = get_rgb_ycc_rows; + else + ERREXIT(cinfo->emethods, "Unsupported color conversion request"); + break; + + case CS_CMYK: + if (cinfo->num_components != 4) + ERREXIT(cinfo->emethods, "Bogus JPEG colorspace"); + if (cinfo->in_color_space == CS_CMYK) + cinfo->methods->get_sample_rows = get_noconvert_rows; + else + ERREXIT(cinfo->emethods, "Unsupported color conversion request"); + break; + + default: + ERREXIT(cinfo->emethods, "Unsupported JPEG colorspace"); + break; + } + + cinfo->methods->colorin_init = colorin_init; + cinfo->methods->colorin_term = colorin_term; +} diff --git a/jcdeflts.c b/jcdeflts.c new file mode 100644 index 0000000..cd1624a --- /dev/null +++ b/jcdeflts.c @@ -0,0 +1,364 @@ +/* + * jcdeflts.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains optional default-setting code for the JPEG compressor. + */ + +#include "jinclude.h" + + +LOCAL void +add_huff_table (compress_info_ptr cinfo, + HUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val) +/* Define a Huffman table */ +{ + if (*htblptr == NULL) + *htblptr = (*cinfo->emethods->alloc_small) (SIZEOF(HUFF_TBL)); + + memcpy((void *) (*htblptr)->bits, (void *) bits, + SIZEOF((*htblptr)->bits)); + memcpy((void *) (*htblptr)->huffval, (void *) val, + SIZEOF((*htblptr)->huffval)); + + /* Initialize sent_table FALSE so table will be written to JPEG file. + * In an application where we are writing non-interchange JPEG files, + * it might be desirable to save space by leaving default Huffman tables + * out of the file. To do that, just initialize sent_table = TRUE... + */ + + (*htblptr)->sent_table = FALSE; +} + + +LOCAL void +std_huff_tables (compress_info_ptr cinfo) +/* Set up the standard Huffman tables (cf. JPEG-8-R8 section 13.3) */ +{ + static const UINT8 dc_luminance_bits[17] = + { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }; + static const UINT8 dc_luminance_val[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 dc_chrominance_bits[17] = + { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }; + static const UINT8 dc_chrominance_val[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 ac_luminance_bits[17] = + { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d }; + static const UINT8 ac_luminance_val[] = + { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + static const UINT8 ac_chrominance_bits[17] = + { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 }; + static const UINT8 ac_chrominance_val[] = + { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[0], + dc_luminance_bits, dc_luminance_val); + add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[0], + ac_luminance_bits, ac_luminance_val); + add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[1], + dc_chrominance_bits, dc_chrominance_val); + add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[1], + ac_chrominance_bits, ac_chrominance_val); +} + + +/* This is the sample quantization table given in JPEG-8-R8 sec 13.1, + * but expressed in zigzag order (as are all of our quant. tables). + * The spec says that the values given produce "good" quality, and + * when divided by 2, "very good" quality. (These two settings are + * selected by quality=50 and quality=75 in j_set_quality, below.) + */ + + +static const QUANT_VAL std_luminance_quant_tbl[DCTSIZE2] = { + 16, 11, 12, 14, 12, 10, 16, 14, + 13, 14, 18, 17, 16, 19, 24, 40, + 26, 24, 22, 22, 24, 49, 35, 37, + 29, 40, 58, 51, 61, 60, 57, 51, + 56, 55, 64, 72, 92, 78, 64, 68, + 87, 69, 55, 56, 80, 109, 81, 87, + 95, 98, 103, 104, 103, 62, 77, 113, + 121, 112, 100, 120, 92, 101, 103, 99 +}; + +static const QUANT_VAL std_chrominance_quant_tbl[DCTSIZE2] = { + 17, 18, 18, 24, 21, 24, 47, 26, + 26, 47, 99, 66, 56, 66, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 +}; + + +LOCAL void +add_quant_table (compress_info_ptr cinfo, int which_tbl, + const QUANT_VAL *basic_table, int scale_factor, + boolean force_baseline) +/* Define a quantization table equal to the basic_table times */ +/* a scale factor (given as a percentage) */ +{ + QUANT_TBL_PTR * qtblptr = & cinfo->quant_tbl_ptrs[which_tbl]; + int i; + long temp; + + if (*qtblptr == NULL) + *qtblptr = (*cinfo->emethods->alloc_small) (SIZEOF(QUANT_TBL)); + + for (i = 0; i < DCTSIZE2; i++) { + temp = ((long) basic_table[i] * scale_factor + 50L) / 100L; + /* limit the values to the valid range */ + if (temp <= 0L) temp = 1L; +#ifdef EIGHT_BIT_SAMPLES + if (temp > 32767L) temp = 32767L; /* QUANT_VALs are 'short' */ +#else + if (temp > 65535L) temp = 65535L; /* QUANT_VALs are 'UINT16' */ +#endif + if (force_baseline && temp > 255L) + temp = 255L; /* limit to baseline range if requested */ + (*qtblptr)[i] = (QUANT_VAL) temp; + } +} + + +GLOBAL void +j_set_quality (compress_info_ptr cinfo, int quality, boolean force_baseline) +/* Set or change the 'quality' (quantization) setting. */ +/* The 'quality' factor should be 0 (terrible) to 100 (very good). */ +/* Quality 50 corresponds to the JPEG basic tables given above; */ +/* quality 100 results in no quantization scaling at all. */ +/* If force_baseline is TRUE, quantization table entries are limited */ +/* to 0..255 for JPEG baseline compatibility; this is only an issue */ +/* for quality settings below 24. */ +{ + /* Safety limit on quality factor. Convert 0 to 1 to avoid zero divide. */ + if (quality <= 0) quality = 1; + if (quality > 100) quality = 100; + + /* Convert quality rating to a percentage scaling of the basic tables. + * The basic table is used as-is (scaling 100) for a quality of 50. + * Qualities 50..100 are converted to scaling percentage 200 - 2*Q; + * note that at Q=100 the scaling is 0, which will cause add_quant_table + * to make all the table entries 1 (hence, no quantization loss). + * Qualities 1..50 are converted to scaling percentage 5000/Q. + */ + if (quality < 50) + quality = 5000 / quality; + else + quality = 200 - quality*2; + + /* Set up two quantization tables using the specified quality scaling */ + add_quant_table(cinfo, 0, std_luminance_quant_tbl, quality, force_baseline); + add_quant_table(cinfo, 1, std_chrominance_quant_tbl, quality, force_baseline); +} + + + +/* Default parameter setup for compression. + * + * User interfaces that don't choose to use this routine must do their + * own setup of all these parameters. Alternately, you can call this + * to establish defaults and then alter parameters selectively. + * + * See above for the meaning of the 'quality' parameter. Typically, + * the application's default quality setting will be passed to this + * routine. A later call on j_set_quality() can be used to change to + * a user-specified quality setting. + * + * This sets up for a color image; to output a grayscale image, + * do this first and call j_monochrome_default() afterwards. + * (The latter can be called within c_ui_method_selection, so the + * choice can depend on the input file header.) + * Note that if you want a JPEG colorspace other than GRAYSCALE or YCbCr, + * you should also change the component ID codes, and you should NOT emit + * a JFIF header (set write_JFIF_header = FALSE). + * + * CAUTION: if you want to compress multiple images per run, it's safest + * to call j_default_compression before *each* call to jpeg_compress (and + * j_free_defaults afterwards). If this isn't practical, you'll have to + * be careful to reset any individual parameters that may change during + * the compression run. The main thing you need to worry about as this + * is written is that the sent_table boolean in each Huffman table must + * be reset to FALSE before each compression; otherwise, Huffman tables + * won't get emitted for the second and subsequent images. + */ + +GLOBAL void +j_default_compression (compress_info_ptr cinfo, int quality) +/* NB: the external methods must already be set up. */ +{ + short i; + jpeg_component_info * compptr; + + /* Initialize pointers as needed to mark stuff unallocated. */ + cinfo->comp_info = NULL; + for (i = 0; i < NUM_QUANT_TBLS; i++) + cinfo->quant_tbl_ptrs[i] = NULL; + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + cinfo->data_precision = 8; /* default; can be overridden by input_init */ + cinfo->density_unit = 0; /* Pixel size is unknown by default */ + cinfo->X_density = 1; /* Pixel aspect ratio is square by default */ + cinfo->Y_density = 1; + + cinfo->input_gamma = 1.0; /* no gamma correction by default */ + + /* Prepare three color components; first is luminance which is also usable */ + /* for grayscale. The others are assumed to be UV or similar chrominance. */ + cinfo->write_JFIF_header = TRUE; + cinfo->jpeg_color_space = CS_YCbCr; + cinfo->num_components = 3; + cinfo->comp_info = (*cinfo->emethods->alloc_small) + (4 * SIZEOF(jpeg_component_info)); + /* Note: we allocate a 4-entry comp_info array so that user interface can + * easily change over to CMYK color space if desired. + */ + + compptr = &cinfo->comp_info[0]; + compptr->component_index = 0; + compptr->component_id = 1; /* JFIF specifies IDs 1,2,3 */ + compptr->h_samp_factor = 2; /* default to 2x2 subsamples of chrominance */ + compptr->v_samp_factor = 2; + compptr->quant_tbl_no = 0; /* use tables 0 for luminance */ + compptr->dc_tbl_no = 0; + compptr->ac_tbl_no = 0; + + compptr = &cinfo->comp_info[1]; + compptr->component_index = 1; + compptr->component_id = 2; + compptr->h_samp_factor = 1; + compptr->v_samp_factor = 1; + compptr->quant_tbl_no = 1; /* use tables 1 for chrominance */ + compptr->dc_tbl_no = 1; + compptr->ac_tbl_no = 1; + + compptr = &cinfo->comp_info[2]; + compptr->component_index = 2; + compptr->component_id = 3; + compptr->h_samp_factor = 1; + compptr->v_samp_factor = 1; + compptr->quant_tbl_no = 1; /* use tables 1 for chrominance */ + compptr->dc_tbl_no = 1; + compptr->ac_tbl_no = 1; + + /* Set up two quantization tables using the specified quality scaling */ + /* Baseline compatibility is forced (a nonissue for reasonable defaults) */ + j_set_quality(cinfo, quality, TRUE); + + /* Set up two Huffman tables in case user interface wants Huffman coding */ + std_huff_tables(cinfo); + + /* Initialize default arithmetic coding conditioning */ + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + + /* Use Huffman coding, not arithmetic coding, by default */ + cinfo->arith_code = FALSE; + + /* Color images are interleaved by default */ + cinfo->interleave = TRUE; + + /* By default, don't do extra passes to optimize entropy coding */ + cinfo->optimize_coding = FALSE; + + /* By default, use the simpler non-cosited sampling alignment */ + cinfo->CCIR601_sampling = FALSE; + + /* No restart markers */ + cinfo->restart_interval = 0; +} + + + +GLOBAL void +j_monochrome_default (compress_info_ptr cinfo) +/* Change the j_default_compression() values to emit a monochrome JPEG file. */ +{ + jpeg_component_info * compptr; + + cinfo->jpeg_color_space = CS_GRAYSCALE; + cinfo->num_components = 1; + /* Set single component to 1x1 subsampling */ + compptr = &cinfo->comp_info[0]; + compptr->h_samp_factor = 1; + compptr->v_samp_factor = 1; +} + + + +/* This routine releases storage allocated by j_default_compression. + * Note that freeing the method pointer structs and the compress_info_struct + * itself are the responsibility of the user interface. + */ + +GLOBAL void +j_free_defaults (compress_info_ptr cinfo) +{ + short i; + +#define FREE(ptr) if ((ptr) != NULL) \ + (*cinfo->emethods->free_small) ((void *) ptr) + + FREE(cinfo->comp_info); + for (i = 0; i < NUM_QUANT_TBLS; i++) + FREE(cinfo->quant_tbl_ptrs[i]); + for (i = 0; i < NUM_HUFF_TBLS; i++) { + FREE(cinfo->dc_huff_tbl_ptrs[i]); + FREE(cinfo->ac_huff_tbl_ptrs[i]); + } +} diff --git a/jcexpand.c b/jcexpand.c new file mode 100644 index 0000000..94878bd --- /dev/null +++ b/jcexpand.c @@ -0,0 +1,75 @@ +/* + * jcexpand.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains image edge-expansion routines. + * These routines are invoked via the edge_expand method. + */ + +#include "jinclude.h" + + +/* + * Expand an image so that it is a multiple of the MCU dimensions. + * This is to be accomplished by duplicating the rightmost column + * and/or bottommost row of pixels. The image has not yet been + * subsampled, so all components have the same dimensions. + */ + +METHODDEF void +edge_expand (compress_info_ptr cinfo, + long input_cols, int input_rows, + long output_cols, int output_rows, + JSAMPIMAGE image_data) +{ + /* Expand horizontally */ + if (input_cols < output_cols) { + register JSAMPROW ptr; + register JSAMPLE pixval; + register long count; + register int row; + short ci; + long numcols = output_cols - input_cols; + + for (ci = 0; ci < cinfo->num_components; ci++) { + for (row = 0; row < input_rows; row++) { + ptr = image_data[ci][row] + (input_cols-1); + pixval = GETJSAMPLE(*ptr++); + for (count = numcols; count > 0; count--) + *ptr++ = pixval; + } + } + } + + /* Expand vertically */ + /* This happens only once at the bottom of the image, */ + /* so it needn't be super-efficient */ + if (input_rows < output_rows) { + register int row; + short ci; + JSAMPARRAY this_component; + + for (ci = 0; ci < cinfo->num_components; ci++) { + this_component = image_data[ci]; + for (row = input_rows; row < output_rows; row++) { + jcopy_sample_rows(this_component, input_rows-1, this_component, row, + 1, output_cols); + } + } + } +} + + +/* + * The method selection routine for edge expansion. + */ + +GLOBAL void +jselexpand (compress_info_ptr cinfo) +{ + /* just one implementation for now */ + cinfo->methods->edge_expand = edge_expand; +} diff --git a/jchuff.c b/jchuff.c new file mode 100644 index 0000000..531bc75 --- /dev/null +++ b/jchuff.c @@ -0,0 +1,689 @@ +/* + * jchuff.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy encoding routines. + * These routines are invoked via the methods entropy_encode, + * entropy_encoder_init/term, and entropy_optimize. + */ + +#include "jinclude.h" + + +/* Static variables to avoid passing 'round extra parameters */ + +static compress_info_ptr cinfo; + +static INT32 huff_put_buffer; /* current bit-accumulation buffer */ +static int huff_put_bits; /* # of bits now in it */ + +static char * output_buffer; /* output buffer */ +static int bytes_in_buffer; + + + +LOCAL void +fix_huff_tbl (HUFF_TBL * htbl) +/* Compute derived values for a Huffman table */ +{ + int p, i, l, lastp, si; + char huffsize[257]; + UINT16 huffcode[257]; + UINT16 code; + + /* Figure 7.3.5.4.2.1: make table of Huffman code length for each symbol */ + /* Note that this is in code-length order. */ + + p = 0; + for (l = 1; l <= 16; l++) { + for (i = 1; i <= htbl->bits[l]; i++) + huffsize[p++] = l; + } + huffsize[p] = 0; + lastp = p; + + /* Figure 7.3.5.4.2.2: generate the codes themselves */ + /* Note that this is in code-length order. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (huffsize[p] == si) { + huffcode[p++] = code; + code++; + } + code <<= 1; + si++; + } + + /* Figure 7.3.5.4.2.3: generate encoding tables */ + /* These are code and size indexed by symbol value */ + + for (p = 0; p < lastp; p++) { + htbl->ehufco[htbl->huffval[p]] = huffcode[p]; + htbl->ehufsi[htbl->huffval[p]] = huffsize[p]; + } + + /* Figure 13.4.2.3.1: generate decoding tables */ + + p = 0; + for (l = 1; l <= 16; l++) { + if (htbl->bits[l]) { + htbl->valptr[l] = p; /* huffval[] index of 1st sym of code len l */ + htbl->mincode[l] = huffcode[p]; /* minimum code of length l */ + p += htbl->bits[l]; + htbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */ + } else { + htbl->maxcode[l] = -1; + } + } +} + + +/* Outputting bytes to the file */ + +LOCAL void +flush_bytes (void) +{ + if (bytes_in_buffer) + (*cinfo->methods->entropy_output) (cinfo, output_buffer, bytes_in_buffer); + bytes_in_buffer = 0; +} + + +#define emit_byte(val) ((bytes_in_buffer >= JPEG_BUF_SIZE ? \ + (flush_bytes(), 0) : 0), \ + output_buffer[bytes_in_buffer] = (val), \ + bytes_in_buffer++) + + + +/* Outputting bits to the file */ + +/* Only the right 24 bits of huff_put_buffer are used; the valid bits are + * left-justified in this part. At most 16 bits can be passed to emit_bits + * in one call, and we never retain more than 7 bits in huff_put_buffer + * between calls, so 24 bits are sufficient. + */ + +LOCAL void +emit_bits (UINT16 code, int size) +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer = code; + register int put_bits = huff_put_bits; + + put_buffer &= (((INT32) 1) << size) - 1; /* Mask off any excess bits in code */ + + put_bits += size; /* new number of bits in buffer */ + + put_buffer <<= 24 - put_bits; /* align incoming bits */ + + put_buffer |= huff_put_buffer; /* and merge with old buffer contents */ + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte(c); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte(0); + } + put_buffer <<= 8; + put_bits -= 8; + } + + huff_put_buffer = put_buffer; /* Update global variables */ + huff_put_bits = put_bits; +} + + +LOCAL void +flush_bits (void) +{ + emit_bits((UINT16) 0x7F, 7); /* fill any partial byte with ones */ + huff_put_buffer = 0; /* and reset bit-buffer to empty */ + huff_put_bits = 0; +} + + + +/* Encode a single block's worth of coefficients */ +/* Note that the DC coefficient has already been converted to a difference */ + +LOCAL void +encode_one_block (JBLOCK block, HUFF_TBL *dctbl, HUFF_TBL *actbl) +{ + register INT32 temp; + register int nbits; + register int k, r, i; + + /* Encode the DC coefficient difference per section 7.3.5.1 */ + + /* Find the number of bits needed for the magnitude of the coefficient */ + temp = block[0]; + if (temp < 0) temp = -temp; + + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + + /* Emit the Huffman-coded symbol for the number of bits */ + emit_bits(dctbl->ehufco[nbits], dctbl->ehufsi[nbits]); + + /* If positive, emit nbits low order bits; */ + /* if negative, emit nbits low order bits of value-1 */ + if ((temp = block[0]) < 0) + temp--; + + emit_bits((UINT16) temp, nbits); + + /* Encode the AC coefficients per section 7.3.5.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k < DCTSIZE2; k++) { + if ((temp = block[k]) == 0) { + r++; + } else { + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + emit_bits(actbl->ehufco[0xF0], actbl->ehufsi[0xF0]); + r -= 16; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + if (temp < 0) temp = -temp; + + nbits = 1; /* there must be at least one 1 bit */ + while (temp >>= 1) + nbits++; + + /* Emit Huffman symbol for run length / number of bits */ + i = (r << 4) + nbits; + emit_bits(actbl->ehufco[i], actbl->ehufsi[i]); + + /* If positive, emit nbits low order bits; */ + /* if negative, emit nbits low order bits of value-1 */ + if ((temp = block[k]) < 0) + temp--; + + emit_bits((UINT16) temp, nbits); + + r = 0; + } + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + emit_bits(actbl->ehufco[0], actbl->ehufsi[0]); +} + + + +/* + * Initialize for a Huffman-compressed scan. + * This is invoked after writing the SOS marker. + * The pipeline controller must establish the entropy_output method pointer + * before calling this routine. + */ + +METHODDEF void +huff_init (compress_info_ptr xinfo) +{ + short ci; + jpeg_component_info * compptr; + + /* Initialize static variables */ + cinfo = xinfo; + huff_put_buffer = 0; + huff_put_bits = 0; + + /* Initialize the output buffer */ + output_buffer = (char *) (*cinfo->emethods->alloc_small) + ((size_t) JPEG_BUF_SIZE); + bytes_in_buffer = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Make sure requested tables are present */ + if (cinfo->dc_huff_tbl_ptrs[compptr->dc_tbl_no] == NULL || + cinfo->ac_huff_tbl_ptrs[compptr->ac_tbl_no] == NULL) + ERREXIT(cinfo->emethods, "Use of undefined Huffman table"); + /* Compute derived values for Huffman tables */ + /* We may do this more than once for same table, but it's not a big deal */ + fix_huff_tbl(cinfo->dc_huff_tbl_ptrs[compptr->dc_tbl_no]); + fix_huff_tbl(cinfo->ac_huff_tbl_ptrs[compptr->ac_tbl_no]); + /* Initialize DC predictions to 0 */ + cinfo->last_dc_val[ci] = 0; + } + + /* Initialize restart stuff */ + cinfo->restarts_to_go = cinfo->restart_interval; + cinfo->next_restart_num = 0; +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL void +emit_restart (compress_info_ptr cinfo) +{ + short ci; + + flush_bits(); + + emit_byte(0xFF); + emit_byte(RST0 + cinfo->next_restart_num); + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + cinfo->last_dc_val[ci] = 0; + + /* Update restart state */ + cinfo->restarts_to_go = cinfo->restart_interval; + cinfo->next_restart_num++; + cinfo->next_restart_num &= 7; +} + + +/* + * Encode and output one MCU's worth of Huffman-compressed coefficients. + */ + +METHODDEF void +huff_encode (compress_info_ptr cinfo, JBLOCK *MCU_data) +{ + short blkn, ci; + jpeg_component_info * compptr; + JCOEF temp; + + /* Account for restart interval, emit restart marker if needed */ + if (cinfo->restart_interval) { + if (cinfo->restarts_to_go == 0) + emit_restart(cinfo); + cinfo->restarts_to_go--; + } + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + /* Convert DC value to difference, update last_dc_val */ + temp = MCU_data[blkn][0]; + MCU_data[blkn][0] -= cinfo->last_dc_val[ci]; + cinfo->last_dc_val[ci] = temp; + encode_one_block(MCU_data[blkn], + cinfo->dc_huff_tbl_ptrs[compptr->dc_tbl_no], + cinfo->ac_huff_tbl_ptrs[compptr->ac_tbl_no]); + } +} + + +/* + * Finish up at the end of a Huffman-compressed scan. + */ + +METHODDEF void +huff_term (compress_info_ptr cinfo) +{ + /* Flush out the last data */ + flush_bits(); + flush_bytes(); + /* Release the I/O buffer */ + (*cinfo->emethods->free_small) ((void *) output_buffer); +} + + + + +/* + * Huffman coding optimization. + * + * This actually is optimization, in the sense that we find the best possible + * Huffman table(s) for the given data. We first scan the supplied data and + * count the number of uses of each symbol that is to be Huffman-coded. + * (This process must agree with the code above.) Then we build an + * optimal Huffman coding tree for the observed counts. + */ + +#ifdef ENTROPY_OPT_SUPPORTED + + +/* These are static so htest_one_block can find 'em */ +static long * dc_count_ptrs[NUM_HUFF_TBLS]; +static long * ac_count_ptrs[NUM_HUFF_TBLS]; + + +LOCAL void +gen_huff_coding (compress_info_ptr cinfo, HUFF_TBL *htbl, long freq[]) +/* Generate the optimal coding for the given counts */ +{ +#define MAX_CLEN 32 /* assumed maximum initial code length */ + UINT8 bits[MAX_CLEN+1]; /* bits[k] = # of symbols with code length k */ + short codesize[257]; /* codesize[k] = code length of symbol k */ + short others[257]; /* next symbol in current branch of tree */ + int c1, c2; + int p, i, j; + long v; + + /* This algorithm is explained in section 13.2 of JPEG-8-R8 */ + + MEMZERO((void *) bits, SIZEOF(bits)); + MEMZERO((void *) codesize, SIZEOF(codesize)); + for (i = 0; i < 257; i++) + others[i] = -1; /* init links to empty */ + + freq[256] = 1; /* make sure there is a nonzero count */ + /* including the pseudo-symbol 256 in the Huffman procedure guarantees + * that no real symbol is given code-value of all ones, because 256 + * will be placed in the largest codeword category. + */ + + /* Huffman's basic algorithm to assign optimal code lengths to symbols */ + + for (;;) { + /* Find the smallest nonzero frequency, set c1 = its symbol */ + /* In case of ties, take the larger symbol number */ + c1 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v) { + v = freq[i]; + c1 = i; + } + } + + /* Find the next smallest nonzero frequency, set c2 = its symbol */ + /* In case of ties, take the larger symbol number */ + c2 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v && i != c1) { + v = freq[i]; + c2 = i; + } + } + + /* Done if we've merged everything into one frequency */ + if (c2 < 0) + break; + + /* Else merge the two counts/trees */ + freq[c1] += freq[c2]; + freq[c2] = 0; + + /* Increment the codesize of everything in c1's tree branch */ + codesize[c1]++; + while (others[c1] >= 0) { + c1 = others[c1]; + codesize[c1]++; + } + + others[c1] = c2; /* chain c2 onto c1's tree branch */ + + /* Increment the codesize of everything in c2's tree branch */ + codesize[c2]++; + while (others[c2] >= 0) { + c2 = others[c2]; + codesize[c2]++; + } + } + + /* Now count the number of symbols of each code length */ + for (i = 0; i <= 256; i++) { + if (codesize[i]) { + /* The JPEG standard seems to think that this can't happen, */ + /* but I'm paranoid... */ + if (codesize[i] > MAX_CLEN) + ERREXIT(cinfo->emethods, "Huffman code size table overflow"); + + bits[codesize[i]]++; + } + } + + /* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure + * Huffman procedure assigned any such lengths, we must adjust the coding. + * Here is what the JPEG spec says about how this next bit works: + * Since symbols are paired for the longest Huffman code, the symbols are + * removed from this length category two at a time. The prefix for the pair + * (which is one bit shorter) is allocated to one of the pair; then, + * skipping the BITS entry for that prefix length, a code word from the next + * shortest nonzero BITS entry is converted into a prefix for two code words + * one bit longer. + */ + + for (i = MAX_CLEN; i > 16; i--) { + while (bits[i] > 0) { + j = i - 2; /* find length of new prefix to be used */ + while (bits[j] == 0) + j--; + + bits[i] -= 2; /* remove two symbols */ + bits[i-1]++; /* one goes in this length */ + bits[j+1] += 2; /* two new symbols in this length */ + bits[j]--; /* symbol of this length is now a prefix */ + } + } + + /* Remove the count for the pseudo-symbol 256 from the largest codelength */ + while (bits[i] == 0) /* find largest codelength still in use */ + i--; + bits[i]--; + + /* Return final symbol counts (only for lengths 0..16) */ + memcpy((void *) htbl->bits, (void *) bits, SIZEOF(htbl->bits)); + + /* Return a list of the symbols sorted by code length */ + /* It's not real clear to me why we don't need to consider the codelength + * changes made above, but the JPEG spec seems to think this works. + */ + p = 0; + for (i = 1; i <= MAX_CLEN; i++) { + for (j = 0; j <= 255; j++) { + if (codesize[j] == i) { + htbl->huffval[p] = j; + p++; + } + } + } +} + + +/* Process a single block's worth of coefficients */ +/* Note that the DC coefficient has already been converted to a difference */ + +LOCAL void +htest_one_block (JBLOCK block, JCOEF block0, + long dc_counts[], long ac_counts[]) +{ + register INT32 temp; + register int nbits; + register int k, r; + + /* Encode the DC coefficient difference per section 7.3.5.1 */ + + /* Find the number of bits needed for the magnitude of the coefficient */ + temp = block0; + if (temp < 0) temp = -temp; + + for (nbits = 0; temp; nbits++) + temp >>= 1; + + /* Count the Huffman symbol for the number of bits */ + dc_counts[nbits]++; + + /* Encode the AC coefficients per section 7.3.5.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k < DCTSIZE2; k++) { + if ((temp = block[k]) == 0) { + r++; + } else { + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + ac_counts[0xF0]++; + r -= 16; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + if (temp < 0) temp = -temp; + + for (nbits = 0; temp; nbits++) + temp >>= 1; + + /* Count Huffman symbol for run length / number of bits */ + ac_counts[(r << 4) + nbits]++; + + r = 0; + } + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + ac_counts[0]++; +} + + + +/* + * Trial-encode one MCU's worth of Huffman-compressed coefficients. + */ + +LOCAL void +htest_encode (compress_info_ptr cinfo, JBLOCK *MCU_data) +{ + short blkn, ci; + jpeg_component_info * compptr; + + /* Take care of restart intervals if needed */ + if (cinfo->restart_interval) { + if (cinfo->restarts_to_go == 0) { + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + cinfo->last_dc_val[ci] = 0; + /* Update restart state */ + cinfo->restarts_to_go = cinfo->restart_interval; + } + cinfo->restarts_to_go--; + } + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + /* NB: unlike the real entropy encoder, we may not change the input data */ + htest_one_block(MCU_data[blkn], + (JCOEF) (MCU_data[blkn][0] - cinfo->last_dc_val[ci]), + dc_count_ptrs[compptr->dc_tbl_no], + ac_count_ptrs[compptr->ac_tbl_no]); + cinfo->last_dc_val[ci] = MCU_data[blkn][0]; + } +} + + + +/* + * Find the best coding parameters for a Huffman-coded scan. + * When called, the scan data has already been converted to a sequence of + * MCU groups of quantized coefficients, which are stored in a "big" array. + * The source_method knows how to iterate through that array. + * On return, the MCU data is unmodified, but the Huffman tables referenced + * by the scan components may have been altered. + */ + +METHODDEF void +huff_optimize (compress_info_ptr cinfo, MCU_output_caller_ptr source_method) +/* Optimize Huffman-coding parameters (Huffman symbol table) */ +{ + int i, tbl; + HUFF_TBL **htblptr; + + /* Allocate and zero the count tables */ + /* Note that gen_huff_coding expects 257 entries in each table! */ + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + dc_count_ptrs[i] = NULL; + ac_count_ptrs[i] = NULL; + } + + for (i = 0; i < cinfo->comps_in_scan; i++) { + /* Create DC table */ + tbl = cinfo->cur_comp_info[i]->dc_tbl_no; + if (dc_count_ptrs[tbl] == NULL) { + dc_count_ptrs[tbl] = (long *) (*cinfo->emethods->alloc_small) + (257 * SIZEOF(long)); + MEMZERO((void *) dc_count_ptrs[tbl], 257 * SIZEOF(long)); + } + /* Create AC table */ + tbl = cinfo->cur_comp_info[i]->ac_tbl_no; + if (ac_count_ptrs[tbl] == NULL) { + ac_count_ptrs[tbl] = (long *) (*cinfo->emethods->alloc_small) + (257 * SIZEOF(long)); + MEMZERO((void *) ac_count_ptrs[tbl], 257 * SIZEOF(long)); + } + } + + /* Initialize DC predictions to 0 */ + for (i = 0; i < cinfo->comps_in_scan; i++) { + cinfo->last_dc_val[i] = 0; + } + /* Initialize restart stuff */ + cinfo->restarts_to_go = cinfo->restart_interval; + + /* Scan the MCU data, count symbol uses */ + (*source_method) (cinfo, htest_encode); + + /* Now generate optimal Huffman tables */ + for (tbl = 0; tbl < NUM_HUFF_TBLS; tbl++) { + if (dc_count_ptrs[tbl] != NULL) { + htblptr = & cinfo->dc_huff_tbl_ptrs[tbl]; + if (*htblptr == NULL) + *htblptr = (*cinfo->emethods->alloc_small) (SIZEOF(HUFF_TBL)); + /* Set sent_table FALSE so updated table will be written to JPEG file. */ + (*htblptr)->sent_table = FALSE; + /* Compute the optimal Huffman encoding */ + gen_huff_coding(cinfo, *htblptr, dc_count_ptrs[tbl]); + /* Release the count table */ + (*cinfo->emethods->free_small) ((void *) dc_count_ptrs[tbl]); + } + if (ac_count_ptrs[tbl] != NULL) { + htblptr = & cinfo->ac_huff_tbl_ptrs[tbl]; + if (*htblptr == NULL) + *htblptr = (*cinfo->emethods->alloc_small) (SIZEOF(HUFF_TBL)); + /* Set sent_table FALSE so updated table will be written to JPEG file. */ + (*htblptr)->sent_table = FALSE; + /* Compute the optimal Huffman encoding */ + gen_huff_coding(cinfo, *htblptr, ac_count_ptrs[tbl]); + /* Release the count table */ + (*cinfo->emethods->free_small) ((void *) ac_count_ptrs[tbl]); + } + } +} + + +#endif /* ENTROPY_OPT_SUPPORTED */ + + +/* + * The method selection routine for Huffman entropy encoding. + */ + +GLOBAL void +jselchuffman (compress_info_ptr cinfo) +{ + if (! cinfo->arith_code) { + cinfo->methods->entropy_encoder_init = huff_init; + cinfo->methods->entropy_encode = huff_encode; + cinfo->methods->entropy_encoder_term = huff_term; +#ifdef ENTROPY_OPT_SUPPORTED + cinfo->methods->entropy_optimize = huff_optimize; +#endif + } +} diff --git a/jcmain.c b/jcmain.c new file mode 100644 index 0000000..f71d5ad --- /dev/null +++ b/jcmain.c @@ -0,0 +1,272 @@ +/* + * jcmain.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a trivial test user interface for the JPEG compressor. + * It should work on any system with Unix- or MS-DOS-style command lines. + * + * Two different command line styles are permitted, depending on the + * compile-time switch TWO_FILE_COMMANDLINE: + * cjpeg [options] inputfile outputfile + * cjpeg [options] [inputfile] + * In the second style, output is always to standard output, which you'd + * normally redirect to a file or pipe to some other program. Input is + * either from a named file or from standard input (typically redirected). + * The second style is convenient on Unix but is unhelpful on systems that + * don't support pipes. Also, you MUST use the first style if your system + * doesn't do binary I/O to stdin/stdout. + */ + +#include "jinclude.h" +#ifdef __STDC__ +#include /* to declare exit() */ +#endif + +#ifdef THINK_C +#include /* command-line reader for Macintosh */ +#endif + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define WRITE_BINARY "w" +#else +#define READ_BINARY "rb" +#define WRITE_BINARY "wb" +#endif + + +/* + * If your system has getopt(3), you can use your library version by + * defining HAVE_GETOPT. By default, we use the PD 'egetopt'. + */ + +#ifdef HAVE_GETOPT +extern int getopt PP((int argc, char **argv, char *optstring)); +extern char * optarg; +extern int optind; +#else +#include "egetopt.c" +#define getopt(argc,argv,opt) egetopt(argc,argv,opt) +#endif + + +/* + * This routine determines what format the input file is, + * and selects the appropriate input-reading module. + * + * To determine which family of input formats the file belongs to, + * we look only at the first byte of the file, since C does not + * guarantee that more than one character can be pushed back with ungetc. + * This is sufficient for the currently envisioned set of input formats. + * + * If you need to look at more than one character to select an input module, + * you can either + * 1) assume you can fseek() the input file (may fail for piped input); + * 2) assume you can push back more than one character (works in + * some C implementations, but unportable); + * or 3) don't put back the data, and modify the various input_init + * methods to assume they start reading after the start of file. + */ + +LOCAL void +select_file_type (compress_info_ptr cinfo) +{ + int c; + + if ((c = getc(cinfo->input_file)) == EOF) + ERREXIT(cinfo->emethods, "Empty input file"); + + switch (c) { +#ifdef GIF_SUPPORTED + case 'G': + jselrgif(cinfo); + break; +#endif +#ifdef PPM_SUPPORTED + case 'P': + jselrppm(cinfo); + break; +#endif + default: + ERREXIT(cinfo->emethods, "Unsupported input file format"); + break; + } + + if (ungetc(c, cinfo->input_file) == EOF) + ERREXIT(cinfo->emethods, "ungetc failed"); +} + + +/* + * This routine gets control after the input file header has been read. + * It must determine what output JPEG file format is to be written, + * and make any other compression parameter changes that are desirable. + */ + +METHODDEF void +c_ui_method_selection (compress_info_ptr cinfo) +{ + /* If the input is gray scale, generate a monochrome JPEG file. */ + if (cinfo->in_color_space == CS_GRAYSCALE) + j_monochrome_default(cinfo); + /* For now, always select JFIF output format. */ +#ifdef JFIF_SUPPORTED + jselwjfif(cinfo); +#else + You shoulda defined JFIF_SUPPORTED. /* deliberate syntax error */ +#endif +} + + +LOCAL void +usage (char * progname) +/* complain about bad command line */ +{ + fprintf(stderr, "usage: %s ", progname); + fprintf(stderr, "[-I] [-Q quality 0..100] [-a] [-o] [-d]"); +#ifdef TWO_FILE_COMMANDLINE + fprintf(stderr, " inputfile outputfile\n"); +#else + fprintf(stderr, " [inputfile]\n"); +#endif + exit(2); +} + + +/* + * The main program. + */ + +GLOBAL void +main (int argc, char **argv) +{ + struct compress_info_struct cinfo; + struct compress_methods_struct c_methods; + struct external_methods_struct e_methods; + int c; + + /* On Mac, fetch a command line. */ +#ifdef THINK_C + argc = ccommand(&argv); +#endif + + /* Initialize the system-dependent method pointers. */ + cinfo.methods = &c_methods; + cinfo.emethods = &e_methods; + jselerror(&e_methods); /* error/trace message routines */ + jselvirtmem(&e_methods); /* memory allocation routines */ + c_methods.c_ui_method_selection = c_ui_method_selection; + + /* Set up default input and output file references. */ + /* (These may be overridden below.) */ + cinfo.input_file = stdin; + cinfo.output_file = stdout; + + /* Set up default parameters. */ + e_methods.trace_level = 0; + j_default_compression(&cinfo, 75); /* default quality level */ + + /* Scan parameters */ + + while ((c = getopt(argc, argv, "IQ:aod")) != EOF) + switch (c) { + case 'I': /* Create noninterleaved file. */ +#ifdef MULTISCAN_FILES_SUPPORTED + cinfo.interleave = FALSE; +#else + fprintf(stderr, "%s: sorry, multiple-scan support was not compiled\n", + argv[0]); + exit(2); +#endif + break; + case 'Q': /* Quality factor. */ + { int val; + if (optarg == NULL) + usage(argv[0]); + if (sscanf(optarg, "%d", &val) != 1) + usage(argv[0]); + /* Note: for now, we leave force_baseline FALSE. + * In a production user interface, probably should make it TRUE + * unless overridden by a separate switch. + */ + j_set_quality(&cinfo, val, FALSE); + } + break; + case 'a': /* Use arithmetic coding. */ +#ifdef ARITH_CODING_SUPPORTED + cinfo.arith_code = TRUE; +#else + fprintf(stderr, "%s: sorry, arithmetic coding not supported\n", + argv[0]); + exit(2); +#endif + break; + case 'o': /* Enable entropy parm optimization. */ +#ifdef ENTROPY_OPT_SUPPORTED + cinfo.optimize_coding = TRUE; +#else + fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n", + argv[0]); + exit(2); +#endif + break; + case 'd': /* Debugging. */ + e_methods.trace_level++; + break; + case '?': + default: + usage(argv[0]); + break; + } + + /* Select the input and output files */ + +#ifdef TWO_FILE_COMMANDLINE + + if (optind != argc-2) { + fprintf(stderr, "%s: must name one input and one output file\n", argv[0]); + usage(argv[0]); + } + if ((cinfo.input_file = fopen(argv[optind], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", argv[0], argv[optind]); + exit(2); + } + if ((cinfo.output_file = fopen(argv[optind+1], WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", argv[0], argv[optind+1]); + exit(2); + } + +#else /* not TWO_FILE_COMMANDLINE -- use Unix style */ + + if (optind < argc-1) { + fprintf(stderr, "%s: only one input file\n", argv[0]); + usage(argv[0]); + } + if (optind < argc) { + if ((cinfo.input_file = fopen(argv[optind], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", argv[0], argv[optind]); + exit(2); + } + } + +#endif /* TWO_FILE_COMMANDLINE */ + + /* Figure out the input file format, and set up to read it. */ + select_file_type(&cinfo); + + /* Do it to it! */ + jpeg_compress(&cinfo); + + /* Release memory. */ + j_free_defaults(&cinfo); +#ifdef MEM_STATS + if (e_methods.trace_level > 0) + j_mem_stats(); +#endif + + /* All done. */ + exit(0); +} diff --git a/jcmaster.c b/jcmaster.c new file mode 100644 index 0000000..b15217a --- /dev/null +++ b/jcmaster.c @@ -0,0 +1,127 @@ +/* + * jcmaster.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main control for the JPEG compressor. + * The system-dependent (user interface) code should call jpeg_compress() + * after doing appropriate setup of the compress_info_struct parameter. + */ + +#include "jinclude.h" + + +METHODDEF void +c_per_scan_method_selection (compress_info_ptr cinfo) +/* Central point for per-scan method selection */ +{ + /* Edge expansion */ + jselexpand(cinfo); + /* Subsampling of pixels */ + jselsubsample(cinfo); + /* MCU extraction */ + jselcmcu(cinfo); +} + + +LOCAL void +c_initial_method_selection (compress_info_ptr cinfo) +/* Central point for initial method selection */ +{ + /* Input image reading method selection is already done. */ + /* So is output file header formatting (both are done by user interface). */ + + /* Gamma and color space conversion */ + jselccolor(cinfo); + /* Entropy encoding: either Huffman or arithmetic coding. */ +#ifdef ARITH_CODING_SUPPORTED + jselcarithmetic(cinfo); +#else + cinfo->arith_code = FALSE; /* force Huffman mode */ +#endif + jselchuffman(cinfo); + /* Pipeline control */ + jselcpipeline(cinfo); + /* Overall control (that's me!) */ + cinfo->methods->c_per_scan_method_selection = c_per_scan_method_selection; +} + + +LOCAL void +initial_setup (compress_info_ptr cinfo) +/* Do computations that are needed before initial method selection */ +{ + short ci; + jpeg_component_info *compptr; + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0; ci < cinfo->num_components; ci++) { + compptr = &cinfo->comp_info[ci]; + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo->emethods, "Bogus sampling factors"); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + + } + + /* Compute logical subsampled dimensions of components */ + for (ci = 0; ci < cinfo->num_components; ci++) { + compptr = &cinfo->comp_info[ci]; + compptr->true_comp_width = (cinfo->image_width * compptr->h_samp_factor + + cinfo->max_h_samp_factor - 1) + / cinfo->max_h_samp_factor; + compptr->true_comp_height = (cinfo->image_height * compptr->v_samp_factor + + cinfo->max_v_samp_factor - 1) + / cinfo->max_v_samp_factor; + } +} + + +/* + * This is the main entry point to the JPEG compressor. + */ + + +GLOBAL void +jpeg_compress (compress_info_ptr cinfo) +{ + /* Read the input file header: determine image size & component count. + * NOTE: the user interface must have initialized the input_init method + * pointer (eg, by calling jselrppm) before calling me. + * The other file reading methods (get_input_row etc.) were probably + * set at the same time, but could be set up by input_init itself, + * or by c_ui_method_selection. + */ + (*cinfo->methods->input_init) (cinfo); + + /* Give UI a chance to adjust compression parameters and select */ + /* output file format based on results of input_init. */ + (*cinfo->methods->c_ui_method_selection) (cinfo); + + /* Now select methods for compression steps. */ + initial_setup(cinfo); + c_initial_method_selection(cinfo); + + /* Initialize the output file & other modules as needed */ + /* (entropy_encoder is inited by pipeline controller) */ + + (*cinfo->methods->colorin_init) (cinfo); + (*cinfo->methods->write_file_header) (cinfo); + + /* And let the pipeline controller do the rest. */ + (*cinfo->methods->c_pipeline_controller) (cinfo); + + /* Finish output file, release working storage, etc */ + (*cinfo->methods->write_file_trailer) (cinfo); + (*cinfo->methods->colorin_term) (cinfo); + (*cinfo->methods->input_term) (cinfo); + + /* My, that was easy, wasn't it? */ +} diff --git a/jcmcu.c b/jcmcu.c new file mode 100644 index 0000000..1400eab --- /dev/null +++ b/jcmcu.c @@ -0,0 +1,212 @@ +/* + * jcmcu.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains MCU extraction routines and quantization scaling. + * These routines are invoked via the extract_MCUs and + * extract_init/term methods. + */ + +#include "jinclude.h" + + +/* + * If this file is compiled with -DDCT_ERR_STATS, it will reverse-DCT each + * block and sum the total errors across the whole picture. This provides + * a convenient method of using real picture data to test the roundoff error + * of a DCT algorithm. DCT_ERR_STATS should *not* be defined for a production + * compression program, since compression is much slower with it defined. + * Also note that jrevdct.o must be linked into the compressor when this + * switch is defined. + */ + +#ifdef DCT_ERR_STATS +static int dcterrorsum; /* these hold the error statistics */ +static int dcterrormax; +static int dctcoefcount; /* This will probably overflow on a 16-bit-int machine */ +#endif + + +/* ZAG[i] is the natural-order position of the i'th element of zigzag order. */ + +static const short ZAG[DCTSIZE2] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + + +LOCAL void +extract_block (JSAMPARRAY input_data, int start_row, long start_col, + JBLOCK output_data, QUANT_TBL_PTR quanttbl) +/* Extract one 8x8 block from the specified location in the sample array; */ +/* perform forward DCT, quantization scaling, and zigzag reordering on it. */ +{ + /* This routine is heavily used, so it's worth coding it tightly. */ + DCTBLOCK block; +#ifdef DCT_ERR_STATS + DCTBLOCK svblock; /* saves input data for comparison */ +#endif + + { register JSAMPROW elemptr; + register DCTELEM *localblkptr = block; +#if DCTSIZE != 8 + register short elemc; +#endif + register short elemr; + + for (elemr = DCTSIZE; elemr > 0; elemr--) { + elemptr = input_data[start_row++] + start_col; +#if DCTSIZE == 8 /* unroll the inner loop */ + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; +#else + for (elemc = DCTSIZE; elemc > 0; elemc--) { + *localblkptr++ = (DCTELEM) GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + } +#endif + } + } + +#ifdef DCT_ERR_STATS + memcpy((void *) svblock, (void *) block, SIZEOF(DCTBLOCK)); +#endif + + j_fwd_dct(block); + + { register JCOEF temp; + register short i; + + for (i = 0; i < DCTSIZE2; i++) { + temp = (JCOEF) block[ZAG[i]]; + /* divide by *quanttbl, ensuring proper rounding */ + if (temp < 0) { + temp = -temp; + temp += *quanttbl>>1; + temp /= *quanttbl; + temp = -temp; + } else { + temp += *quanttbl>>1; + temp /= *quanttbl; + } + *output_data++ = temp; + quanttbl++; + } + } + +#ifdef DCT_ERR_STATS + j_rev_dct(block); + + { register int diff; + register short i; + + for (i = 0; i < DCTSIZE2; i++) { + diff = block[i] - svblock[i]; + if (diff < 0) diff = -diff; + dcterrorsum += diff; + if (dcterrormax < diff) dcterrormax = diff; + } + dctcoefcount += DCTSIZE2; + } +#endif +} + + +/* + * Extract samples in MCU order, process & hand off to output_method. + * The input is always exactly N MCU rows worth of data. + */ + +METHODDEF void +extract_MCUs (compress_info_ptr cinfo, + JSAMPIMAGE image_data, + int num_mcu_rows, + MCU_output_method_ptr output_method) +{ + JBLOCK MCU_data[MAX_BLOCKS_IN_MCU]; + int mcurow; + long mcuindex; + short blkn, ci, xpos, ypos; + jpeg_component_info * compptr; + QUANT_TBL_PTR quant_ptr; + + for (mcurow = 0; mcurow < num_mcu_rows; mcurow++) { + for (mcuindex = 0; mcuindex < cinfo->MCUs_per_row; mcuindex++) { + /* Extract data from the image array, DCT it, and quantize it */ + blkn = 0; + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + quant_ptr = cinfo->quant_tbl_ptrs[compptr->quant_tbl_no]; + for (ypos = 0; ypos < compptr->MCU_height; ypos++) { + for (xpos = 0; xpos < compptr->MCU_width; xpos++) { + extract_block(image_data[ci], + (mcurow * compptr->MCU_height + ypos)*DCTSIZE, + (mcuindex * compptr->MCU_width + xpos)*DCTSIZE, + MCU_data[blkn], quant_ptr); + blkn++; + } + } + } + /* Send the MCU whereever the pipeline controller wants it to go */ + (*output_method) (cinfo, MCU_data); + } + } +} + + +/* + * Initialize for processing a scan. + */ + +METHODDEF void +extract_init (compress_info_ptr cinfo) +{ + /* no work for now */ +#ifdef DCT_ERR_STATS + dcterrorsum = dcterrormax = dctcoefcount = 0; +#endif +} + + +/* + * Clean up after a scan. + */ + +METHODDEF void +extract_term (compress_info_ptr cinfo) +{ + /* no work for now */ +#ifdef DCT_ERR_STATS + TRACEMS3(cinfo->emethods, 0, "DCT roundoff errors = %d/%d, max = %d", + dcterrorsum, dctcoefcount, dcterrormax); +#endif +} + + + +/* + * The method selection routine for MCU extraction. + */ + +GLOBAL void +jselcmcu (compress_info_ptr cinfo) +{ + /* just one implementation for now */ + cinfo->methods->extract_init = extract_init; + cinfo->methods->extract_MCUs = extract_MCUs; + cinfo->methods->extract_term = extract_term; +} diff --git a/jconfig.h b/jconfig.h new file mode 100644 index 0000000..3b22acb --- /dev/null +++ b/jconfig.h @@ -0,0 +1,320 @@ +/* + * jconfig.h + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains preprocessor declarations that help customize + * the JPEG software for a particular application, machine, or compiler. + * Edit these declarations as needed (or add -D flags to the Makefile). + */ + + +/* + * These symbols indicate the properties of your machine or compiler. + * The conditional definitions given may do the right thing already, + * but you'd best look them over closely, especially if your compiler + * does not handle full ANSI C. An ANSI-compliant C compiler should + * provide all the necessary features; __STDC__ is supposed to be + * predefined by such compilers. + */ + +/* Does your compiler support function prototypes? */ +/* (If not, you also need to use ansi2knr, see README) */ + +#ifdef __STDC__ /* ANSI C compilers always have prototypes */ +#define PROTO +#else +#ifdef __cplusplus /* So do C++ compilers */ +#define PROTO +#endif +#endif + +/* Does your compiler support the declaration "unsigned char" ? */ +/* How about "unsigned short" ? */ + +#ifdef __STDC__ /* ANSI C compilers must support both */ +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +#endif + +/* Define this if an ordinary "char" type is unsigned. + * If you're not sure, leaving it undefined will work at some cost in speed. + * If you defined HAVE_UNSIGNED_CHAR then it doesn't matter very much. + */ + +/* #define CHAR_IS_UNSIGNED */ + +/* Define this if your compiler implements ">>" on signed values as a logical + * (unsigned) shift; leave it undefined if ">>" is a signed (arithmetic) shift, + * which is the normal and rational definition. + * The DCT and IDCT routines will compute wrong values if you get this wrong! + */ + +/* #define RIGHT_SHIFT_IS_UNSIGNED */ + +/* Define "void" as "char" if your compiler doesn't know about type void. + * NOTE: be sure to define void such that "void *" represents the most general + * pointer type, e.g., that returned by malloc(). + */ + +/* #define void char */ + +/* Define const as empty if your compiler doesn't know the "const" keyword. */ +/* (Even if it does, defining const as empty won't break anything.) */ + +#ifndef __STDC__ /* ANSI C and C++ compilers should know it. */ +#ifndef __cplusplus +#define const +#endif +#endif + +/* For 80x86 machines, you need to define NEED_FAR_POINTERS, + * unless you are using a large-data memory model or 80386 flat-memory mode. + * On less brain-damaged CPUs this symbol must not be defined. + * (Defining this symbol causes large data structures to be referenced through + * "far" pointers and to be allocated with a special version of malloc.) + */ + +#ifdef MSDOS /* Microsoft C and compatibles */ +#define NEED_FAR_POINTERS +#else +#ifdef __TURBOC__ /* Turbo C doesn't define MSDOS */ +#define NEED_FAR_POINTERS +#endif +#endif + + +/* The next couple of symbols only affect the system-dependent user interface + * modules (jcmain.c, jdmain.c). You can ignore these if you are supplying + * your own user interface code. + */ + +/* Define this if you want to name both input and output files on the command + * line, rather than using stdout and optionally stdin. You MUST do this if + * your system can't cope with binary I/O to stdin/stdout. See comments at + * head of jcmain.c or jdmain.c. + */ + +#ifdef MSDOS /* two-file style is needed for PCs */ +#define TWO_FILE_COMMANDLINE +#else +#ifdef __TURBOC__ /* Turbo C doesn't define MSDOS */ +#define TWO_FILE_COMMANDLINE +#endif +#endif +#ifdef THINK_C /* needed for Macintosh too */ +#define TWO_FILE_COMMANDLINE +#endif + +/* By default, we open image files with fopen(...,"rb") or fopen(...,"wb"). + * This is necessary on systems that distinguish text files from binary files, + * and is harmless on most systems that don't. If you have one of the rare + * systems that complains about the "b" spec, define this symbol. + */ + +/* #define DONT_USE_B_MODE */ + + +/* If you're getting bored, that's the end of the symbols you HAVE to + * worry about. Go fix the makefile and compile. + */ + + +/* If your compiler supports inline functions, define INLINE as + * the inline keyword; otherwise define it as empty. + */ + +#ifdef __GNUC__ /* GNU C has inline... */ +#define INLINE inline +#else /* ...but I don't think anyone else does. */ +#define INLINE +#endif + +/* On a few systems, type boolean and/or macros FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * In that case you need only comment out these definitions. + */ + +typedef int boolean; +#define FALSE 0 /* values of boolean */ +#define TRUE 1 + +/* This defines the size of the I/O buffers for entropy compression + * and decompression; you could reduce it if memory is tight. + */ + +#define JPEG_BUF_SIZE 4096 /* bytes */ + + + +/* These symbols determine the JPEG functionality supported. */ + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * program file. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */ +#undef ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing during decoding? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#undef QUANT_2PASS_SUPPORTED /* 2-pass color quantization? (not yet impl.) */ +/* these defines indicate which JPEG file formats are allowed */ +#define JFIF_SUPPORTED /* JFIF or "raw JPEG" files */ +#undef JTIFF_SUPPORTED /* JPEG-in-TIFF (not yet implemented) */ +/* these defines indicate which image (non-JPEG) file formats are allowed */ +#define PPM_SUPPORTED /* PPM/PGM image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#undef TIFF_SUPPORTED /* TIFF image file format (not yet impl.) */ + +/* more capability options later, no doubt */ + + +/* + * Define exactly one of these three symbols to indicate whether you want + * 8-bit, 12-bit, or 16-bit sample (pixel component) values. 8-bit is the + * default and is nearly always the right thing to use. You can use 12-bit if + * you need to support image formats with more than 8 bits of resolution in a + * color value. 16-bit should only be used for the lossless JPEG mode (not + * currently supported). Note that 12- and 16-bit values take up twice as + * much memory as 8-bit! + */ + +#define EIGHT_BIT_SAMPLES +#undef TWELVE_BIT_SAMPLES +#undef SIXTEEN_BIT_SAMPLES + + + +/* + * The remaining definitions don't need to be hand-edited in most cases. + * You may need to change these if you have a machine with unusual data + * types; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* First define the representation of a single pixel element value. */ + +#ifdef EIGHT_BIT_SAMPLES +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + * If you have only signed chars, and you are more worried about speed than + * memory usage, it might be a win to make JSAMPLE be short. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED + +typedef char JSAMPLE; +#define GETJSAMPLE(value) (value) + +#else /* not CHAR_IS_UNSIGNED */ + +typedef char JSAMPLE; +#define GETJSAMPLE(value) ((value) & 0xFF) + +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* EIGHT_BIT_SAMPLES */ + + +#ifdef TWELVE_BIT_SAMPLES +/* JSAMPLE should be the smallest type that will hold the values 0..4095. */ +/* On nearly all machines "short" will do nicely. */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) (value) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* TWELVE_BIT_SAMPLES */ + + +#ifdef SIXTEEN_BIT_SAMPLES +/* JSAMPLE should be the smallest type that will hold the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT + +typedef unsigned short JSAMPLE; +#define GETJSAMPLE(value) (value) + +#else /* not HAVE_UNSIGNED_SHORT */ + +/* If int is 32 bits this'll be horrendously inefficient storage-wise. + * But since we don't actually support 16-bit samples (ie lossless coding) yet, + * I'm not going to worry about making a smarter definition ... + */ +typedef unsigned int JSAMPLE; +#define GETJSAMPLE(value) (value) + +#endif /* HAVE_UNSIGNED_SHORT */ + +#define MAXJSAMPLE 65535 +#define CENTERJSAMPLE 32768 + +#endif /* SIXTEEN_BIT_SAMPLES */ + + +/* Here we define the representation of a DCT frequency coefficient. + * This should be a signed 16-bit value; "short" is usually right. + * It's important that this be exactly 16 bits, no more and no less; + * more will cost you a BIG hit of memory, less will give wrong answers. + */ + +typedef short JCOEF; + + +/* The remaining typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char UINT8; +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char UINT8; +#else /* not CHAR_IS_UNSIGNED */ +typedef short UINT8; +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +/* UINT16 must hold at least the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT +typedef unsigned short UINT16; +#else /* not HAVE_UNSIGNED_SHORT */ +typedef unsigned int UINT16; +#endif /* HAVE_UNSIGNED_SHORT */ + +/* INT16 must hold at least the values -32768..32767. */ + +typedef short INT16; + +/* INT32 must hold signed 32-bit values; if your machine happens */ +/* to have 64-bit longs, you might want to change this. */ + +typedef long INT32; diff --git a/jcpipe.c b/jcpipe.c new file mode 100644 index 0000000..f58e7db --- /dev/null +++ b/jcpipe.c @@ -0,0 +1,715 @@ +/* + * jcpipe.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains compression pipeline controllers. + * These routines are invoked via the c_pipeline_controller method. + * + * There are four basic pipeline controllers, one for each combination of: + * single-scan JPEG file (single component or fully interleaved) + * vs. multiple-scan JPEG file (noninterleaved or partially interleaved). + * + * optimization of entropy encoding parameters + * vs. usage of default encoding parameters. + * + * Note that these conditions determine the needs for "big" arrays: + * multiple scans imply a big array for splitting the color components; + * entropy encoding optimization needs a big array for the MCU data. + * + * All but the simplest controller (single-scan, no optimization) can be + * compiled out through configuration options, if you need to make a minimal + * implementation. + */ + +#include "jinclude.h" + + +/* + * About the data structures: + * + * The processing chunk size for subsampling is referred to in this file as + * a "row group": a row group is defined as Vk (v_samp_factor) sample rows of + * any component after subsampling, or Vmax (max_v_samp_factor) unsubsampled + * rows. In an interleaved scan each MCU row contains exactly DCTSIZE row + * groups of each component in the scan. In a noninterleaved scan an MCU row + * is one row of blocks, which might not be an integral number of row groups; + * for convenience we use a buffer of the same size as in interleaved scans, + * and process Vk MCU rows in each burst of subsampling. + * To provide context for the subsampling step, we have to retain the last + * two row groups of the previous MCU row while reading in the next MCU row + * (or set of Vk MCU rows). To do this without copying data about, we create + * a rather strange data structure. Exactly DCTSIZE+2 row groups of samples + * are allocated, but we create two different sets of pointers to this array. + * The second set swaps the last two pairs of row groups. By working + * alternately with the two sets of pointers, we can access the data in the + * desired order. + */ + + + +/* + * Utility routines: common code for pipeline controllers + */ + +LOCAL void +interleaved_scan_setup (compress_info_ptr cinfo) +/* Compute all derived info for an interleaved (multi-component) scan */ +/* On entry, cinfo->comps_in_scan and cinfo->cur_comp_info[] are set up */ +{ + short ci, mcublks; + jpeg_component_info *compptr; + + if (cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT(cinfo->emethods, "Too many components for interleaved scan"); + + cinfo->MCUs_per_row = (cinfo->image_width + + cinfo->max_h_samp_factor*DCTSIZE - 1) + / (cinfo->max_h_samp_factor*DCTSIZE); + + cinfo->MCU_rows_in_scan = (cinfo->image_height + + cinfo->max_v_samp_factor*DCTSIZE - 1) + / (cinfo->max_v_samp_factor*DCTSIZE); + + cinfo->blocks_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* for interleaved scan, sampling factors give # of blocks per component */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; + /* compute physical dimensions of component */ + compptr->subsampled_width = jround_up(compptr->true_comp_width, + (long) (compptr->MCU_width*DCTSIZE)); + compptr->subsampled_height = jround_up(compptr->true_comp_height, + (long) (compptr->MCU_height*DCTSIZE)); + /* Sanity check */ + if (compptr->subsampled_width != + (cinfo->MCUs_per_row * (compptr->MCU_width*DCTSIZE))) + ERREXIT(cinfo->emethods, "I'm confused about the image width"); + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_blocks; + if (cinfo->blocks_in_MCU + mcublks > MAX_BLOCKS_IN_MCU) + ERREXIT(cinfo->emethods, "Sampling factors too large for interleaved scan"); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; + } + } + + (*cinfo->methods->c_per_scan_method_selection) (cinfo); +} + + +LOCAL void +noninterleaved_scan_setup (compress_info_ptr cinfo) +/* Compute all derived info for a noninterleaved (single-component) scan */ +/* On entry, cinfo->comps_in_scan = 1 and cinfo->cur_comp_info[0] is set up */ +{ + jpeg_component_info *compptr = cinfo->cur_comp_info[0]; + + /* for noninterleaved scan, always one block per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_blocks = 1; + /* compute physical dimensions of component */ + compptr->subsampled_width = jround_up(compptr->true_comp_width, + (long) DCTSIZE); + compptr->subsampled_height = jround_up(compptr->true_comp_height, + (long) DCTSIZE); + + cinfo->MCUs_per_row = compptr->subsampled_width / DCTSIZE; + cinfo->MCU_rows_in_scan = compptr->subsampled_height / DCTSIZE; + + /* Prepare array describing MCU composition */ + cinfo->blocks_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + (*cinfo->methods->c_per_scan_method_selection) (cinfo); +} + + + +LOCAL void +alloc_sampling_buffer (compress_info_ptr cinfo, JSAMPIMAGE fullsize_data[2], + long fullsize_width) +/* Create a pre-subsampling data buffer having the desired structure */ +/* (see comments at head of file) */ +{ + short ci, vs, i; + + vs = cinfo->max_v_samp_factor; /* row group height */ + + /* Get top-level space for array pointers */ + fullsize_data[0] = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(JSAMPARRAY)); + fullsize_data[1] = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(JSAMPARRAY)); + + for (ci = 0; ci < cinfo->num_components; ci++) { + /* Allocate the real storage */ + fullsize_data[0][ci] = (*cinfo->emethods->alloc_small_sarray) + (fullsize_width, + (long) (vs * (DCTSIZE+2))); + /* Create space for the scrambled-order pointers */ + fullsize_data[1][ci] = (JSAMPARRAY) (*cinfo->emethods->alloc_small) + (vs * (DCTSIZE+2) * SIZEOF(JSAMPROW)); + /* Duplicate the first DCTSIZE-2 row groups */ + for (i = 0; i < vs * (DCTSIZE-2); i++) { + fullsize_data[1][ci][i] = fullsize_data[0][ci][i]; + } + /* Copy the last four row groups in swapped order */ + for (i = 0; i < vs * 2; i++) { + fullsize_data[1][ci][vs*DCTSIZE + i] = fullsize_data[0][ci][vs*(DCTSIZE-2) + i]; + fullsize_data[1][ci][vs*(DCTSIZE-2) + i] = fullsize_data[0][ci][vs*DCTSIZE + i]; + } + } +} + + +LOCAL void +free_sampling_buffer (compress_info_ptr cinfo, JSAMPIMAGE fullsize_data[2]) +/* Release a sampling buffer created by alloc_sampling_buffer */ +{ + short ci, vs; + + vs = cinfo->max_v_samp_factor; /* row group height */ + + for (ci = 0; ci < cinfo->num_components; ci++) { + /* Free the real storage */ + (*cinfo->emethods->free_small_sarray) + (fullsize_data[0][ci], (long) (vs * (DCTSIZE+2))); + /* Free the scrambled-order pointers */ + (*cinfo->emethods->free_small) ((void *) fullsize_data[1][ci]); + } + + /* Free the top-level space */ + (*cinfo->emethods->free_small) ((void *) fullsize_data[0]); + (*cinfo->emethods->free_small) ((void *) fullsize_data[1]); +} + + +LOCAL void +subsample (compress_info_ptr cinfo, + JSAMPIMAGE fullsize_data, JSAMPIMAGE subsampled_data, + long fullsize_width, + short above, short current, short below, short out) +/* Do subsampling of a single row group (of each component). */ +/* above, current, below are indexes of row groups in fullsize_data; */ +/* out is the index of the target row group in subsampled_data. */ +/* Special case: above, below can be -1 to indicate top, bottom of image. */ +{ + jpeg_component_info *compptr; + JSAMPARRAY above_ptr, below_ptr; + JSAMPROW dummy[MAX_SAMP_FACTOR]; /* for subsample expansion at top/bottom */ + short ci, vs, i; + + vs = cinfo->max_v_samp_factor; /* row group height */ + + for (ci = 0; ci < cinfo->num_components; ci++) { + compptr = & cinfo->comp_info[ci]; + + if (above >= 0) + above_ptr = fullsize_data[ci] + above * vs; + else { + /* Top of image: make a dummy above-context with copies of 1st row */ + /* We assume current=0 in this case */ + for (i = 0; i < vs; i++) + dummy[i] = fullsize_data[ci][0]; + above_ptr = (JSAMPARRAY) dummy; /* possible near->far pointer conv */ + } + + if (below >= 0) + below_ptr = fullsize_data[ci] + below * vs; + else { + /* Bot of image: make a dummy below-context with copies of last row */ + for (i = 0; i < vs; i++) + dummy[i] = fullsize_data[ci][(current+1)*vs-1]; + below_ptr = (JSAMPARRAY) dummy; /* possible near->far pointer conv */ + } + + (*cinfo->methods->subsample[ci]) + (cinfo, (int) ci, + fullsize_width, (int) vs, + compptr->subsampled_width, (int) compptr->v_samp_factor, + above_ptr, + fullsize_data[ci] + current * vs, + below_ptr, + subsampled_data[ci] + out * compptr->v_samp_factor); + } +} + + +/* These vars are initialized by the pipeline controller for use by + * MCU_output_catcher. + * To avoid a lot of row-pointer overhead, we cram as many MCUs into each + * row of whole_scan_MCUs as we can get without exceeding 64KB per row. + */ + +#define MAX_WHOLE_ROW_BLOCKS (65500 / SIZEOF(JBLOCK)) /* max blocks/row */ + +static big_barray_ptr whole_scan_MCUs; /* Big array for saving the MCUs */ +static int MCUs_in_big_row; /* # of MCUs in each row of whole_scan_MCUs */ +static long next_whole_row; /* next row to access in whole_scan_MCUs */ +static int next_MCU_index; /* next MCU in current row */ + + +METHODDEF void +MCU_output_catcher (compress_info_ptr cinfo, JBLOCK *MCU_data) +/* Output method for siphoning off extract_MCUs output into a big array */ +{ + static JBLOCKARRAY rowptr; + + if (next_MCU_index >= MCUs_in_big_row) { + rowptr = (*cinfo->emethods->access_big_barray) (whole_scan_MCUs, + next_whole_row, TRUE); + next_whole_row++; + next_MCU_index = 0; + } + + /* + * note that on 80x86, the cast applied to MCU_data implies + * near to far pointer conversion. + */ + jcopy_block_row((JBLOCKROW) MCU_data, + rowptr[0] + next_MCU_index * cinfo->blocks_in_MCU, + (long) cinfo->blocks_in_MCU); + next_MCU_index++; +} + + +METHODDEF void +dump_scan_MCUs (compress_info_ptr cinfo, MCU_output_method_ptr output_method) +/* Dump the MCUs saved in whole_scan_MCUs to the output method. */ +/* The method may be either the entropy encoder or some routine supplied */ +/* by the entropy optimizer. */ +{ + /* On an 80x86 machine, the entropy encoder expects the passed data block + * to be in NEAR memory (for performance reasons), so we have to copy it + * back from the big array to a local array. On less brain-damaged CPUs + * we needn't do that. + */ +#ifdef NEED_FAR_POINTERS + JBLOCK MCU_data[MAX_BLOCKS_IN_MCU]; +#endif + long mcurow, mcuindex, next_row; + int next_index; + JBLOCKARRAY rowptr = NULL; /* init only to suppress compiler complaint */ + + next_row = 0; + next_index = MCUs_in_big_row; + + for (mcurow = 0; mcurow < cinfo->MCU_rows_in_scan; mcurow++) { + for (mcuindex = 0; mcuindex < cinfo->MCUs_per_row; mcuindex++) { + if (next_index >= MCUs_in_big_row) { + rowptr = (*cinfo->emethods->access_big_barray) (whole_scan_MCUs, + next_row, FALSE); + next_row++; + next_index = 0; + } +#ifdef NEED_FAR_POINTERS + jcopy_block_row(rowptr[0] + next_index * cinfo->blocks_in_MCU, + (JBLOCKROW) MCU_data, /* note cast */ + (long) cinfo->blocks_in_MCU); + (*output_method) (cinfo, MCU_data); +#else + (*output_method) (cinfo, rowptr[0] + next_index * cinfo->blocks_in_MCU); +#endif + next_index++; + } + } +} + + + +/* + * Compression pipeline controller used for single-scan files + * with no optimization of entropy parameters. + */ + +METHODDEF void +single_ccontroller (compress_info_ptr cinfo) +{ + int rows_in_mem; /* # of sample rows in full-size buffers */ + long fullsize_width; /* # of samples per row in full-size buffers */ + long cur_pixel_row; /* counts # of pixel rows processed */ + long mcu_rows_output; /* # of MCU rows actually emitted */ + int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */ + /* Work buffer for pre-subsampling data (see comments at head of file) */ + JSAMPIMAGE fullsize_data[2]; + /* Work buffer for subsampled data */ + JSAMPIMAGE subsampled_data; + int rows_this_time; + short ci, whichss, i; + + /* Prepare for single scan containing all components */ + if (cinfo->num_components > MAX_COMPS_IN_SCAN) + ERREXIT(cinfo->emethods, "Too many components for interleaved scan"); + cinfo->comps_in_scan = cinfo->num_components; + for (ci = 0; ci < cinfo->num_components; ci++) { + cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci]; + } + if (cinfo->comps_in_scan == 1) { + noninterleaved_scan_setup(cinfo); + /* Vk block rows constitute the same number of MCU rows */ + mcu_rows_per_loop = cinfo->cur_comp_info[0]->v_samp_factor; + } else { + interleaved_scan_setup(cinfo); + /* in an interleaved scan, one MCU row contains Vk block rows */ + mcu_rows_per_loop = 1; + } + + /* Compute dimensions of full-size pixel buffers */ + /* Note these are the same whether interleaved or not. */ + rows_in_mem = cinfo->max_v_samp_factor * DCTSIZE; + fullsize_width = jround_up(cinfo->image_width, + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + + /* Allocate working memory: */ + /* fullsize_data is sample data before subsampling */ + alloc_sampling_buffer(cinfo, fullsize_data, fullsize_width); + /* subsampled_data is sample data after subsampling */ + subsampled_data = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(JSAMPARRAY)); + for (ci = 0; ci < cinfo->num_components; ci++) { + subsampled_data[ci] = (*cinfo->emethods->alloc_small_sarray) + (cinfo->comp_info[ci].subsampled_width, + (long) (cinfo->comp_info[ci].v_samp_factor * DCTSIZE)); + } + + /* Tell the memory manager to instantiate big arrays. + * We don't need any big arrays in this controller, + * but some other module (like the input file reader) may need one. + */ + (*cinfo->emethods->alloc_big_arrays) + ((long) 0, /* no more small sarrays */ + (long) 0, /* no more small barrays */ + (long) 0); /* no more "medium" objects */ + + /* Initialize output file & do per-scan object init */ + + (*cinfo->methods->write_scan_header) (cinfo); + cinfo->methods->entropy_output = cinfo->methods->write_jpeg_data; + (*cinfo->methods->entropy_encoder_init) (cinfo); + (*cinfo->methods->subsample_init) (cinfo); + (*cinfo->methods->extract_init) (cinfo); + + /* Loop over input image: rows_in_mem pixel rows are processed per loop */ + + mcu_rows_output = 0; + whichss = 1; /* arrange to start with fullsize_data[0] */ + + for (cur_pixel_row = 0; cur_pixel_row < cinfo->image_height; + cur_pixel_row += rows_in_mem) { + whichss ^= 1; /* switch to other fullsize_data buffer */ + + /* Obtain rows_this_time pixel rows and expand to rows_in_mem rows. */ + /* Then we have exactly DCTSIZE row groups for subsampling. */ + rows_this_time = MIN(rows_in_mem, cinfo->image_height - cur_pixel_row); + + (*cinfo->methods->get_sample_rows) (cinfo, rows_this_time, + fullsize_data[whichss]); + (*cinfo->methods->edge_expand) (cinfo, + cinfo->image_width, rows_this_time, + fullsize_width, rows_in_mem, + fullsize_data[whichss]); + + /* Subsample the data (all components) */ + /* First time through is a special case */ + + if (cur_pixel_row) { + /* Subsample last row group of previous set */ + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) DCTSIZE, (short) (DCTSIZE+1), (short) 0, + (short) (DCTSIZE-1)); + /* and dump the previous set's subsampled data */ + (*cinfo->methods->extract_MCUs) (cinfo, subsampled_data, + mcu_rows_per_loop, + cinfo->methods->entropy_encode); + mcu_rows_output += mcu_rows_per_loop; + /* Subsample first row group of this set */ + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) (DCTSIZE+1), (short) 0, (short) 1, + (short) 0); + } else { + /* Subsample first row group with dummy above-context */ + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) (-1), (short) 0, (short) 1, + (short) 0); + } + /* Subsample second through next-to-last row groups of this set */ + for (i = 1; i <= DCTSIZE-2; i++) { + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) (i-1), (short) i, (short) (i+1), + (short) i); + } + } /* end of outer loop */ + + /* Subsample the last row group with dummy below-context */ + /* Note whichss points to last buffer side used */ + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1), + (short) (DCTSIZE-1)); + /* Dump the remaining data (may be less than full height if uninterleaved) */ + (*cinfo->methods->extract_MCUs) (cinfo, subsampled_data, + (int) (cinfo->MCU_rows_in_scan - mcu_rows_output), + cinfo->methods->entropy_encode); + + /* Finish output file */ + (*cinfo->methods->extract_term) (cinfo); + (*cinfo->methods->subsample_term) (cinfo); + (*cinfo->methods->entropy_encoder_term) (cinfo); + (*cinfo->methods->write_scan_trailer) (cinfo); + + /* Release working memory */ + free_sampling_buffer(cinfo, fullsize_data); + for (ci = 0; ci < cinfo->num_components; ci++) { + (*cinfo->emethods->free_small_sarray) + (subsampled_data[ci], + (long) (cinfo->comp_info[ci].v_samp_factor * DCTSIZE)); + } + (*cinfo->emethods->free_small) ((void *) subsampled_data); +} + + +/* + * Compression pipeline controller used for single-scan files + * with optimization of entropy parameters. + */ + +#ifdef ENTROPY_OPT_SUPPORTED + +METHODDEF void +single_eopt_ccontroller (compress_info_ptr cinfo) +{ + int rows_in_mem; /* # of sample rows in full-size buffers */ + long fullsize_width; /* # of samples per row in full-size buffers */ + long cur_pixel_row; /* counts # of pixel rows processed */ + long mcu_rows_output; /* # of MCU rows actually emitted */ + int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */ + /* Work buffer for pre-subsampling data (see comments at head of file) */ + JSAMPIMAGE fullsize_data[2]; + /* Work buffer for subsampled data */ + JSAMPIMAGE subsampled_data; + int rows_this_time; + int blocks_in_big_row; + short ci, whichss, i; + + /* Prepare for single scan containing all components */ + if (cinfo->num_components > MAX_COMPS_IN_SCAN) + ERREXIT(cinfo->emethods, "Too many components for interleaved scan"); + cinfo->comps_in_scan = cinfo->num_components; + for (ci = 0; ci < cinfo->num_components; ci++) { + cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci]; + } + if (cinfo->comps_in_scan == 1) { + noninterleaved_scan_setup(cinfo); + /* Vk block rows constitute the same number of MCU rows */ + mcu_rows_per_loop = cinfo->cur_comp_info[0]->v_samp_factor; + } else { + interleaved_scan_setup(cinfo); + /* in an interleaved scan, one MCU row contains Vk block rows */ + mcu_rows_per_loop = 1; + } + + /* Compute dimensions of full-size pixel buffers */ + /* Note these are the same whether interleaved or not. */ + rows_in_mem = cinfo->max_v_samp_factor * DCTSIZE; + fullsize_width = jround_up(cinfo->image_width, + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + + /* Allocate working memory: */ + /* fullsize_data is sample data before subsampling */ + alloc_sampling_buffer(cinfo, fullsize_data, fullsize_width); + /* subsampled_data is sample data after subsampling */ + subsampled_data = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(JSAMPARRAY)); + for (ci = 0; ci < cinfo->num_components; ci++) { + subsampled_data[ci] = (*cinfo->emethods->alloc_small_sarray) + (cinfo->comp_info[ci].subsampled_width, + (long) (cinfo->comp_info[ci].v_samp_factor * DCTSIZE)); + } + + /* Figure # of MCUs to be packed in a row of whole_scan_MCUs */ + MCUs_in_big_row = MAX_WHOLE_ROW_BLOCKS / cinfo->blocks_in_MCU; + blocks_in_big_row = MCUs_in_big_row * cinfo->blocks_in_MCU; + + /* Request a big array: whole_scan_MCUs saves the MCU data for the scan */ + whole_scan_MCUs = (*cinfo->emethods->request_big_barray) + ((long) blocks_in_big_row, + (long) (cinfo->MCUs_per_row * cinfo->MCU_rows_in_scan + + MCUs_in_big_row-1) / MCUs_in_big_row, + 1L); /* unit height is 1 row */ + + next_whole_row = 0; /* init output ptr for MCU_output_catcher */ + next_MCU_index = MCUs_in_big_row; /* forces access on first call! */ + + /* Tell the memory manager to instantiate big arrays */ + (*cinfo->emethods->alloc_big_arrays) + ((long) 0, /* no more small sarrays */ + (long) 0, /* no more small barrays */ + (long) 0); /* no more "medium" objects */ + + /* Do per-scan object init */ + + (*cinfo->methods->subsample_init) (cinfo); + (*cinfo->methods->extract_init) (cinfo); + + /* Loop over input image: rows_in_mem pixel rows are processed per loop */ + /* MCU data goes into whole_scan_MCUs, not to the entropy encoder */ + + mcu_rows_output = 0; + whichss = 1; /* arrange to start with fullsize_data[0] */ + + for (cur_pixel_row = 0; cur_pixel_row < cinfo->image_height; + cur_pixel_row += rows_in_mem) { + whichss ^= 1; /* switch to other fullsize_data buffer */ + + /* Obtain rows_this_time pixel rows and expand to rows_in_mem rows. */ + /* Then we have exactly DCTSIZE row groups for subsampling. */ + rows_this_time = MIN(rows_in_mem, cinfo->image_height - cur_pixel_row); + + (*cinfo->methods->get_sample_rows) (cinfo, rows_this_time, + fullsize_data[whichss]); + (*cinfo->methods->edge_expand) (cinfo, + cinfo->image_width, rows_this_time, + fullsize_width, rows_in_mem, + fullsize_data[whichss]); + + /* Subsample the data (all components) */ + /* First time through is a special case */ + + if (cur_pixel_row) { + /* Subsample last row group of previous set */ + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) DCTSIZE, (short) (DCTSIZE+1), (short) 0, + (short) (DCTSIZE-1)); + /* and dump the previous set's subsampled data */ + (*cinfo->methods->extract_MCUs) (cinfo, subsampled_data, + mcu_rows_per_loop, + MCU_output_catcher); + mcu_rows_output += mcu_rows_per_loop; + /* Subsample first row group of this set */ + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) (DCTSIZE+1), (short) 0, (short) 1, + (short) 0); + } else { + /* Subsample first row group with dummy above-context */ + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) (-1), (short) 0, (short) 1, + (short) 0); + } + /* Subsample second through next-to-last row groups of this set */ + for (i = 1; i <= DCTSIZE-2; i++) { + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) (i-1), (short) i, (short) (i+1), + (short) i); + } + } /* end of outer loop */ + + /* Subsample the last row group with dummy below-context */ + /* Note whichss points to last buffer side used */ + subsample(cinfo, fullsize_data[whichss], subsampled_data, fullsize_width, + (short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1), + (short) (DCTSIZE-1)); + /* Dump the remaining data (may be less than full height if uninterleaved) */ + (*cinfo->methods->extract_MCUs) (cinfo, subsampled_data, + (int) (cinfo->MCU_rows_in_scan - mcu_rows_output), + MCU_output_catcher); + + /* Clean up after that stuff, then find the optimal entropy parameters */ + + (*cinfo->methods->extract_term) (cinfo); + (*cinfo->methods->subsample_term) (cinfo); + + (*cinfo->methods->entropy_optimize) (cinfo, dump_scan_MCUs); + + /* Emit scan to output file */ + /* Note: we can't do write_scan_header until entropy parameters are set! */ + + (*cinfo->methods->write_scan_header) (cinfo); + cinfo->methods->entropy_output = cinfo->methods->write_jpeg_data; + (*cinfo->methods->entropy_encoder_init) (cinfo); + dump_scan_MCUs(cinfo, cinfo->methods->entropy_encode); + (*cinfo->methods->entropy_encoder_term) (cinfo); + (*cinfo->methods->write_scan_trailer) (cinfo); + + /* Release working memory */ + free_sampling_buffer(cinfo, fullsize_data); + for (ci = 0; ci < cinfo->num_components; ci++) { + (*cinfo->emethods->free_small_sarray) + (subsampled_data[ci], + (long) (cinfo->comp_info[ci].v_samp_factor * DCTSIZE)); + } + (*cinfo->emethods->free_small) ((void *) subsampled_data); + (*cinfo->emethods->free_big_barray) (whole_scan_MCUs); +} + +#endif /* ENTROPY_OPT_SUPPORTED */ + + +/* + * Compression pipeline controller used for multiple-scan files + * with no optimization of entropy parameters. + */ + +#ifdef MULTISCAN_FILES_SUPPORTED + +METHODDEF void +multi_ccontroller (compress_info_ptr cinfo) +{ + ERREXIT(cinfo->emethods, "Not implemented yet"); +} + +#endif /* MULTISCAN_FILES_SUPPORTED */ + + +/* + * Compression pipeline controller used for multiple-scan files + * with optimization of entropy parameters. + */ + +#ifdef MULTISCAN_FILES_SUPPORTED +#ifdef ENTROPY_OPT_SUPPORTED + +METHODDEF void +multi_eopt_ccontroller (compress_info_ptr cinfo) +{ + ERREXIT(cinfo->emethods, "Not implemented yet"); +} + +#endif /* ENTROPY_OPT_SUPPORTED */ +#endif /* MULTISCAN_FILES_SUPPORTED */ + + +/* + * The method selection routine for compression pipeline controllers. + */ + +GLOBAL void +jselcpipeline (compress_info_ptr cinfo) +{ + if (cinfo->interleave || cinfo->num_components == 1) { + /* single scan needed */ +#ifdef ENTROPY_OPT_SUPPORTED + if (cinfo->optimize_coding) + cinfo->methods->c_pipeline_controller = single_eopt_ccontroller; + else +#endif + cinfo->methods->c_pipeline_controller = single_ccontroller; + } else { + /* multiple scans needed */ +#ifdef MULTISCAN_FILES_SUPPORTED +#ifdef ENTROPY_OPT_SUPPORTED + if (cinfo->optimize_coding) + cinfo->methods->c_pipeline_controller = multi_eopt_ccontroller; + else +#endif + cinfo->methods->c_pipeline_controller = multi_ccontroller; +#else + ERREXIT(cinfo->emethods, "Multiple-scan support was not compiled"); +#endif + } +} diff --git a/jcsample.c b/jcsample.c new file mode 100644 index 0000000..d23e23a --- /dev/null +++ b/jcsample.c @@ -0,0 +1,135 @@ +/* + * jcsample.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains subsampling routines. + * These routines are invoked via the subsample and + * subsample_init/term methods. + */ + +#include "jinclude.h" + + +/* + * Initialize for subsampling a scan. + */ + +METHODDEF void +subsample_init (compress_info_ptr cinfo) +{ + /* no work for now */ +} + + +/* + * Subsample pixel values of a single component. + * This version only handles integral sampling ratios. + */ + +METHODDEF void +subsample (compress_info_ptr cinfo, int which_component, + long input_cols, int input_rows, + long output_cols, int output_rows, + JSAMPARRAY above, JSAMPARRAY input_data, JSAMPARRAY below, + JSAMPARRAY output_data) +{ + jpeg_component_info * compptr = cinfo->cur_comp_info[which_component]; + int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v; + long outcol; + JSAMPROW inptr, outptr; + INT32 outvalue; + + /* TEMP FOR DEBUGGING PIPELINE CONTROLLER */ + if (output_rows != compptr->v_samp_factor || + input_rows != cinfo->max_v_samp_factor || + (output_cols % compptr->h_samp_factor) != 0 || + (input_cols % cinfo->max_h_samp_factor) != 0 || + input_cols*compptr->h_samp_factor != output_cols*cinfo->max_h_samp_factor) + ERREXIT(cinfo->emethods, "Bogus subsample parameters"); + + h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor; + v_expand = cinfo->max_v_samp_factor / compptr->v_samp_factor; + numpix = h_expand * v_expand; + numpix2 = numpix/2; + + inrow = 0; + for (outrow = 0; outrow < output_rows; outrow++) { + outptr = output_data[outrow]; + for (outcol = 0; outcol < output_cols; outcol++) { + outvalue = 0; + for (v = 0; v < v_expand; v++) { + inptr = input_data[inrow+v] + (outcol*h_expand); + for (h = 0; h < h_expand; h++) { + outvalue += GETJSAMPLE(*inptr++); + } + } + *outptr++ = (outvalue + numpix2) / numpix; + } + inrow += v_expand; + } +} + + +/* + * Subsample pixel values of a single component. + * This version handles the special case of a full-size component. + */ + +METHODDEF void +fullsize_subsample (compress_info_ptr cinfo, int which_component, + long input_cols, int input_rows, + long output_cols, int output_rows, + JSAMPARRAY above, JSAMPARRAY input_data, JSAMPARRAY below, + JSAMPARRAY output_data) +{ + if (input_cols != output_cols || input_rows != output_rows) /* DEBUG */ + ERREXIT(cinfo->emethods, "Pipeline controller messed up"); + + jcopy_sample_rows(input_data, 0, output_data, 0, output_rows, output_cols); +} + + +/* + * Clean up after a scan. + */ + +METHODDEF void +subsample_term (compress_info_ptr cinfo) +{ + /* no work for now */ +} + + + +/* + * The method selection routine for subsampling. + * Note that we must select a routine for each component. + */ + +GLOBAL void +jselsubsample (compress_info_ptr cinfo) +{ + short ci; + jpeg_component_info * compptr; + + if (cinfo->CCIR601_sampling) + ERREXIT(cinfo->emethods, "CCIR601 subsampling not implemented yet"); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + if (compptr->h_samp_factor == cinfo->max_h_samp_factor && + compptr->v_samp_factor == cinfo->max_v_samp_factor) + cinfo->methods->subsample[ci] = fullsize_subsample; + else if ((cinfo->max_h_samp_factor % compptr->h_samp_factor) == 0 && + (cinfo->max_v_samp_factor % compptr->v_samp_factor) == 0) + cinfo->methods->subsample[ci] = subsample; + else + ERREXIT(cinfo->emethods, "Fractional subsampling not implemented yet"); + } + + cinfo->methods->subsample_init = subsample_init; + cinfo->methods->subsample_term = subsample_term; +} diff --git a/jdarith.c b/jdarith.c new file mode 100644 index 0000000..0f19be8 --- /dev/null +++ b/jdarith.c @@ -0,0 +1,42 @@ +/* + * jdarith.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains arithmetic entropy decoding routines. + * These routines are invoked via the methods entropy_decode + * and entropy_decoder_init/term. + */ + +#include "jinclude.h" + +#ifdef ARITH_CODING_SUPPORTED + + +/* + * The arithmetic coding option of the JPEG standard specifies Q-coding, + * which is covered by patents held by IBM (and possibly AT&T and Mitsubishi). + * At this time it does not appear to be legal for the Independent JPEG + * Group to distribute software that implements arithmetic coding. + * We have therefore removed arithmetic coding support from the + * distributed source code. + * + * We're not happy about it either. + */ + + +/* + * The method selection routine for arithmetic entropy decoding. + */ + +GLOBAL void +jseldarithmetic (decompress_info_ptr cinfo) +{ + if (cinfo->arith_code) { + ERREXIT(cinfo->emethods, "Sorry, there are legal restrictions on arithmetic coding"); + } +} + +#endif /* ARITH_CODING_SUPPORTED */ diff --git a/jdcolor.c b/jdcolor.c new file mode 100644 index 0000000..a39ebff --- /dev/null +++ b/jdcolor.c @@ -0,0 +1,194 @@ +/* + * jdcolor.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains output colorspace conversion routines. + * These routines are invoked via the methods color_convert + * and colorout_init/term. + */ + +#include "jinclude.h" + + +/* + * Initialize for colorspace conversion. + */ + +METHODDEF void +colorout_init (decompress_info_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * Convert some rows of samples to the output colorspace. + * This version handles YCbCr -> RGB conversion. + * YCbCr is defined per CCIR 601-1, except that Cb and Cr are + * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + */ + +METHODDEF void +ycc_rgb_convert (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE input_data, JSAMPIMAGE output_data) +{ + register INT32 y, u, v, x; + register JSAMPROW inptr0, inptr1, inptr2; + register JSAMPROW outptr0, outptr1, outptr2; + register long col; + register long width = cinfo->image_width; + register int row; + + for (row = 0; row < num_rows; row++) { + inptr0 = input_data[0][row]; + inptr1 = input_data[1][row]; + inptr2 = input_data[2][row]; + outptr0 = output_data[0][row]; + outptr1 = output_data[1][row]; + outptr2 = output_data[2][row]; + for (col = width; col > 0; col--) { + y = GETJSAMPLE(*inptr0++); + u = (int) GETJSAMPLE(*inptr1++) - CENTERJSAMPLE; + v = (int) GETJSAMPLE(*inptr2++) - CENTERJSAMPLE; + /* Note: if the inputs were computed directly from RGB values, + * range-limiting would be unnecessary here; but due to possible + * noise in the DCT/IDCT phase, we do need to apply range limits. + */ + y *= 1024; /* in case compiler can't spot common subexpression */ + x = y + 1436*v + 512; /* red */ + if (x < 0) x = 0; + if (x > ((INT32) MAXJSAMPLE*1024)) x = (INT32) MAXJSAMPLE*1024; + *outptr0++ = x >> 10; + x = y - 352*u - 731*v + 512; /* green */ + if (x < 0) x = 0; + if (x > ((INT32) MAXJSAMPLE*1024)) x = (INT32) MAXJSAMPLE*1024; + *outptr1++ = x >> 10; + x = y + 1815*u + 512; /* blue */ + if (x < 0) x = 0; + if (x > ((INT32) MAXJSAMPLE*1024)) x = (INT32) MAXJSAMPLE*1024; + *outptr2++ = x >> 10; + } + } +} + + +/* + * Color conversion for no colorspace change: just copy the data. + */ + +METHODDEF void +null_convert (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE input_data, JSAMPIMAGE output_data) +{ + short ci; + + for (ci = 0; ci < cinfo->num_components; ci++) { + jcopy_sample_rows(input_data[ci], 0, output_data[ci], 0, + num_rows, cinfo->image_width); + } +} + + +/* + * Color conversion for grayscale: just copy the data. + * This also works for YCbCr/YIQ -> grayscale conversion, in which + * we just copy the Y (luminance) component and ignore chrominance. + */ + +METHODDEF void +grayscale_convert (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE input_data, JSAMPIMAGE output_data) +{ + jcopy_sample_rows(input_data[0], 0, output_data[0], 0, + num_rows, cinfo->image_width); +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +colorout_term (decompress_info_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * The method selection routine for output colorspace conversion. + */ + +GLOBAL void +jseldcolor (decompress_info_ptr cinfo) +{ + /* Make sure num_components agrees with jpeg_color_space */ + switch (cinfo->jpeg_color_space) { + case CS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo->emethods, "Bogus JPEG colorspace"); + break; + + case CS_RGB: + case CS_YIQ: + case CS_YCbCr: + if (cinfo->num_components != 3) + ERREXIT(cinfo->emethods, "Bogus JPEG colorspace"); + break; + + case CS_CMYK: + if (cinfo->num_components != 4) + ERREXIT(cinfo->emethods, "Bogus JPEG colorspace"); + break; + + default: + ERREXIT(cinfo->emethods, "Unsupported JPEG colorspace"); + break; + } + + /* Set color_out_comps and conversion method based on requested space */ + switch (cinfo->out_color_space) { + case CS_GRAYSCALE: + cinfo->color_out_comps = 1; + if (cinfo->jpeg_color_space == CS_GRAYSCALE || + cinfo->jpeg_color_space == CS_YCbCr || + cinfo->jpeg_color_space == CS_YIQ) + cinfo->methods->color_convert = grayscale_convert; + else + ERREXIT(cinfo->emethods, "Unsupported color conversion request"); + break; + + case CS_RGB: + cinfo->color_out_comps = 3; + if (cinfo->jpeg_color_space == CS_YCbCr) + cinfo->methods->color_convert = ycc_rgb_convert; + else if (cinfo->jpeg_color_space == CS_RGB) + cinfo->methods->color_convert = null_convert; + else + ERREXIT(cinfo->emethods, "Unsupported color conversion request"); + break; + + case CS_CMYK: + cinfo->color_out_comps = 4; + if (cinfo->jpeg_color_space == CS_CMYK) + cinfo->methods->color_convert = null_convert; + else + ERREXIT(cinfo->emethods, "Unsupported color conversion request"); + break; + + default: + ERREXIT(cinfo->emethods, "Unsupported output colorspace"); + break; + } + + if (cinfo->quantize_colors) + cinfo->final_out_comps = 1; /* single colormapped output component */ + else + cinfo->final_out_comps = cinfo->color_out_comps; + + cinfo->methods->colorout_init = colorout_init; + cinfo->methods->colorout_term = colorout_term; +} diff --git a/jdhuff.c b/jdhuff.c new file mode 100644 index 0000000..e9af688 --- /dev/null +++ b/jdhuff.c @@ -0,0 +1,318 @@ +/* + * jdhuff.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines. + * These routines are invoked via the methods entropy_decode + * and entropy_decoder_init/term. + */ + +#include "jinclude.h" + + +/* Static variables to avoid passing 'round extra parameters */ + +static decompress_info_ptr dcinfo; + +static unsigned int get_buffer; /* current bit-extraction buffer */ +static int bits_left; /* # of unused bits in it */ + + +LOCAL void +fix_huff_tbl (HUFF_TBL * htbl) +/* Compute derived values for a Huffman table */ +{ + int p, i, l, lastp, si; + char huffsize[257]; + UINT16 huffcode[257]; + UINT16 code; + + /* Figure 7.3.5.4.2.1: make table of Huffman code length for each symbol */ + /* Note that this is in code-length order. */ + + p = 0; + for (l = 1; l <= 16; l++) { + for (i = 1; i <= htbl->bits[l]; i++) + huffsize[p++] = l; + } + huffsize[p] = 0; + lastp = p; + + /* Figure 7.3.5.4.2.2: generate the codes themselves */ + /* Note that this is in code-length order. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (huffsize[p] == si) { + huffcode[p++] = code; + code++; + } + code <<= 1; + si++; + } + + /* Figure 7.3.5.4.2.3: generate encoding tables */ + /* These are code and size indexed by symbol value */ + + for (p = 0; p < lastp; p++) { + htbl->ehufco[htbl->huffval[p]] = huffcode[p]; + htbl->ehufsi[htbl->huffval[p]] = huffsize[p]; + } + + /* Figure 13.4.2.3.1: generate decoding tables */ + + p = 0; + for (l = 1; l <= 16; l++) { + if (htbl->bits[l]) { + htbl->valptr[l] = p; /* huffval[] index of 1st sym of code len l */ + htbl->mincode[l] = huffcode[p]; /* minimum code of length l */ + p += htbl->bits[l]; + htbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */ + } else { + htbl->maxcode[l] = -1; + } + } +} + + +/* Extract the next N bits from the input stream (N <= 8) */ + +LOCAL int +get_bits (int nbits) +{ + int result; + + while (nbits > bits_left) { + int c = JGETC(dcinfo); + + get_buffer = (get_buffer << 8) + c; + bits_left += 8; + /* If it's 0xFF, check and discard stuffed zero byte */ + if (c == 0xff) { + c = JGETC(dcinfo); /* Byte stuffing */ + if (c != 0) + ERREXIT1(dcinfo->emethods, + "Unexpected marker 0x%02x in compressed data", c); + } + } + + bits_left -= nbits; + result = (get_buffer >> bits_left) & ((1 << nbits) - 1); + return result; +} + +/* Macro to make things go at some speed! */ + +#define get_bit() (bits_left ? \ + ((get_buffer >> (--bits_left)) & 1) : \ + get_bits(1)) + + +/* Figure 13.4.2.3.2: extract next coded symbol from input stream */ + +LOCAL int +huff_DECODE (HUFF_TBL * htbl) +{ + int l, p; + INT32 code; + + code = get_bit(); + l = 1; + while (code > htbl->maxcode[l]) { + code = (code << 1) + get_bit(); + l++; + } + + p = htbl->valptr[l] + (code - htbl->mincode[l]); + + return htbl->huffval[p]; +} + + +/* Figure 13.4.2.1.1: extend sign bit */ + +#define huff_EXTEND(x, s) ((x) < (1 << ((s)-1)) ? \ + (x) + (-1 << (s)) + 1 : \ + (x)) + + +/* Decode a single block's worth of coefficients */ +/* Note that only the difference is returned for the DC coefficient */ + +LOCAL void +decode_one_block (JBLOCK block, HUFF_TBL *dctbl, HUFF_TBL *actbl) +{ + int s, k, r, n; + + /* zero out the coefficient block */ + + MEMZERO((void *) block, SIZEOF(JBLOCK)); + + /* Section 13.4.2.1: decode the DC coefficient difference */ + + s = huff_DECODE(dctbl); + r = get_bits(s); + block[0] = huff_EXTEND(r, s); + + /* Section 13.4.2.2: decode the AC coefficients */ + + for (k = 1; k < DCTSIZE2; k++) { + r = huff_DECODE(actbl); + + s = r & 15; + n = r >> 4; + + if (s) { + k = k + n; + r = get_bits(s); + block[k] = huff_EXTEND(r, s); + } else { + if (n != 15) + break; + k += 15; + } + } +} + + +/* + * Initialize for a Huffman-compressed scan. + * This is invoked after reading the SOS marker. + */ + +METHODDEF void +huff_decoder_init (decompress_info_ptr cinfo) +{ + short ci; + jpeg_component_info * compptr; + + /* Initialize static variables */ + dcinfo = cinfo; + bits_left = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Make sure requested tables are present */ + if (cinfo->dc_huff_tbl_ptrs[compptr->dc_tbl_no] == NULL || + cinfo->ac_huff_tbl_ptrs[compptr->ac_tbl_no] == NULL) + ERREXIT(cinfo->emethods, "Use of undefined Huffman table"); + /* Compute derived values for Huffman tables */ + /* We may do this more than once for same table, but it's not a big deal */ + fix_huff_tbl(cinfo->dc_huff_tbl_ptrs[compptr->dc_tbl_no]); + fix_huff_tbl(cinfo->ac_huff_tbl_ptrs[compptr->ac_tbl_no]); + /* Initialize DC predictions to 0 */ + cinfo->last_dc_val[ci] = 0; + } + + /* Initialize restart stuff */ + cinfo->restarts_to_go = cinfo->restart_interval; + cinfo->next_restart_num = 0; +} + + +/* + * Check for a restart marker & resynchronize decoder. + */ + +LOCAL void +process_restart (decompress_info_ptr cinfo) +{ + int c, nbytes; + short ci; + + /* Throw away any partial unread byte */ + bits_left = 0; + + /* Scan for next JPEG marker */ + nbytes = 0; + do { + do { /* skip any non-FF bytes */ + nbytes++; + c = JGETC(cinfo); + } while (c != 0xFF); + do { /* skip any duplicate FFs */ + nbytes++; + c = JGETC(cinfo); + } while (c == 0xFF); + } while (c == 0); /* repeat if it was a stuffed FF/00 */ + + if (c != (RST0 + cinfo->next_restart_num)) + ERREXIT2(cinfo->emethods, "Found 0x%02x marker instead of RST%d", + c, cinfo->next_restart_num); + + if (nbytes != 2) + TRACEMS2(cinfo->emethods, 1, "Skipped %d bytes before RST%d", + nbytes-2, cinfo->next_restart_num); + else + TRACEMS1(cinfo->emethods, 2, "RST%d", cinfo->next_restart_num); + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + cinfo->last_dc_val[ci] = 0; + + /* Update restart state */ + cinfo->restarts_to_go = cinfo->restart_interval; + cinfo->next_restart_num++; + cinfo->next_restart_num &= 7; +} + + +/* + * Decode and return one MCU's worth of Huffman-compressed coefficients. + */ + +METHODDEF void +huff_decode (decompress_info_ptr cinfo, JBLOCK *MCU_data) +{ + short blkn, ci; + jpeg_component_info * compptr; + + /* Account for restart interval, process restart marker if needed */ + if (cinfo->restart_interval) { + if (cinfo->restarts_to_go == 0) + process_restart(cinfo); + cinfo->restarts_to_go--; + } + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + decode_one_block(MCU_data[blkn], + cinfo->dc_huff_tbl_ptrs[compptr->dc_tbl_no], + cinfo->ac_huff_tbl_ptrs[compptr->ac_tbl_no]); + /* Convert DC difference to actual value, update last_dc_val */ + MCU_data[blkn][0] += cinfo->last_dc_val[ci]; + cinfo->last_dc_val[ci] = MCU_data[blkn][0]; + } +} + + +/* + * Finish up at the end of a Huffman-compressed scan. + */ + +METHODDEF void +huff_decoder_term (decompress_info_ptr cinfo) +{ + /* No work needed */ +} + + +/* + * The method selection routine for Huffman entropy decoding. + */ + +GLOBAL void +jseldhuffman (decompress_info_ptr cinfo) +{ + if (! cinfo->arith_code) { + cinfo->methods->entropy_decoder_init = huff_decoder_init; + cinfo->methods->entropy_decode = huff_decode; + cinfo->methods->entropy_decoder_term = huff_decoder_term; + } +} diff --git a/jdmain.c b/jdmain.c new file mode 100644 index 0000000..109d124 --- /dev/null +++ b/jdmain.c @@ -0,0 +1,289 @@ +/* + * jdmain.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a trivial test user interface for the JPEG decompressor. + * It should work on any system with Unix- or MS-DOS-style command lines. + * + * Two different command line styles are permitted, depending on the + * compile-time switch TWO_FILE_COMMANDLINE: + * djpeg [options] inputfile outputfile + * djpeg [options] [inputfile] + * In the second style, output is always to standard output, which you'd + * normally redirect to a file or pipe to some other program. Input is + * either from a named file or from standard input (typically redirected). + * The second style is convenient on Unix but is unhelpful on systems that + * don't support pipes. Also, you MUST use the first style if your system + * doesn't do binary I/O to stdin/stdout. + */ + +#include "jinclude.h" +#ifdef __STDC__ +#include /* to declare exit() */ +#endif + +#ifdef THINK_C +#include /* command-line reader for Macintosh */ +#endif + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define WRITE_BINARY "w" +#else +#define READ_BINARY "rb" +#define WRITE_BINARY "wb" +#endif + + +/* + * If your system has getopt(3), you can use your library version by + * defining HAVE_GETOPT. By default, we use the PD 'egetopt'. + */ + +#ifdef HAVE_GETOPT +extern int getopt PP((int argc, char **argv, char *optstring)); +extern char * optarg; +extern int optind; +#else +#include "egetopt.c" +#define getopt(argc,argv,opt) egetopt(argc,argv,opt) +#endif + + +typedef enum { /* defines known output image formats */ + FMT_PPM, /* PPM/PGM (PBMPLUS formats) */ + FMT_GIF, /* GIF format */ + FMT_TIFF /* TIFF format */ +} IMAGE_FORMATS; + +static IMAGE_FORMATS requested_fmt; + + +/* + * This routine gets control after the input file header has been read. + * It must determine what output file format is to be written, + * and make any other decompression parameter changes that are desirable. + */ + +METHODDEF void +d_ui_method_selection (decompress_info_ptr cinfo) +{ + /* if grayscale or CMYK input, force similar output; */ + /* else leave the output colorspace as set by options. */ + if (cinfo->jpeg_color_space == CS_GRAYSCALE) + cinfo->out_color_space = CS_GRAYSCALE; + else if (cinfo->jpeg_color_space == CS_CMYK) + cinfo->out_color_space = CS_CMYK; + + /* select output file format */ + /* Note: jselwxxx routine may make additional parameter changes, + * such as forcing color quantization if it's a colormapped format. + */ + switch (requested_fmt) { +#ifdef GIF_SUPPORTED + case FMT_GIF: + jselwgif(cinfo); + break; +#endif +#ifdef PPM_SUPPORTED + case FMT_PPM: + jselwppm(cinfo); + break; +#endif + default: + ERREXIT(cinfo->emethods, "Unsupported output file format"); + break; + } +} + + +/* + * Reload the input buffer after it's been emptied, and return the next byte. + * See the JGETC macro for calling conditions. + * + * This routine would need to be replaced if reading JPEG data from something + * other than a stdio stream. + */ + +METHODDEF int +read_jpeg_data (decompress_info_ptr cinfo) +{ + cinfo->bytes_in_buffer = fread(cinfo->input_buffer + MIN_UNGET, + 1, JPEG_BUF_SIZE, + cinfo->input_file); + + cinfo->next_input_byte = cinfo->input_buffer + MIN_UNGET; + + if (cinfo->bytes_in_buffer <= 0) + ERREXIT(cinfo->emethods, "Unexpected EOF in JPEG file"); + + return JGETC(cinfo); +} + + + +LOCAL void +usage (char * progname) +/* complain about bad command line */ +{ + fprintf(stderr, "usage: %s ", progname); + fprintf(stderr, "[-b] [-q colors] [-2] [-d] [-g] [-G]"); +#ifdef TWO_FILE_COMMANDLINE + fprintf(stderr, " inputfile outputfile\n"); +#else + fprintf(stderr, " [inputfile]\n"); +#endif + exit(2); +} + + +/* + * The main program. + */ + +GLOBAL void +main (int argc, char **argv) +{ + struct decompress_info_struct cinfo; + struct decompress_methods_struct dc_methods; + struct external_methods_struct e_methods; + int c; + + /* On Mac, fetch a command line. */ +#ifdef THINK_C + argc = ccommand(&argv); +#endif + + /* Initialize the system-dependent method pointers. */ + cinfo.methods = &dc_methods; + cinfo.emethods = &e_methods; + jselerror(&e_methods); /* error/trace message routines */ + jselvirtmem(&e_methods); /* memory allocation routines */ + dc_methods.d_ui_method_selection = d_ui_method_selection; + dc_methods.read_jpeg_data = read_jpeg_data; + + /* Allocate memory for input buffer. */ + cinfo.input_buffer = (char *) (*cinfo.emethods->alloc_small) + ((size_t) (JPEG_BUF_SIZE + MIN_UNGET)); + cinfo.bytes_in_buffer = 0; /* initialize buffer to empty */ + + /* Set up default input and output file references. */ + /* (These may be overridden below.) */ + cinfo.input_file = stdin; + cinfo.output_file = stdout; + + /* Set up default parameters. */ + e_methods.trace_level = 0; + cinfo.output_gamma = 1.0; + cinfo.quantize_colors = FALSE; + cinfo.two_pass_quantize = FALSE; + cinfo.use_dithering = FALSE; + cinfo.desired_number_of_colors = 256; + cinfo.do_block_smoothing = FALSE; + cinfo.do_pixel_smoothing = FALSE; + cinfo.out_color_space = CS_RGB; + cinfo.jpeg_color_space = CS_UNKNOWN; + /* setting any other value in jpeg_color_space overrides heuristics */ + /* in jrdjfif.c ... */ + /* You may wanta change the default output format; here's the place: */ +#ifdef PPM_SUPPORTED + requested_fmt = FMT_PPM; +#else + requested_fmt = FMT_GIF; +#endif + + /* Scan parameters */ + + while ((c = getopt(argc, argv, "bq:2DdgG")) != EOF) + switch (c) { + case 'b': /* Enable cross-block smoothing. */ + cinfo.do_block_smoothing = TRUE; + break; + case 'q': /* Do color quantization. */ + { int val; + if (optarg == NULL) + usage(argv[0]); + if (sscanf(optarg, "%d", &val) != 1) + usage(argv[0]); + cinfo.desired_number_of_colors = val; + } + cinfo.quantize_colors = TRUE; + break; + case '2': /* Use two-pass quantization. */ + cinfo.two_pass_quantize = TRUE; + break; + case 'D': /* Use dithering in color quantization. */ + cinfo.use_dithering = TRUE; + break; + case 'd': /* Debugging. */ + e_methods.trace_level++; + break; + case 'g': /* Force grayscale output. */ + cinfo.out_color_space = CS_GRAYSCALE; + break; + case 'G': /* GIF output format. */ + requested_fmt = FMT_GIF; + break; + case '?': + default: + usage(argv[0]); + break; + } + + /* Select the input and output files */ + +#ifdef TWO_FILE_COMMANDLINE + + if (optind != argc-2) { + fprintf(stderr, "%s: must name one input and one output file\n", argv[0]); + usage(argv[0]); + } + if ((cinfo.input_file = fopen(argv[optind], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", argv[0], argv[optind]); + exit(2); + } + if ((cinfo.output_file = fopen(argv[optind+1], WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", argv[0], argv[optind+1]); + exit(2); + } + +#else /* not TWO_FILE_COMMANDLINE -- use Unix style */ + + if (optind < argc-1) { + fprintf(stderr, "%s: only one input file\n", argv[0]); + usage(argv[0]); + } + if (optind < argc) { + if ((cinfo.input_file = fopen(argv[optind], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", argv[0], argv[optind]); + exit(2); + } + } + +#endif /* TWO_FILE_COMMANDLINE */ + + /* Set up to read a JFIF or baseline-JPEG file. */ + /* A smarter UI would inspect the first few bytes of the input file */ + /* to determine its type. */ +#ifdef JFIF_SUPPORTED + jselrjfif(&cinfo); +#else + You shoulda defined JFIF_SUPPORTED. /* deliberate syntax error */ +#endif + + /* Do it to it! */ + jpeg_decompress(&cinfo); + + /* Release memory. */ + (*cinfo.emethods->free_small) ((void *) cinfo.input_buffer); +#ifdef MEM_STATS + if (e_methods.trace_level > 0) + j_mem_stats(); +#endif + + /* All done. */ + exit(0); +} diff --git a/jdmaster.c b/jdmaster.c new file mode 100644 index 0000000..5693882 --- /dev/null +++ b/jdmaster.c @@ -0,0 +1,180 @@ +/* + * jdmaster.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main control for the JPEG decompressor. + * The system-dependent (user interface) code should call jpeg_decompress() + * after doing appropriate setup of the decompress_info_struct parameter. + */ + +#include "jinclude.h" + + +METHODDEF void +d_per_scan_method_selection (decompress_info_ptr cinfo) +/* Central point for per-scan method selection */ +{ + /* MCU disassembly */ + jseldmcu(cinfo); + /* Un-subsampling of pixels */ + jselunsubsample(cinfo); +} + + +LOCAL void +d_initial_method_selection (decompress_info_ptr cinfo) +/* Central point for initial method selection (after reading file header) */ +{ + /* JPEG file scanning method selection is already done. */ + /* So is output file format selection (both are done by user interface). */ + + /* Entropy decoding: either Huffman or arithmetic coding. */ +#ifdef ARITH_CODING_SUPPORTED + jseldarithmetic(cinfo); +#else + if (cinfo->arith_code) { + ERREXIT(cinfo->emethods, "Arithmetic coding not supported"); + } +#endif + jseldhuffman(cinfo); + /* Cross-block smoothing */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + jselbsmooth(cinfo); +#else + cinfo->do_block_smoothing = FALSE; +#endif + /* Gamma and color space conversion */ + jseldcolor(cinfo); + + /* Color quantization */ +#ifdef QUANT_1PASS_SUPPORTED +#ifndef QUANT_2PASS_SUPPORTED + cinfo->two_pass_quantize = FALSE; /* only have 1-pass */ +#endif +#else /* not QUANT_1PASS_SUPPORTED */ +#ifdef QUANT_2PASS_SUPPORTED + cinfo->two_pass_quantize = TRUE; /* only have 2-pass */ +#else /* not QUANT_2PASS_SUPPORTED */ + if (cinfo->quantize_colors) { + ERREXIT(cinfo->emethods, "Color quantization was not compiled"); + } +#endif +#endif + +#ifdef QUANT_1PASS_SUPPORTED + jsel1quantize(cinfo); +#endif +#ifdef QUANT_2PASS_SUPPORTED + jsel2quantize(cinfo); +#endif + + /* Pipeline control */ + jseldpipeline(cinfo); + /* Overall control (that's me!) */ + cinfo->methods->d_per_scan_method_selection = d_per_scan_method_selection; +} + + +LOCAL void +initial_setup (decompress_info_ptr cinfo) +/* Do computations that are needed before initial method selection */ +{ + short ci; + jpeg_component_info *compptr; + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0; ci < cinfo->num_components; ci++) { + compptr = &cinfo->comp_info[ci]; + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo->emethods, "Bogus sampling factors"); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + + } + + /* Compute logical subsampled dimensions of components */ + for (ci = 0; ci < cinfo->num_components; ci++) { + compptr = &cinfo->comp_info[ci]; + compptr->true_comp_width = (cinfo->image_width * compptr->h_samp_factor + + cinfo->max_h_samp_factor - 1) + / cinfo->max_h_samp_factor; + compptr->true_comp_height = (cinfo->image_height * compptr->v_samp_factor + + cinfo->max_v_samp_factor - 1) + / cinfo->max_v_samp_factor; + } +} + + +/* + * This is the main entry point to the JPEG decompressor. + */ + + +GLOBAL void +jpeg_decompress (decompress_info_ptr cinfo) +{ + short i; + + /* Initialize pointers as needed to mark stuff unallocated. */ + cinfo->comp_info = NULL; + for (i = 0; i < NUM_QUANT_TBLS; i++) + cinfo->quant_tbl_ptrs[i] = NULL; + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + /* Read the JPEG file header markers; everything up through the first SOS + * marker is read now. NOTE: the user interface must have initialized the + * read_file_header method pointer (eg, by calling jselrjfif or jselrtiff). + * The other file reading methods (read_scan_header etc.) were probably + * set at the same time, but could be set up by read_file_header itself. + */ + (*cinfo->methods->read_file_header) (cinfo); + if (! ((*cinfo->methods->read_scan_header) (cinfo))) + ERREXIT(cinfo->emethods, "Empty JPEG file"); + + /* Give UI a chance to adjust decompression parameters and select */ + /* output file format based on info from file header. */ + (*cinfo->methods->d_ui_method_selection) (cinfo); + + /* Now select methods for decompression steps. */ + initial_setup(cinfo); + d_initial_method_selection(cinfo); + + /* Initialize the output file & other modules as needed */ + /* (color_quant and entropy_decoder are inited by pipeline controller) */ + + (*cinfo->methods->output_init) (cinfo); + (*cinfo->methods->colorout_init) (cinfo); + + /* And let the pipeline controller do the rest. */ + (*cinfo->methods->d_pipeline_controller) (cinfo); + + /* Finish output file, release working storage, etc */ + (*cinfo->methods->colorout_term) (cinfo); + (*cinfo->methods->output_term) (cinfo); + (*cinfo->methods->read_file_trailer) (cinfo); + + /* Release allocated storage for tables */ +#define FREE(ptr) if ((ptr) != NULL) \ + (*cinfo->emethods->free_small) ((void *) ptr) + + FREE(cinfo->comp_info); + for (i = 0; i < NUM_QUANT_TBLS; i++) + FREE(cinfo->quant_tbl_ptrs[i]); + for (i = 0; i < NUM_HUFF_TBLS; i++) { + FREE(cinfo->dc_huff_tbl_ptrs[i]); + FREE(cinfo->ac_huff_tbl_ptrs[i]); + } + + /* My, that was easy, wasn't it? */ +} diff --git a/jdmcu.c b/jdmcu.c new file mode 100644 index 0000000..0d99170 --- /dev/null +++ b/jdmcu.c @@ -0,0 +1,146 @@ +/* + * jdmcu.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains MCU disassembly routines and quantization descaling. + * These routines are invoked via the disassemble_MCU and + * disassemble_init/term methods. + */ + +#include "jinclude.h" + + +/* + * Quantization descaling and zigzag reordering + */ + + +/* ZAG[i] is the natural-order position of the i'th element of zigzag order. */ + +static const short ZAG[DCTSIZE2] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + + +LOCAL void +qdescale_zig (JBLOCK input, JBLOCKROW outputptr, QUANT_TBL_PTR quanttbl) +{ + short i; + + for (i = 0; i < DCTSIZE2; i++) { + (*outputptr)[ZAG[i]] = (*input++) * (*quanttbl++); + } +} + + + +/* + * Fetch one MCU row from entropy_decode, build coefficient array. + * This version is used for noninterleaved (single-component) scans. + */ + +METHODDEF void +disassemble_noninterleaved_MCU (decompress_info_ptr cinfo, + JBLOCKIMAGE image_data) +{ + JBLOCK MCU_data[1]; + long mcuindex; + jpeg_component_info * compptr; + QUANT_TBL_PTR quant_ptr; + + /* this is pretty easy since there is one component and one block per MCU */ + compptr = cinfo->cur_comp_info[0]; + quant_ptr = cinfo->quant_tbl_ptrs[compptr->quant_tbl_no]; + for (mcuindex = 0; mcuindex < cinfo->MCUs_per_row; mcuindex++) { + /* Fetch the coefficient data */ + (*cinfo->methods->entropy_decode) (cinfo, MCU_data); + /* Descale, reorder, and distribute it into the image array */ + qdescale_zig(MCU_data[0], image_data[0][0] + mcuindex, quant_ptr); + } +} + + +/* + * Fetch one MCU row from entropy_decode, build coefficient array. + * This version is used for interleaved (multi-component) scans. + */ + +METHODDEF void +disassemble_interleaved_MCU (decompress_info_ptr cinfo, + JBLOCKIMAGE image_data) +{ + JBLOCK MCU_data[MAX_BLOCKS_IN_MCU]; + long mcuindex; + short blkn, ci, xpos, ypos; + jpeg_component_info * compptr; + QUANT_TBL_PTR quant_ptr; + JBLOCKROW image_ptr; + + for (mcuindex = 0; mcuindex < cinfo->MCUs_per_row; mcuindex++) { + /* Fetch the coefficient data */ + (*cinfo->methods->entropy_decode) (cinfo, MCU_data); + /* Descale, reorder, and distribute it into the image array */ + blkn = 0; + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + quant_ptr = cinfo->quant_tbl_ptrs[compptr->quant_tbl_no]; + for (ypos = 0; ypos < compptr->MCU_height; ypos++) { + image_ptr = image_data[ci][ypos] + (mcuindex * compptr->MCU_width); + for (xpos = 0; xpos < compptr->MCU_width; xpos++) { + qdescale_zig(MCU_data[blkn], image_ptr, quant_ptr); + image_ptr++; + blkn++; + } + } + } + } +} + + +/* + * Initialize for processing a scan. + */ + +METHODDEF void +disassemble_init (decompress_info_ptr cinfo) +{ + /* no work for now */ +} + + +/* + * Clean up after a scan. + */ + +METHODDEF void +disassemble_term (decompress_info_ptr cinfo) +{ + /* no work for now */ +} + + + +/* + * The method selection routine for MCU disassembly. + */ + +GLOBAL void +jseldmcu (decompress_info_ptr cinfo) +{ + if (cinfo->comps_in_scan == 1) + cinfo->methods->disassemble_MCU = disassemble_noninterleaved_MCU; + else + cinfo->methods->disassemble_MCU = disassemble_interleaved_MCU; + cinfo->methods->disassemble_init = disassemble_init; + cinfo->methods->disassemble_term = disassemble_term; +} diff --git a/jdpipe.c b/jdpipe.c new file mode 100644 index 0000000..8e08874 --- /dev/null +++ b/jdpipe.c @@ -0,0 +1,1309 @@ +/* + * jdpipe.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains decompression pipeline controllers. + * These routines are invoked via the d_pipeline_controller method. + * + * There are four basic pipeline controllers, one for each combination of: + * single-scan JPEG file (single component or fully interleaved) + * vs. multiple-scan JPEG file (noninterleaved or partially interleaved). + * + * 2-pass color quantization + * vs. no color quantization or 1-pass quantization. + * + * Note that these conditions determine the needs for "big" images: + * multiple scans imply a big image for recombining the color components; + * 2-pass color quantization needs a big image for saving the data for pass 2. + * + * All but the simplest controller (single-scan, no 2-pass quantization) can be + * compiled out through configuration options, if you need to make a minimal + * implementation. You should leave in multiple-scan support if at all + * possible, so that you can handle all legal JPEG files. + */ + +#include "jinclude.h" + + +/* + * About the data structures: + * + * The processing chunk size for unsubsampling is referred to in this file as + * a "row group": a row group is defined as Vk (v_samp_factor) sample rows of + * any component while subsampled, or Vmax (max_v_samp_factor) unsubsampled + * rows. In an interleaved scan each MCU row contains exactly DCTSIZE row + * groups of each component in the scan. In a noninterleaved scan an MCU row + * is one row of blocks, which might not be an integral number of row groups; + * therefore, we read in Vk MCU rows to obtain the same amount of data as we'd + * have in an interleaved scan. + * To provide context for the unsubsampling step, we have to retain the last + * two row groups of the previous MCU row while reading in the next MCU row + * (or set of Vk MCU rows). To do this without copying data about, we create + * a rather strange data structure. Exactly DCTSIZE+2 row groups of samples + * are allocated, but we create two different sets of pointers to this array. + * The second set swaps the last two pairs of row groups. By working + * alternately with the two sets of pointers, we can access the data in the + * desired order. + * + * Cross-block smoothing also needs context above and below the "current" row. + * Since this is an optional feature, I've implemented it in a way that is + * much simpler but requires more than the minimum amount of memory. We + * simply allocate three extra MCU rows worth of coefficient blocks and use + * them to "read ahead" one MCU row in the file. For a typical 1000-pixel-wide + * image with 2x2,1x1,1x1 sampling, each MCU row is about 50Kb; an 80x86 + * machine may be unable to apply cross-block smoothing to wider images. + */ + + +/* + * These variables are logically local to the pipeline controller, + * but we make them static so that scan_big_image can use them + * without having to pass them through the quantization routines. + * If you don't support 2-pass quantization, you could make them locals. + */ + +static int rows_in_mem; /* # of sample rows in full-size buffers */ +/* Full-size image array holding desubsampled, color-converted data. */ +static big_sarray_ptr *fullsize_cnvt_image; +static JSAMPIMAGE fullsize_cnvt_ptrs; /* workspace for access_big_sarray() results */ +/* Work buffer for color quantization output (full size, only 1 component). */ +static JSAMPARRAY quantize_out; + + +/* + * Utility routines: common code for pipeline controllers + */ + +LOCAL void +interleaved_scan_setup (decompress_info_ptr cinfo) +/* Compute all derived info for an interleaved (multi-component) scan */ +/* On entry, cinfo->comps_in_scan and cinfo->cur_comp_info[] are set up */ +{ + short ci, mcublks; + jpeg_component_info *compptr; + + if (cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT(cinfo->emethods, "Too many components for interleaved scan"); + + cinfo->MCUs_per_row = (cinfo->image_width + + cinfo->max_h_samp_factor*DCTSIZE - 1) + / (cinfo->max_h_samp_factor*DCTSIZE); + + cinfo->MCU_rows_in_scan = (cinfo->image_height + + cinfo->max_v_samp_factor*DCTSIZE - 1) + / (cinfo->max_v_samp_factor*DCTSIZE); + + cinfo->blocks_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* for interleaved scan, sampling factors give # of blocks per component */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; + /* compute physical dimensions of component */ + compptr->subsampled_width = jround_up(compptr->true_comp_width, + (long) (compptr->MCU_width*DCTSIZE)); + compptr->subsampled_height = jround_up(compptr->true_comp_height, + (long) (compptr->MCU_height*DCTSIZE)); + /* Sanity check */ + if (compptr->subsampled_width != + (cinfo->MCUs_per_row * (compptr->MCU_width*DCTSIZE))) + ERREXIT(cinfo->emethods, "I'm confused about the image width"); + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_blocks; + if (cinfo->blocks_in_MCU + mcublks > MAX_BLOCKS_IN_MCU) + ERREXIT(cinfo->emethods, "Sampling factors too large for interleaved scan"); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; + } + } + + (*cinfo->methods->d_per_scan_method_selection) (cinfo); +} + + +LOCAL void +noninterleaved_scan_setup (decompress_info_ptr cinfo) +/* Compute all derived info for a noninterleaved (single-component) scan */ +/* On entry, cinfo->comps_in_scan = 1 and cinfo->cur_comp_info[0] is set up */ +{ + jpeg_component_info *compptr = cinfo->cur_comp_info[0]; + + /* for noninterleaved scan, always one block per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_blocks = 1; + /* compute physical dimensions of component */ + compptr->subsampled_width = jround_up(compptr->true_comp_width, + (long) DCTSIZE); + compptr->subsampled_height = jround_up(compptr->true_comp_height, + (long) DCTSIZE); + + cinfo->MCUs_per_row = compptr->subsampled_width / DCTSIZE; + cinfo->MCU_rows_in_scan = compptr->subsampled_height / DCTSIZE; + + /* Prepare array describing MCU composition */ + cinfo->blocks_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + (*cinfo->methods->d_per_scan_method_selection) (cinfo); +} + + +LOCAL void +reverse_DCT (decompress_info_ptr cinfo, + JBLOCKIMAGE coeff_data, JSAMPIMAGE output_data, + int start_row) +/* Perform inverse DCT on each block in an MCU row's worth of data; */ +/* output the results into a sample array starting at row start_row. */ +/* NB: start_row can only be nonzero when dealing with a single-component */ +/* scan; otherwise we'd have to provide for different offsets for different */ +/* components, since the heights of interleaved MCU rows can vary. */ +{ + DCTBLOCK block; + JBLOCKROW browptr; + JSAMPARRAY srowptr; + long blocksperrow, bi; + short numrows, ri; + short ci; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + /* calc size of an MCU row in this component */ + blocksperrow = cinfo->cur_comp_info[ci]->subsampled_width / DCTSIZE; + numrows = cinfo->cur_comp_info[ci]->MCU_height; + /* iterate through all blocks in MCU row */ + for (ri = 0; ri < numrows; ri++) { + browptr = coeff_data[ci][ri]; + srowptr = output_data[ci] + (ri * DCTSIZE + start_row); + for (bi = 0; bi < blocksperrow; bi++) { + /* copy the data into a local DCTBLOCK. This allows for change of + * representation (if DCTELEM != JCOEF). On 80x86 machines it also + * brings the data back from FAR storage to NEAR storage. + */ + { register JCOEFPTR elemptr = browptr[bi]; + register DCTELEM *localblkptr = block; + register short elem = DCTSIZE2; + + while (--elem >= 0) + *localblkptr++ = (DCTELEM) *elemptr++; + } + + j_rev_dct(block); /* perform inverse DCT */ + + /* output the data into the sample array. + * Note change from signed to unsigned representation: + * DCT calculation works with values +-CENTERJSAMPLE, + * but sample arrays always hold 0..MAXJSAMPLE. + * Have to do explicit range-limiting because of quantization errors + * and so forth in the DCT/IDCT phase. + */ + { register JSAMPROW elemptr; + register DCTELEM *localblkptr = block; + register short elemr, elemc; + register DCTELEM temp; + + for (elemr = 0; elemr < DCTSIZE; elemr++) { + elemptr = srowptr[elemr] + (bi * DCTSIZE); + for (elemc = 0; elemc < DCTSIZE; elemc++) { + temp = (*localblkptr++) + CENTERJSAMPLE; + if (temp < 0) temp = 0; + else if (temp > MAXJSAMPLE) temp = MAXJSAMPLE; + *elemptr++ = (JSAMPLE) temp; + } + } + } + } + } + } +} + + + +LOCAL JSAMPIMAGE +alloc_sampimage (decompress_info_ptr cinfo, + int num_comps, long num_rows, long num_cols) +/* Allocate an in-memory sample image (all components same size) */ +{ + JSAMPIMAGE image; + int ci; + + image = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (num_comps * SIZEOF(JSAMPARRAY)); + for (ci = 0; ci < num_comps; ci++) { + image[ci] = (*cinfo->emethods->alloc_small_sarray) (num_cols, num_rows); + } + return image; +} + + +LOCAL void +free_sampimage (decompress_info_ptr cinfo, JSAMPIMAGE image, + int num_comps, long num_rows) +/* Release a sample image created by alloc_sampimage */ +{ + int ci; + + for (ci = 0; ci < num_comps; ci++) { + (*cinfo->emethods->free_small_sarray) (image[ci], num_rows); + } + (*cinfo->emethods->free_small) ((void *) image); +} + + +LOCAL JBLOCKIMAGE +alloc_MCU_row (decompress_info_ptr cinfo) +/* Allocate one MCU row's worth of coefficient blocks */ +{ + JBLOCKIMAGE image; + int ci; + + image = (JBLOCKIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->comps_in_scan * SIZEOF(JBLOCKARRAY)); + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + image[ci] = (*cinfo->emethods->alloc_small_barray) + (cinfo->cur_comp_info[ci]->subsampled_width / DCTSIZE, + (long) cinfo->cur_comp_info[ci]->MCU_height); + } + return image; +} + + +LOCAL void +free_MCU_row (decompress_info_ptr cinfo, JBLOCKIMAGE image) +/* Release a coefficient block array created by alloc_MCU_row */ +{ + int ci; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + (*cinfo->emethods->free_small_barray) + (image[ci], (long) cinfo->cur_comp_info[ci]->MCU_height); + } + (*cinfo->emethods->free_small) ((void *) image); +} + + +LOCAL void +alloc_sampling_buffer (decompress_info_ptr cinfo, JSAMPIMAGE subsampled_data[2]) +/* Create a subsampled-data buffer having the desired structure */ +/* (see comments at head of file) */ +{ + short ci, vs, i; + + /* Get top-level space for array pointers */ + subsampled_data[0] = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->comps_in_scan * SIZEOF(JSAMPARRAY)); + subsampled_data[1] = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->comps_in_scan * SIZEOF(JSAMPARRAY)); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + vs = cinfo->cur_comp_info[ci]->v_samp_factor; /* row group height */ + /* Allocate the real storage */ + subsampled_data[0][ci] = (*cinfo->emethods->alloc_small_sarray) + (cinfo->cur_comp_info[ci]->subsampled_width, + (long) (vs * (DCTSIZE+2))); + /* Create space for the scrambled-order pointers */ + subsampled_data[1][ci] = (JSAMPARRAY) (*cinfo->emethods->alloc_small) + (vs * (DCTSIZE+2) * SIZEOF(JSAMPROW)); + /* Duplicate the first DCTSIZE-2 row groups */ + for (i = 0; i < vs * (DCTSIZE-2); i++) { + subsampled_data[1][ci][i] = subsampled_data[0][ci][i]; + } + /* Copy the last four row groups in swapped order */ + for (i = 0; i < vs * 2; i++) { + subsampled_data[1][ci][vs*DCTSIZE + i] = subsampled_data[0][ci][vs*(DCTSIZE-2) + i]; + subsampled_data[1][ci][vs*(DCTSIZE-2) + i] = subsampled_data[0][ci][vs*DCTSIZE + i]; + } + } +} + + +LOCAL void +free_sampling_buffer (decompress_info_ptr cinfo, JSAMPIMAGE subsampled_data[2]) +/* Release a sampling buffer created by alloc_sampling_buffer */ +{ + short ci, vs; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + vs = cinfo->cur_comp_info[ci]->v_samp_factor; /* row group height */ + /* Free the real storage */ + (*cinfo->emethods->free_small_sarray) + (subsampled_data[0][ci], (long) (vs * (DCTSIZE+2))); + /* Free the scrambled-order pointers */ + (*cinfo->emethods->free_small) ((void *) subsampled_data[1][ci]); + } + + /* Free the top-level space */ + (*cinfo->emethods->free_small) ((void *) subsampled_data[0]); + (*cinfo->emethods->free_small) ((void *) subsampled_data[1]); +} + + +LOCAL void +duplicate_row (JSAMPARRAY image_data, + long num_cols, int source_row, int num_rows) +/* Duplicate the source_row at source_row+1 .. source_row+num_rows */ +/* This happens only at the bottom of the image, */ +/* so it needn't be super-efficient */ +{ + register int row; + + for (row = 1; row <= num_rows; row++) { + jcopy_sample_rows(image_data, source_row, image_data, source_row + row, + 1, num_cols); + } +} + + +LOCAL void +expand (decompress_info_ptr cinfo, + JSAMPIMAGE subsampled_data, JSAMPIMAGE fullsize_data, + long fullsize_width, + short above, short current, short below, short out) +/* Do unsubsampling expansion of a single row group (of each component). */ +/* above, current, below are indexes of row groups in subsampled_data; */ +/* out is the index of the target row group in fullsize_data. */ +/* Special case: above, below can be -1 to indicate top, bottom of image. */ +{ + jpeg_component_info *compptr; + JSAMPARRAY above_ptr, below_ptr; + JSAMPROW dummy[MAX_SAMP_FACTOR]; /* for subsample expansion at top/bottom */ + short ci, vs, i; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + vs = compptr->v_samp_factor; /* row group height */ + + if (above >= 0) + above_ptr = subsampled_data[ci] + above * vs; + else { + /* Top of image: make a dummy above-context with copies of 1st row */ + /* We assume current=0 in this case */ + for (i = 0; i < vs; i++) + dummy[i] = subsampled_data[ci][0]; + above_ptr = (JSAMPARRAY) dummy; /* possible near->far pointer conv */ + } + + if (below >= 0) + below_ptr = subsampled_data[ci] + below * vs; + else { + /* Bot of image: make a dummy below-context with copies of last row */ + for (i = 0; i < vs; i++) + dummy[i] = subsampled_data[ci][(current+1)*vs-1]; + below_ptr = (JSAMPARRAY) dummy; /* possible near->far pointer conv */ + } + + (*cinfo->methods->unsubsample[ci]) + (cinfo, (int) ci, + compptr->subsampled_width, (int) vs, + fullsize_width, (int) cinfo->max_v_samp_factor, + above_ptr, + subsampled_data[ci] + current * vs, + below_ptr, + fullsize_data[ci] + out * cinfo->max_v_samp_factor); + } +} + + +LOCAL void +emit_1pass (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE fullsize_data, JSAMPIMAGE color_data) +/* Do color conversion and output of num_rows full-size rows. */ +/* This is not used for 2-pass color quantization. */ +{ + (*cinfo->methods->color_convert) (cinfo, num_rows, + fullsize_data, color_data); + + if (cinfo->quantize_colors) { + (*cinfo->methods->color_quantize) (cinfo, num_rows, + color_data, quantize_out); + + (*cinfo->methods->put_pixel_rows) (cinfo, num_rows, + &quantize_out); + } else { + (*cinfo->methods->put_pixel_rows) (cinfo, num_rows, + color_data); + } +} + + +/* + * Support routines for 2-pass color quantization. + */ + +#ifdef QUANT_2PASS_SUPPORTED + +LOCAL void +emit_2pass (decompress_info_ptr cinfo, long top_row, int num_rows, + JSAMPIMAGE fullsize_data) +/* Do color conversion and output data to the quantization buffer image. */ +/* This is used only with 2-pass color quantization. */ +{ + short ci; + + /* Realign the big buffers */ + for (ci = 0; ci < cinfo->num_components; ci++) { + fullsize_cnvt_ptrs[ci] = (*cinfo->emethods->access_big_sarray) + (fullsize_cnvt_image[ci], top_row, TRUE); + } + + /* Do colorspace conversion */ + (*cinfo->methods->color_convert) (cinfo, num_rows, + fullsize_data, fullsize_cnvt_ptrs); + /* Let quantizer get first-pass peek at the data. */ + /* (Quantizer could change data if it wants to.) */ + (*cinfo->methods->color_quant_prescan) (cinfo, num_rows, fullsize_cnvt_ptrs); +} + + +METHODDEF void +scan_big_image (decompress_info_ptr cinfo, quantize_method_ptr quantize_method) +/* This is the "iterator" routine used by the quantizer. */ +{ + long pixel_rows_output; + short ci; + + for (pixel_rows_output = 0; pixel_rows_output < cinfo->image_height; + pixel_rows_output += rows_in_mem) { + /* Realign the big buffers */ + for (ci = 0; ci < cinfo->num_components; ci++) { + fullsize_cnvt_ptrs[ci] = (*cinfo->emethods->access_big_sarray) + (fullsize_cnvt_image[ci], pixel_rows_output, FALSE); + } + /* Let the quantizer have its way with the data. + * Note that quantize_out is simply workspace for the quantizer; + * when it's ready to output, it must call put_pixel_rows itself. + */ + (*quantize_method) (cinfo, + (int) MIN(rows_in_mem, + cinfo->image_height - pixel_rows_output), + fullsize_cnvt_ptrs, quantize_out); + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Support routines for cross-block smoothing. + */ + +#ifdef BLOCK_SMOOTHING_SUPPORTED + + +LOCAL void +smooth_mcu_row (decompress_info_ptr cinfo, + JBLOCKIMAGE above, JBLOCKIMAGE input, JBLOCKIMAGE below, + JBLOCKIMAGE output) +/* Apply cross-block smoothing to one MCU row's worth of coefficient blocks. */ +/* above,below are NULL if at top/bottom of image. */ +{ + jpeg_component_info *compptr; + short ci, ri, last; + JBLOCKROW prev; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + last = compptr->MCU_height - 1; + + if (above == NULL) + prev = NULL; + else + prev = above[ci][last]; + + for (ri = 0; ri < last; ri++) { + (*cinfo->methods->smooth_coefficients) (cinfo, compptr, + prev, input[ci][ri], input[ci][ri+1], + output[ci][ri]); + prev = input[ci][ri]; + } + + if (below == NULL) + (*cinfo->methods->smooth_coefficients) (cinfo, compptr, + prev, input[ci][last], (JBLOCKROW) NULL, + output[ci][last]); + else + (*cinfo->methods->smooth_coefficients) (cinfo, compptr, + prev, input[ci][last], below[ci][0], + output[ci][last]); + } +} + + +LOCAL void +get_smoothed_row (decompress_info_ptr cinfo, JBLOCKIMAGE coeff_data, + JBLOCKIMAGE bsmooth[3], int * whichb, long cur_mcu_row) +/* Get an MCU row of coefficients, applying cross-block smoothing. */ +/* The output row is placed in coeff_data. bsmooth and whichb hold */ +/* working state, and cur_row is needed to check for image top/bottom. */ +/* This routine just takes care of the buffering logic. */ +{ + int prev, cur, next; + + /* Special case for top of image: need to pre-fetch a row & init whichb */ + if (cur_mcu_row == 0) { + (*cinfo->methods->disassemble_MCU) (cinfo, bsmooth[0]); + if (cinfo->MCU_rows_in_scan > 1) { + (*cinfo->methods->disassemble_MCU) (cinfo, bsmooth[1]); + smooth_mcu_row(cinfo, (JBLOCKIMAGE) NULL, bsmooth[0], bsmooth[1], + coeff_data); + } else { + smooth_mcu_row(cinfo, (JBLOCKIMAGE) NULL, bsmooth[0], (JBLOCKIMAGE) NULL, + coeff_data); + } + *whichb = 1; /* points to next bsmooth[] element to use */ + return; + } + + cur = *whichb; /* set up references */ + prev = (cur == 0 ? 2 : cur - 1); + next = (cur == 2 ? 0 : cur + 1); + *whichb = next; /* advance whichb for next time */ + + /* Special case for bottom of image: don't read another row */ + if (cur_mcu_row >= cinfo->MCU_rows_in_scan - 1) { + smooth_mcu_row(cinfo, bsmooth[prev], bsmooth[cur], (JBLOCKIMAGE) NULL, + coeff_data); + return; + } + + /* Normal case: read ahead a new row, smooth the one I got before */ + (*cinfo->methods->disassemble_MCU) (cinfo, bsmooth[next]); + smooth_mcu_row(cinfo, bsmooth[prev], bsmooth[cur], bsmooth[next], + coeff_data); +} + + +#endif /* BLOCK_SMOOTHING_SUPPORTED */ + + + +/* + * Decompression pipeline controller used for single-scan files + * without 2-pass color quantization. + */ + +METHODDEF void +single_dcontroller (decompress_info_ptr cinfo) +{ + long fullsize_width; /* # of samples per row in full-size buffers */ + long cur_mcu_row; /* counts # of MCU rows processed */ + long pixel_rows_output; /* # of pixel rows actually emitted */ + int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */ + /* Work buffer for dequantized coefficients (IDCT input) */ + JBLOCKIMAGE coeff_data; + /* Work buffer for cross-block smoothing input */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + JBLOCKIMAGE bsmooth[3]; /* this is optional */ + int whichb; +#endif + /* Work buffer for subsampled image data (see comments at head of file) */ + JSAMPIMAGE subsampled_data[2]; + /* Work buffer for desubsampled data */ + JSAMPIMAGE fullsize_data; + /* Work buffer for color conversion output (full size) */ + JSAMPIMAGE color_data; + int whichss, ri; + short i; + + /* Initialize for 1-pass color quantization, if needed */ + if (cinfo->quantize_colors) + (*cinfo->methods->color_quant_init) (cinfo); + + /* Prepare for single scan containing all components */ + if (cinfo->comps_in_scan == 1) { + noninterleaved_scan_setup(cinfo); + /* Need to read Vk MCU rows to obtain Vk block rows */ + mcu_rows_per_loop = cinfo->cur_comp_info[0]->v_samp_factor; + } else { + interleaved_scan_setup(cinfo); + /* in an interleaved scan, one MCU row provides Vk block rows */ + mcu_rows_per_loop = 1; + } + + /* Compute dimensions of full-size pixel buffers */ + /* Note these are the same whether interleaved or not. */ + rows_in_mem = cinfo->max_v_samp_factor * DCTSIZE; + fullsize_width = jround_up(cinfo->image_width, + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + + /* Allocate working memory: */ + /* coeff_data holds a single MCU row of coefficient blocks */ + coeff_data = alloc_MCU_row(cinfo); + /* if doing cross-block smoothing, need extra space for its input */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) { + bsmooth[0] = alloc_MCU_row(cinfo); + bsmooth[1] = alloc_MCU_row(cinfo); + bsmooth[2] = alloc_MCU_row(cinfo); + } +#endif + /* subsampled_data is sample data before unsubsampling */ + alloc_sampling_buffer(cinfo, subsampled_data); + /* fullsize_data is sample data after unsubsampling */ + fullsize_data = alloc_sampimage(cinfo, (int) cinfo->num_components, + (long) rows_in_mem, fullsize_width); + /* color_data is the result of the colorspace conversion step */ + color_data = alloc_sampimage(cinfo, (int) cinfo->color_out_comps, + (long) rows_in_mem, fullsize_width); + /* if quantizing colors, also need a one-component output area for that. */ + if (cinfo->quantize_colors) + quantize_out = (*cinfo->emethods->alloc_small_sarray) + (fullsize_width, (long) rows_in_mem); + + /* Tell the memory manager to instantiate big arrays. + * We don't need any big arrays in this controller, + * but some other module (like the output file writer) may need one. + */ + (*cinfo->emethods->alloc_big_arrays) + ((long) 0, /* no more small sarrays */ + (long) 0, /* no more small barrays */ + (long) 0); /* no more "medium" objects */ + /* NB: quantizer must get any such objects at color_quant_init time */ + + /* Initialize to read scan data */ + + (*cinfo->methods->entropy_decoder_init) (cinfo); + (*cinfo->methods->unsubsample_init) (cinfo); + (*cinfo->methods->disassemble_init) (cinfo); + + /* Loop over scan's data: rows_in_mem pixel rows are processed per loop */ + + pixel_rows_output = 0; + whichss = 1; /* arrange to start with subsampled_data[0] */ + + for (cur_mcu_row = 0; cur_mcu_row < cinfo->MCU_rows_in_scan; + cur_mcu_row += mcu_rows_per_loop) { + whichss ^= 1; /* switch to other subsample buffer */ + + /* Obtain v_samp_factor block rows of each component in the scan. */ + /* This is a single MCU row if interleaved, multiple MCU rows if not. */ + /* In the noninterleaved case there might be fewer than v_samp_factor */ + /* block rows remaining; if so, pad with copies of the last pixel row */ + /* so that unsubsampling doesn't have to treat it as a special case. */ + + for (ri = 0; ri < mcu_rows_per_loop; ri++) { + if (cur_mcu_row + ri < cinfo->MCU_rows_in_scan) { + /* OK to actually read an MCU row. */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) + get_smoothed_row(cinfo, coeff_data, + bsmooth, &whichb, cur_mcu_row + ri); + else +#endif + (*cinfo->methods->disassemble_MCU) (cinfo, coeff_data); + + reverse_DCT(cinfo, coeff_data, subsampled_data[whichss], + ri * DCTSIZE); + } else { + /* Need to pad out with copies of the last subsampled row. */ + /* This can only happen if there is just one component. */ + duplicate_row(subsampled_data[whichss][0], + cinfo->cur_comp_info[0]->subsampled_width, + ri * DCTSIZE - 1, DCTSIZE); + } + } + + /* Unsubsample the data */ + /* First time through is a special case */ + + if (cur_mcu_row) { + /* Expand last row group of previous set */ + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) DCTSIZE, (short) (DCTSIZE+1), (short) 0, + (short) (DCTSIZE-1)); + /* and dump the previous set's expanded data */ + emit_1pass (cinfo, rows_in_mem, fullsize_data, color_data); + pixel_rows_output += rows_in_mem; + /* Expand first row group of this set */ + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) (DCTSIZE+1), (short) 0, (short) 1, + (short) 0); + } else { + /* Expand first row group with dummy above-context */ + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) (-1), (short) 0, (short) 1, + (short) 0); + } + /* Expand second through next-to-last row groups of this set */ + for (i = 1; i <= DCTSIZE-2; i++) { + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) (i-1), (short) i, (short) (i+1), + (short) i); + } + } /* end of outer loop */ + + /* Expand the last row group with dummy below-context */ + /* Note whichss points to last buffer side used */ + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1), + (short) (DCTSIZE-1)); + /* and dump the remaining data (may be less than full height) */ + emit_1pass (cinfo, (int) (cinfo->image_height - pixel_rows_output), + fullsize_data, color_data); + + /* Clean up after the scan */ + (*cinfo->methods->disassemble_term) (cinfo); + (*cinfo->methods->unsubsample_term) (cinfo); + (*cinfo->methods->entropy_decoder_term) (cinfo); + (*cinfo->methods->read_scan_trailer) (cinfo); + + /* Verify that we've seen the whole input file */ + if ((*cinfo->methods->read_scan_header) (cinfo)) + ERREXIT(cinfo->emethods, "Didn't expect more than one scan"); + + /* Release working memory */ + free_MCU_row(cinfo, coeff_data); +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) { + free_MCU_row(cinfo, bsmooth[0]); + free_MCU_row(cinfo, bsmooth[1]); + free_MCU_row(cinfo, bsmooth[2]); + } +#endif + free_sampling_buffer(cinfo, subsampled_data); + free_sampimage(cinfo, fullsize_data, (int) cinfo->num_components, + (long) rows_in_mem); + free_sampimage(cinfo, color_data, (int) cinfo->color_out_comps, + (long) rows_in_mem); + if (cinfo->quantize_colors) + (*cinfo->emethods->free_small_sarray) + (quantize_out, (long) rows_in_mem); + + /* Close up shop */ + if (cinfo->quantize_colors) + (*cinfo->methods->color_quant_term) (cinfo); +} + + +/* + * Decompression pipeline controller used for single-scan files + * with 2-pass color quantization. + */ + +#ifdef QUANT_2PASS_SUPPORTED + +METHODDEF void +single_2quant_dcontroller (decompress_info_ptr cinfo) +{ + long fullsize_width; /* # of samples per row in full-size buffers */ + long cur_mcu_row; /* counts # of MCU rows processed */ + long pixel_rows_output; /* # of pixel rows actually emitted */ + int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */ + /* Work buffer for dequantized coefficients (IDCT input) */ + JBLOCKIMAGE coeff_data; + /* Work buffer for cross-block smoothing input */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + JBLOCKIMAGE bsmooth[3]; /* this is optional */ + int whichb; +#endif + /* Work buffer for subsampled image data (see comments at head of file) */ + JSAMPIMAGE subsampled_data[2]; + /* Work buffer for desubsampled data */ + JSAMPIMAGE fullsize_data; + int whichss, ri; + short ci, i; + + /* Initialize for 2-pass color quantization */ + (*cinfo->methods->color_quant_init) (cinfo); + + /* Prepare for single scan containing all components */ + if (cinfo->comps_in_scan == 1) { + noninterleaved_scan_setup(cinfo); + /* Need to read Vk MCU rows to obtain Vk block rows */ + mcu_rows_per_loop = cinfo->cur_comp_info[0]->v_samp_factor; + } else { + interleaved_scan_setup(cinfo); + /* in an interleaved scan, one MCU row provides Vk block rows */ + mcu_rows_per_loop = 1; + } + + /* Compute dimensions of full-size pixel buffers */ + /* Note these are the same whether interleaved or not. */ + rows_in_mem = cinfo->max_v_samp_factor * DCTSIZE; + fullsize_width = jround_up(cinfo->image_width, + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + + /* Allocate working memory: */ + /* coeff_data holds a single MCU row of coefficient blocks */ + coeff_data = alloc_MCU_row(cinfo); + /* if doing cross-block smoothing, need extra space for its input */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) { + bsmooth[0] = alloc_MCU_row(cinfo); + bsmooth[1] = alloc_MCU_row(cinfo); + bsmooth[2] = alloc_MCU_row(cinfo); + } +#endif + /* subsampled_data is sample data before unsubsampling */ + alloc_sampling_buffer(cinfo, subsampled_data); + /* fullsize_data is sample data after unsubsampling */ + fullsize_data = alloc_sampimage(cinfo, (int) cinfo->num_components, + (long) rows_in_mem, fullsize_width); + /* Also need a one-component output area for color quantizer. */ + quantize_out = (*cinfo->emethods->alloc_small_sarray) + (fullsize_width, (long) rows_in_mem); + + /* Get a big image for quantizer input: desubsampled, color-converted data */ + fullsize_cnvt_image = (big_sarray_ptr *) (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(big_sarray_ptr)); + for (ci = 0; ci < cinfo->num_components; ci++) { + fullsize_cnvt_image[ci] = (*cinfo->emethods->request_big_sarray) + (fullsize_width, + jround_up(cinfo->image_height, (long) rows_in_mem), + (long) rows_in_mem); + } + /* Also get an area for pointers to currently accessible chunks */ + fullsize_cnvt_ptrs = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(JSAMPARRAY)); + + /* Tell the memory manager to instantiate big arrays */ + (*cinfo->emethods->alloc_big_arrays) + ((long) 0, /* no more small sarrays */ + (long) 0, /* no more small barrays */ + (long) 0); /* no more "medium" objects */ + /* NB: quantizer must get any such objects at color_quant_init time */ + + /* Initialize to read scan data */ + + (*cinfo->methods->entropy_decoder_init) (cinfo); + (*cinfo->methods->unsubsample_init) (cinfo); + (*cinfo->methods->disassemble_init) (cinfo); + + /* Loop over scan's data: rows_in_mem pixel rows are processed per loop */ + + pixel_rows_output = 0; + whichss = 1; /* arrange to start with subsampled_data[0] */ + + for (cur_mcu_row = 0; cur_mcu_row < cinfo->MCU_rows_in_scan; + cur_mcu_row += mcu_rows_per_loop) { + whichss ^= 1; /* switch to other subsample buffer */ + + /* Obtain v_samp_factor block rows of each component in the scan. */ + /* This is a single MCU row if interleaved, multiple MCU rows if not. */ + /* In the noninterleaved case there might be fewer than v_samp_factor */ + /* block rows remaining; if so, pad with copies of the last pixel row */ + /* so that unsubsampling doesn't have to treat it as a special case. */ + + for (ri = 0; ri < mcu_rows_per_loop; ri++) { + if (cur_mcu_row + ri < cinfo->MCU_rows_in_scan) { + /* OK to actually read an MCU row. */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) + get_smoothed_row(cinfo, coeff_data, + bsmooth, &whichb, cur_mcu_row + ri); + else +#endif + (*cinfo->methods->disassemble_MCU) (cinfo, coeff_data); + + reverse_DCT(cinfo, coeff_data, subsampled_data[whichss], + ri * DCTSIZE); + } else { + /* Need to pad out with copies of the last subsampled row. */ + /* This can only happen if there is just one component. */ + duplicate_row(subsampled_data[whichss][0], + cinfo->cur_comp_info[0]->subsampled_width, + ri * DCTSIZE - 1, DCTSIZE); + } + } + + /* Unsubsample the data */ + /* First time through is a special case */ + + if (cur_mcu_row) { + /* Expand last row group of previous set */ + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) DCTSIZE, (short) (DCTSIZE+1), (short) 0, + (short) (DCTSIZE-1)); + /* and dump the previous set's expanded data */ + emit_2pass (cinfo, pixel_rows_output, rows_in_mem, fullsize_data); + pixel_rows_output += rows_in_mem; + /* Expand first row group of this set */ + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) (DCTSIZE+1), (short) 0, (short) 1, + (short) 0); + } else { + /* Expand first row group with dummy above-context */ + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) (-1), (short) 0, (short) 1, + (short) 0); + } + /* Expand second through next-to-last row groups of this set */ + for (i = 1; i <= DCTSIZE-2; i++) { + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) (i-1), (short) i, (short) (i+1), + (short) i); + } + } /* end of outer loop */ + + /* Expand the last row group with dummy below-context */ + /* Note whichss points to last buffer side used */ + expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, + (short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1), + (short) (DCTSIZE-1)); + /* and dump the remaining data (may be less than full height) */ + emit_2pass (cinfo, pixel_rows_output, + (int) (cinfo->image_height - pixel_rows_output), + fullsize_data); + + /* Clean up after the scan */ + (*cinfo->methods->disassemble_term) (cinfo); + (*cinfo->methods->unsubsample_term) (cinfo); + (*cinfo->methods->entropy_decoder_term) (cinfo); + (*cinfo->methods->read_scan_trailer) (cinfo); + + /* Verify that we've seen the whole input file */ + if ((*cinfo->methods->read_scan_header) (cinfo)) + ERREXIT(cinfo->emethods, "Didn't expect more than one scan"); + + /* Now that we've collected the data, let the color quantizer do its thing */ + (*cinfo->methods->color_quant_doit) (cinfo, scan_big_image); + + /* Release working memory */ + free_MCU_row(cinfo, coeff_data); +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) { + free_MCU_row(cinfo, bsmooth[0]); + free_MCU_row(cinfo, bsmooth[1]); + free_MCU_row(cinfo, bsmooth[2]); + } +#endif + free_sampling_buffer(cinfo, subsampled_data); + free_sampimage(cinfo, fullsize_data, (int) cinfo->num_components, + (long) rows_in_mem); + (*cinfo->emethods->free_small_sarray) + (quantize_out, (long) rows_in_mem); + for (ci = 0; ci < cinfo->num_components; ci++) { + (*cinfo->emethods->free_big_sarray) (fullsize_cnvt_image[ci]); + } + (*cinfo->emethods->free_small) ((void *) fullsize_cnvt_image); + (*cinfo->emethods->free_small) ((void *) fullsize_cnvt_ptrs); + + /* Close up shop */ + (*cinfo->methods->color_quant_term) (cinfo); +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Decompression pipeline controller used for multiple-scan files + * without 2-pass color quantization. + * + * The current implementation places the "big" buffer at the stage of + * desubsampled data. Buffering subsampled data instead would reduce the + * size of temp files (by about a factor of 2 in typical cases). However, + * the unsubsampling logic is dependent on the assumption that unsubsampling + * occurs during a scan, so it's much easier to do the enlargement as the + * JPEG file is read. This also simplifies life for the memory manager, + * which would otherwise have to deal with overlapping access_big_sarray() + * requests. + * + * At present it appears that most JPEG files will be single-scan, so + * it doesn't seem worthwhile to try to make this implementation smarter. + */ + +#ifdef MULTISCAN_FILES_SUPPORTED + +METHODDEF void +multi_dcontroller (decompress_info_ptr cinfo) +{ + long fullsize_width; /* # of samples per row in full-size buffers */ + long cur_mcu_row; /* counts # of MCU rows processed */ + long pixel_rows_output; /* # of pixel rows actually emitted */ + int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */ + /* Work buffer for dequantized coefficients (IDCT input) */ + JBLOCKIMAGE coeff_data; + /* Work buffer for cross-block smoothing input */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + JBLOCKIMAGE bsmooth[3]; /* this is optional */ + int whichb; +#endif + /* Work buffer for subsampled image data (see comments at head of file) */ + JSAMPIMAGE subsampled_data[2]; + /* Full-image buffer holding desubsampled, but not color-converted, data */ + big_sarray_ptr *fullsize_image; + JSAMPIMAGE fullsize_ptrs; /* workspace for access_big_sarray() results */ + /* Work buffer for color conversion output (full size) */ + JSAMPIMAGE color_data; + int whichss, ri; + short ci, i; + + /* Initialize for 1-pass color quantization, if needed */ + if (cinfo->quantize_colors) + (*cinfo->methods->color_quant_init) (cinfo); + + /* Compute dimensions of full-size pixel buffers */ + /* Note these are the same whether interleaved or not. */ + rows_in_mem = cinfo->max_v_samp_factor * DCTSIZE; + fullsize_width = jround_up(cinfo->image_width, + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + + /* Allocate all working memory that doesn't depend on scan info */ + /* color_data is the result of the colorspace conversion step */ + color_data = alloc_sampimage(cinfo, (int) cinfo->color_out_comps, + (long) rows_in_mem, fullsize_width); + /* if quantizing colors, also need a one-component output area for that. */ + if (cinfo->quantize_colors) + quantize_out = (*cinfo->emethods->alloc_small_sarray) + (fullsize_width, (long) rows_in_mem); + + /* Get a big image: fullsize_image is sample data after unsubsampling. */ + fullsize_image = (big_sarray_ptr *) (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(big_sarray_ptr)); + for (ci = 0; ci < cinfo->num_components; ci++) { + fullsize_image[ci] = (*cinfo->emethods->request_big_sarray) + (fullsize_width, + jround_up(cinfo->image_height, (long) rows_in_mem), + (long) rows_in_mem); + } + /* Also get an area for pointers to currently accessible chunks */ + fullsize_ptrs = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(JSAMPARRAY)); + + /* Tell the memory manager to instantiate big arrays */ + (*cinfo->emethods->alloc_big_arrays) + /* extra sarray space is for subsampled-data buffers: */ + ((long) (fullsize_width /* max width in samples */ + * cinfo->max_v_samp_factor*(DCTSIZE+2) /* max height */ + * cinfo->num_components), /* max components per scan */ + /* extra barray space is for MCU-row buffers: */ + (long) ((fullsize_width / DCTSIZE) /* max width in blocks */ + * cinfo->max_v_samp_factor /* max height */ + * cinfo->num_components /* max components per scan */ + * (cinfo->do_block_smoothing ? 4 : 1)),/* how many of these we need */ + /* no extra "medium"-object space */ + /* NB: quantizer must get any such objects at color_quant_init time */ + (long) 0); + + + /* Loop over scans in file */ + + do { + + /* Prepare for this scan */ + if (cinfo->comps_in_scan == 1) { + noninterleaved_scan_setup(cinfo); + /* Need to read Vk MCU rows to obtain Vk block rows */ + mcu_rows_per_loop = cinfo->cur_comp_info[0]->v_samp_factor; + } else { + interleaved_scan_setup(cinfo); + /* in an interleaved scan, one MCU row provides Vk block rows */ + mcu_rows_per_loop = 1; + } + + /* Allocate scan-local working memory */ + /* coeff_data holds a single MCU row of coefficient blocks */ + coeff_data = alloc_MCU_row(cinfo); + /* if doing cross-block smoothing, need extra space for its input */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) { + bsmooth[0] = alloc_MCU_row(cinfo); + bsmooth[1] = alloc_MCU_row(cinfo); + bsmooth[2] = alloc_MCU_row(cinfo); + } +#endif + /* subsampled_data is sample data before unsubsampling */ + alloc_sampling_buffer(cinfo, subsampled_data); + + /* line up the big buffers */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + fullsize_ptrs[ci] = (*cinfo->emethods->access_big_sarray) + (fullsize_image[cinfo->cur_comp_info[ci]->component_index], + (long) 0, TRUE); + } + + /* Initialize to read scan data */ + + (*cinfo->methods->entropy_decoder_init) (cinfo); + (*cinfo->methods->unsubsample_init) (cinfo); + (*cinfo->methods->disassemble_init) (cinfo); + + /* Loop over scan's data: rows_in_mem pixel rows are processed per loop */ + + pixel_rows_output = 0; + whichss = 1; /* arrange to start with subsampled_data[0] */ + + for (cur_mcu_row = 0; cur_mcu_row < cinfo->MCU_rows_in_scan; + cur_mcu_row += mcu_rows_per_loop) { + whichss ^= 1; /* switch to other subsample buffer */ + + /* Obtain v_samp_factor block rows of each component in the scan. */ + /* This is a single MCU row if interleaved, multiple MCU rows if not. */ + /* In the noninterleaved case there might be fewer than v_samp_factor */ + /* block rows remaining; if so, pad with copies of the last pixel row */ + /* so that unsubsampling doesn't have to treat it as a special case. */ + + for (ri = 0; ri < mcu_rows_per_loop; ri++) { + if (cur_mcu_row + ri < cinfo->MCU_rows_in_scan) { + /* OK to actually read an MCU row. */ +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) + get_smoothed_row(cinfo, coeff_data, + bsmooth, &whichb, cur_mcu_row + ri); + else +#endif + (*cinfo->methods->disassemble_MCU) (cinfo, coeff_data); + + reverse_DCT(cinfo, coeff_data, subsampled_data[whichss], + ri * DCTSIZE); + } else { + /* Need to pad out with copies of the last subsampled row. */ + /* This can only happen if there is just one component. */ + duplicate_row(subsampled_data[whichss][0], + cinfo->cur_comp_info[0]->subsampled_width, + ri * DCTSIZE - 1, DCTSIZE); + } + } + + /* Unsubsample the data */ + /* First time through is a special case */ + + if (cur_mcu_row) { + /* Expand last row group of previous set */ + expand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width, + (short) DCTSIZE, (short) (DCTSIZE+1), (short) 0, + (short) (DCTSIZE-1)); + /* Realign the big buffers */ + pixel_rows_output += rows_in_mem; + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + fullsize_ptrs[ci] = (*cinfo->emethods->access_big_sarray) + (fullsize_image[cinfo->cur_comp_info[ci]->component_index], + pixel_rows_output, TRUE); + } + /* Expand first row group of this set */ + expand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width, + (short) (DCTSIZE+1), (short) 0, (short) 1, + (short) 0); + } else { + /* Expand first row group with dummy above-context */ + expand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width, + (short) (-1), (short) 0, (short) 1, + (short) 0); + } + /* Expand second through next-to-last row groups of this set */ + for (i = 1; i <= DCTSIZE-2; i++) { + expand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width, + (short) (i-1), (short) i, (short) (i+1), + (short) i); + } + } /* end of outer loop */ + + /* Expand the last row group with dummy below-context */ + /* Note whichss points to last buffer side used */ + expand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width, + (short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1), + (short) (DCTSIZE-1)); + + /* Clean up after the scan */ + (*cinfo->methods->disassemble_term) (cinfo); + (*cinfo->methods->unsubsample_term) (cinfo); + (*cinfo->methods->entropy_decoder_term) (cinfo); + (*cinfo->methods->read_scan_trailer) (cinfo); + + /* Release scan-local working memory */ + free_MCU_row(cinfo, coeff_data); +#ifdef BLOCK_SMOOTHING_SUPPORTED + if (cinfo->do_block_smoothing) { + free_MCU_row(cinfo, bsmooth[0]); + free_MCU_row(cinfo, bsmooth[1]); + free_MCU_row(cinfo, bsmooth[2]); + } +#endif + free_sampling_buffer(cinfo, subsampled_data); + + /* Repeat if there is another scan */ + } while ((*cinfo->methods->read_scan_header) (cinfo)); + + /* Now that we've collected all the data, color convert & output it. */ + + for (pixel_rows_output = 0; pixel_rows_output < cinfo->image_height; + pixel_rows_output += rows_in_mem) { + + /* realign the big buffers */ + for (ci = 0; ci < cinfo->num_components; ci++) { + fullsize_ptrs[ci] = (*cinfo->emethods->access_big_sarray) + (fullsize_image[ci], pixel_rows_output, FALSE); + } + + emit_1pass (cinfo, + (int) MIN(rows_in_mem, cinfo->image_height-pixel_rows_output), + fullsize_ptrs, color_data); + } + + /* Release working memory */ + free_sampimage(cinfo, color_data, (int) cinfo->color_out_comps, + (long) rows_in_mem); + if (cinfo->quantize_colors) + (*cinfo->emethods->free_small_sarray) + (quantize_out, (long) rows_in_mem); + for (ci = 0; ci < cinfo->num_components; ci++) { + (*cinfo->emethods->free_big_sarray) (fullsize_image[ci]); + } + (*cinfo->emethods->free_small) ((void *) fullsize_image); + (*cinfo->emethods->free_small) ((void *) fullsize_ptrs); + + /* Close up shop */ + if (cinfo->quantize_colors) + (*cinfo->methods->color_quant_term) (cinfo); +} + +#endif /* MULTISCAN_FILES_SUPPORTED */ + + +/* + * Decompression pipeline controller used for multiple-scan files + * with 2-pass color quantization. + */ + +#ifdef MULTISCAN_FILES_SUPPORTED +#ifdef QUANT_2PASS_SUPPORTED + +METHODDEF void +multi_2quant_dcontroller (decompress_info_ptr cinfo) +{ + ERREXIT(cinfo->emethods, "Not implemented yet"); +} + +#endif /* QUANT_2PASS_SUPPORTED */ +#endif /* MULTISCAN_FILES_SUPPORTED */ + + +/* + * The method selection routine for decompression pipeline controllers. + * Note that at this point we've already read the JPEG header and first SOS, + * so we can tell whether the input is one scan or not. + */ + +GLOBAL void +jseldpipeline (decompress_info_ptr cinfo) +{ + /* simplify subsequent tests on color quantization */ + if (! cinfo->quantize_colors) + cinfo->two_pass_quantize = FALSE; + + if (cinfo->comps_in_scan == cinfo->num_components) { + /* It's a single-scan file */ +#ifdef QUANT_2PASS_SUPPORTED + if (cinfo->two_pass_quantize) + cinfo->methods->d_pipeline_controller = single_2quant_dcontroller; + else +#endif + cinfo->methods->d_pipeline_controller = single_dcontroller; + } else { + /* It's a multiple-scan file */ +#ifdef MULTISCAN_FILES_SUPPORTED +#ifdef QUANT_2PASS_SUPPORTED + if (cinfo->two_pass_quantize) + cinfo->methods->d_pipeline_controller = multi_2quant_dcontroller; + else +#endif + cinfo->methods->d_pipeline_controller = multi_dcontroller; +#else + ERREXIT(cinfo->emethods, "Multiple-scan support was not compiled"); +#endif + } +} diff --git a/jdsample.c b/jdsample.c new file mode 100644 index 0000000..15dbf4f --- /dev/null +++ b/jdsample.c @@ -0,0 +1,133 @@ +/* + * jdsample.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains un-subsampling routines. + * These routines are invoked via the unsubsample and + * unsubsample_init/term methods. + */ + +#include "jinclude.h" + + +/* + * Initialize for un-subsampling a scan. + */ + +METHODDEF void +unsubsample_init (decompress_info_ptr cinfo) +{ + /* no work for now */ +} + + +/* + * Un-subsample pixel values of a single component. + * This version only handles integral sampling ratios. + */ + +METHODDEF void +unsubsample (decompress_info_ptr cinfo, int which_component, + long input_cols, int input_rows, + long output_cols, int output_rows, + JSAMPARRAY above, JSAMPARRAY input_data, JSAMPARRAY below, + JSAMPARRAY output_data) +{ + jpeg_component_info * compptr = cinfo->cur_comp_info[which_component]; + short h_expand, v_expand, h, v; + int inrow, outrow; + long incol; + JSAMPROW inptr, outptr; + JSAMPLE invalue; + + /* TEMP FOR DEBUGGING PIPELINE CONTROLLER */ + if (input_rows != compptr->v_samp_factor || + output_rows != cinfo->max_v_samp_factor || + (input_cols % compptr->h_samp_factor) != 0 || + (output_cols % cinfo->max_h_samp_factor) != 0 || + output_cols*compptr->h_samp_factor != input_cols*cinfo->max_h_samp_factor) + ERREXIT(cinfo->emethods, "Bogus unsubsample parameters"); + + h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor; + v_expand = cinfo->max_v_samp_factor / compptr->v_samp_factor; + + outrow = 0; + for (inrow = 0; inrow < input_rows; inrow++) { + for (v = 0; v < v_expand; v++) { + inptr = input_data[inrow]; + outptr = output_data[outrow++]; + for (incol = 0; incol < input_cols; incol++) { + invalue = GETJSAMPLE(*inptr++); + for (h = 0; h < h_expand; h++) { + *outptr++ = invalue; + } + } + } + } +} + + +/* + * Un-subsample pixel values of a single component. + * This version handles the special case of a full-size component. + */ + +METHODDEF void +fullsize_unsubsample (decompress_info_ptr cinfo, int which_component, + long input_cols, int input_rows, + long output_cols, int output_rows, + JSAMPARRAY above, JSAMPARRAY input_data, JSAMPARRAY below, + JSAMPARRAY output_data) +{ + if (input_cols != output_cols || input_rows != output_rows) /* DEBUG */ + ERREXIT(cinfo->emethods, "Pipeline controller messed up"); + + jcopy_sample_rows(input_data, 0, output_data, 0, output_rows, output_cols); +} + + + +/* + * Clean up after a scan. + */ + +METHODDEF void +unsubsample_term (decompress_info_ptr cinfo) +{ + /* no work for now */ +} + + + +/* + * The method selection routine for unsubsampling. + * Note that we must select a routine for each component. + */ + +GLOBAL void +jselunsubsample (decompress_info_ptr cinfo) +{ + short ci; + jpeg_component_info * compptr; + + if (cinfo->CCIR601_sampling) + ERREXIT(cinfo->emethods, "CCIR601 subsampling not implemented yet"); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + if (compptr->h_samp_factor == cinfo->max_h_samp_factor && + compptr->v_samp_factor == cinfo->max_v_samp_factor) + cinfo->methods->unsubsample[ci] = fullsize_unsubsample; + else if ((cinfo->max_h_samp_factor % compptr->h_samp_factor) == 0 && + (cinfo->max_v_samp_factor % compptr->v_samp_factor) == 0) + cinfo->methods->unsubsample[ci] = unsubsample; + else + ERREXIT(cinfo->emethods, "Fractional subsampling not implemented yet"); + } + + cinfo->methods->unsubsample_init = unsubsample_init; + cinfo->methods->unsubsample_term = unsubsample_term; +} diff --git a/jerror.c b/jerror.c new file mode 100644 index 0000000..591b185 --- /dev/null +++ b/jerror.c @@ -0,0 +1,67 @@ +/* + * jerror.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains simple error-reporting and trace-message routines. + * These are suitable for Unix-like systems and others where writing to + * stderr is the right thing to do. If the JPEG software is integrated + * into a larger application, you may well need to replace these. + * + * The error_exit() routine should not return to its caller. Within a + * larger application, you might want to have it do a longjmp() to return + * control to the outer user interface routine. This should work since + * the portable JPEG code doesn't use setjmp/longjmp. However, this won't + * release allocated memory or close temp files --- some bookkeeping would + * need to be added to the memory manager module to make that work. + * + * These routines are used by both the compression and decompression code. + */ + +#include "jinclude.h" +#ifdef __STDC__ +#include /* to declare exit() */ +#endif + + +static external_methods_ptr methods; /* saved for access to message_parm */ + + +METHODDEF void +trace_message (char *msgtext) +{ + fprintf(stderr, msgtext, + methods->message_parm[0], methods->message_parm[1], + methods->message_parm[2], methods->message_parm[3], + methods->message_parm[4], methods->message_parm[5], + methods->message_parm[6], methods->message_parm[7]); + fprintf(stderr, "\n"); +} + + +METHODDEF void +error_exit (char *msgtext) +{ + trace_message(msgtext); + exit(1); +} + + +/* + * The method selection routine for simple error handling. + * The system-dependent setup routine should call this routine + * to install the necessary method pointers in the supplied struct. + */ + +GLOBAL void +jselerror (external_methods_ptr emethods) +{ + methods = emethods; /* save struct addr for msg parm access */ + + emethods->error_exit = error_exit; + emethods->trace_message = trace_message; + + emethods->trace_level = 0; /* default = no tracing */ +} diff --git a/jfwddct.c b/jfwddct.c new file mode 100644 index 0000000..58291ac --- /dev/null +++ b/jfwddct.c @@ -0,0 +1,179 @@ +/* + * jfwddct.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the basic DCT (Discrete Cosine Transform) + * transformation subroutine. + * + * This implementation is based on Appendix A.2 of the book + * "Discrete Cosine Transform---Algorithms, Advantages, Applications" + * by K.R. Rao and P. Yip (Academic Press, Inc, London, 1990). + * It uses scaled fixed-point arithmetic instead of floating point. + */ + +#include "jinclude.h" + + +/* The poop on this scaling stuff is as follows: + * + * Most of the numbers (after multiplication by the constants) are + * (logically) shifted left by LG2_DCT_SCALE. This is undone by UNFIXH + * before assignment to the output array. Note that we want an additional + * division by 2 on the output (required by the equations). + * + * If right shifts are unsigned, then there is a potential problem. + * However, shifting right by 16 and then assigning to a short + * (assuming short = 16 bits) will keep the sign right!! + * + * For other shifts, + * + * ((x + (1 << 30)) >> shft) - (1 << (30 - shft)) + * + * gives a nice right shift with sign (assuming no overflow). However, all the + * scaling is such that this isn't a problem. (Is this true?) + */ + + +#define ONE 1L /* remove L if long > 32 bits */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define LG2_DCT_SCALE 15 +#define RIGHT_SHIFT(_x,_shft) ((((_x) + (ONE << 30)) >> (_shft)) - (ONE << (30 - (_shft)))) +#else +#define LG2_DCT_SCALE 16 +#define RIGHT_SHIFT(_x,_shft) ((_x) >> (_shft)) +#endif + +#define DCT_SCALE (ONE << LG2_DCT_SCALE) + +#define LG2_OVERSCALE 2 +#define OVERSCALE (ONE << LG2_OVERSCALE) + +#define FIX(x) ((INT32) ((x) * DCT_SCALE + 0.5)) +#define FIXO(x) ((INT32) ((x) * DCT_SCALE / OVERSCALE + 0.5)) +#define UNFIX(x) RIGHT_SHIFT((x) + (ONE << (LG2_DCT_SCALE-1)), LG2_DCT_SCALE) +#define UNFIXH(x) RIGHT_SHIFT((x) + (ONE << LG2_DCT_SCALE), LG2_DCT_SCALE+1) +#define UNFIXO(x) RIGHT_SHIFT((x) + (ONE << (LG2_DCT_SCALE-1-LG2_OVERSCALE)), LG2_DCT_SCALE-LG2_OVERSCALE) +#define OVERSH(x) ((x) << LG2_OVERSCALE) + +#define SIN_1_4 FIX(0.7071067811856476) +#define COS_1_4 SIN_1_4 + +#define SIN_1_8 FIX(0.3826834323650898) +#define COS_1_8 FIX(0.9238795325112870) +#define SIN_3_8 COS_1_8 +#define COS_3_8 SIN_1_8 + +#define SIN_1_16 FIX(0.1950903220161282) +#define COS_1_16 FIX(0.9807852804032300) +#define SIN_7_16 COS_1_16 +#define COS_7_16 SIN_1_16 + +#define SIN_3_16 FIX(0.5555702330196022) +#define COS_3_16 FIX(0.8314696123025450) +#define SIN_5_16 COS_3_16 +#define COS_5_16 SIN_3_16 + +#define OSIN_1_4 FIXO(0.707106781185647) +#define OCOS_1_4 OSIN_1_4 + +#define OSIN_1_8 FIXO(0.3826834323650898) +#define OCOS_1_8 FIXO(0.9238795325112870) +#define OSIN_3_8 OCOS_1_8 +#define OCOS_3_8 OSIN_1_8 + +#define OSIN_1_16 FIXO(0.1950903220161282) +#define OCOS_1_16 FIXO(0.9807852804032300) +#define OSIN_7_16 OCOS_1_16 +#define OCOS_7_16 OSIN_1_16 + +#define OSIN_3_16 FIXO(0.5555702330196022) +#define OCOS_3_16 FIXO(0.8314696123025450) +#define OSIN_5_16 OCOS_3_16 +#define OCOS_5_16 OSIN_3_16 + + +INLINE +LOCAL void +fast_dct_8 (DCTELEM *in, int stride) +{ + /* tmp1x are new values of tmpx -- flashy register colourers + * should be able to do this lot very well + */ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17; + INT32 tmp25, tmp26; + INT32 in0, in1, in2, in3, in4, in5, in6, in7; + + in0 = in[ 0]; + in1 = in[stride ]; + in2 = in[stride*2]; + in3 = in[stride*3]; + in4 = in[stride*4]; + in5 = in[stride*5]; + in6 = in[stride*6]; + in7 = in[stride*7]; + + tmp0 = in7 + in0; + tmp1 = in6 + in1; + tmp2 = in5 + in2; + tmp3 = in4 + in3; + tmp4 = in3 - in4; + tmp5 = in2 - in5; + tmp6 = in1 - in6; + tmp7 = in0 - in7; + + tmp10 = tmp3 + tmp0 ; + tmp11 = tmp2 + tmp1 ; + tmp12 = tmp1 - tmp2 ; + tmp13 = tmp0 - tmp3 ; + + /* Now using tmp10, tmp11, tmp12, tmp13 */ + + in[ 0] = UNFIXH((tmp10 + tmp11) * SIN_1_4); + in[stride*4] = UNFIXH((tmp10 - tmp11) * COS_1_4); + + in[stride*2] = UNFIXH(tmp13*COS_1_8 + tmp12*SIN_1_8); + in[stride*6] = UNFIXH(tmp13*SIN_1_8 - tmp12*COS_1_8); + + tmp16 = UNFIXO((tmp6 + tmp5) * SIN_1_4); + tmp15 = UNFIXO((tmp6 - tmp5) * COS_1_4); + + /* Now using tmp10, tmp11, tmp13, tmp14, tmp15, tmp16 */ + + tmp14 = OVERSH(tmp4) + tmp15; + tmp25 = OVERSH(tmp4) - tmp15; + tmp26 = OVERSH(tmp7) - tmp16; + tmp17 = OVERSH(tmp7) + tmp16; + + /* These are now overscaled by OVERSCALE */ + + /* tmp10, tmp11, tmp12, tmp13, tmp14, tmp25, tmp26, tmp17 */ + + in[stride ] = UNFIXH(tmp17*OCOS_1_16 + tmp14*OSIN_1_16); + in[stride*7] = UNFIXH(tmp17*OCOS_7_16 - tmp14*OSIN_7_16); + in[stride*5] = UNFIXH(tmp26*OCOS_5_16 + tmp25*OSIN_5_16); + in[stride*3] = UNFIXH(tmp26*OCOS_3_16 - tmp25*OSIN_3_16); +} + + +/* + * Perform the forward DCT on one block of samples. + * + * Note that this code is specialized to the case DCTSIZE = 8. + */ + +GLOBAL void +j_fwd_dct (DCTBLOCK data) +{ + int i; + + for (i = 0; i < DCTSIZE; i++) + fast_dct_8(data+i*DCTSIZE, 1); + + for (i = 0; i < DCTSIZE; i++) + fast_dct_8(data+i, DCTSIZE); +} diff --git a/jinclude.h b/jinclude.h new file mode 100644 index 0000000..ec7a7e8 --- /dev/null +++ b/jinclude.h @@ -0,0 +1,73 @@ +/* + * jinclude.h + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This is the central file that's #include'd by all the JPEG .c files. + * Its purpose is to provide a single place to fix any problems with + * including the wrong system include files. + * You can edit these declarations if you use a system with nonstandard + * system include files. + */ + + +/* + * is included to get the FILE typedef and NULL macro. + * Note that the core portable-JPEG files do not actually do any I/O + * using the stdio library; only the user interface, error handler, + * and file reading/writing modules invoke any stdio functions. + * (Well, we did cheat a bit in jvirtmem.c, but only if MEM_STATS is defined.) + */ + +#include + +/* + * We need the size_t typedef, which defines the parameter type of malloc(). + * In an ANSI-conforming implementation this is provided by , + * but on non-ANSI systems it's more likely to be in . + */ + +#ifndef __STDC__ /* shouldn't need this if __STDC__ */ +#include +#endif + +/* + * In ANSI C, and indeed any rational implementation, size_t is also the + * type returned by sizeof(). However, it seems there are some irrational + * implementations out there, in which sizeof() returns an int even though + * size_t is defined as long or unsigned long. To ensure consistent results + * we always use this SIZEOF() macro in place of using sizeof() directly. + */ + +#define SIZEOF(object) ((size_t) sizeof(object)) + +/* + * We need the memcpy() and strcmp() functions, plus memory zeroing. + * ANSI and System V implementations declare these in . + * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). + * NOTE: we assume the size parameters to these functions are of type size_t. + * Insert casts in these macros if not! + */ + +#ifdef __STDC__ +#include +#define MEMZERO(voidptr,size) memset((voidptr), 0, (size)) +#else /* not STDC */ +#ifdef BSD +#include +#define MEMZERO(voidptr,size) bzero((voidptr), (size)) +#define memcpy(dest,src,size) bcopy((src), (dest), (size)) +#else /* not BSD, assume Sys V or compatible */ +#include +#define MEMZERO(voidptr,size) memset((voidptr), 0, (size)) +#endif /* BSD */ +#endif /* STDC */ + + +/* Now include the portable JPEG definition files. */ + +#include "jconfig.h" + +#include "jpegdata.h" diff --git a/jpegdata.h b/jpegdata.h new file mode 100644 index 0000000..3e4d753 --- /dev/null +++ b/jpegdata.h @@ -0,0 +1,812 @@ +/* + * jpegdata.h + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines shared data structures for the various JPEG modules. + */ + + +/* + * You might need to change some of the following declarations if you are + * using the JPEG software within a surrounding application program + * or porting it to an unusual system. + */ + + +/* If the source or destination of image data is not to be stdio streams, + * these types may need work. You can replace them with some kind of + * pointer or indicator that is useful to you, or just ignore 'em. + * Note that the user interface and the various jrdxxx/jwrxxx modules + * will also need work for non-stdio input/output. + */ + +typedef FILE * JFILEREF; /* source or dest of JPEG-compressed data */ + +typedef FILE * IFILEREF; /* source or dest of non-JPEG image data */ + + +/* These defines are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions, + * as is shown below for use with C++. Another application would be to make + * all functions global for use with code profilers that require it. + * NOTE: the C++ test does the right thing if you are reading this include + * file in a C++ application to link to JPEG code that's been compiled with a + * regular C compiler. I'm not sure it works if you try to compile the JPEG + * code with C++. + */ + +#define METHODDEF static /* a function called through method pointers */ +#define LOCAL static /* a function used only in its module */ +#define GLOBAL /* a function referenced thru EXTERNs */ +#ifdef __cplusplus +#define EXTERN extern "C" /* a reference to a GLOBAL function */ +#else +#define EXTERN extern /* a reference to a GLOBAL function */ +#endif + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifdef NEED_FAR_POINTERS +#define FAR far +#else +#define FAR +#endif + + + +/* The remaining declarations are not system-dependent, we hope. */ + + +/* + * NOTE: if you have an ancient, strict-K&R C compiler, it may choke on the + * similarly-named fields in compress_info_struct and decompress_info_struct. + * If this happens, you can get around it by rearranging the two structs so + * that the similarly-named fields appear first and in the same order in + * each struct. Since such compilers are now pretty rare, we haven't done + * this in the portable code, preferring to maintain a logical ordering. + */ + + + +/* This macro is used to declare a "method", that is, a function pointer. */ +/* We want to supply prototype parameters if the compiler can cope. */ +/* Note that the arglist parameter must be parenthesized! */ + +#ifdef PROTO +#define METHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define METHOD(type,methodname,arglist) type (*methodname) () +#endif + +/* Forward references to lists of method pointers */ +typedef struct external_methods_struct * external_methods_ptr; +typedef struct compress_methods_struct * compress_methods_ptr; +typedef struct decompress_methods_struct * decompress_methods_ptr; + + +/* Data structures for images containing either samples or coefficients. */ +/* Note that the topmost (leftmost) index is always color component. */ +/* On 80x86 machines, the image arrays are too big for near pointers, */ +/* but the pointer arrays can fit in near memory. */ + +typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* The input and output data of the DCT transform subroutines are of + * the following type, which need not be the same as JCOEF. + * For example, on a machine with fast floating point, it might make sense + * to recode the DCT routines to use floating point; then DCTELEM would be + * 'float' or 'double'. + */ + +typedef JCOEF DCTELEM; +typedef DCTELEM DCTBLOCK[DCTSIZE2]; + + +/* Types for JPEG compression parameters and working tables. */ + + +typedef enum { /* defines known color spaces */ + CS_UNKNOWN, /* error/unspecified */ + CS_GRAYSCALE, /* monochrome (only 1 component) */ + CS_RGB, /* red/green/blue */ + CS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + CS_YIQ, /* Y/I/Q */ + CS_CMYK /* C/M/Y/K */ +} COLOR_SPACE; + + +typedef struct { /* Basic info about one component */ + /* These values are fixed over the whole image */ + /* For compression, they must be supplied by the user interface; */ + /* for decompression, they are read from the SOF marker. */ + short component_id; /* identifier for this component (0..255) */ + short component_index; /* its index in SOF or cinfo->comp_info[] */ + short h_samp_factor; /* horizontal sampling factor (1..4) */ + short v_samp_factor; /* vertical sampling factor (1..4) */ + short quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans */ + /* For compression, they must be supplied by the user interface; */ + /* for decompression, they are read from the SOS marker. */ + short dc_tbl_no; /* DC entropy table selector (0..3) */ + short ac_tbl_no; /* AC entropy table selector (0..3) */ + /* These values are computed during compression or decompression startup */ + long true_comp_width; /* component's image width in samples */ + long true_comp_height; /* component's image height in samples */ + /* the above are the logical dimensions of the subsampled image */ + /* These values are computed before starting a scan of the component */ + short MCU_width; /* number of blocks per MCU, horizontally */ + short MCU_height; /* number of blocks per MCU, vertically */ + short MCU_blocks; /* MCU_width * MCU_height */ + long subsampled_width; /* image width in samples, after expansion */ + long subsampled_height; /* image height in samples, after expansion */ + /* the above are the true_comp_xxx values rounded up to multiples of */ + /* the MCU dimensions; these are the working dimensions of the array */ + /* as it is passed through the DCT or IDCT step. NOTE: these values */ + /* differ depending on whether the component is interleaved or not!! */ +} jpeg_component_info; + + +/* DCT coefficient quantization tables. + * For 8-bit precision, 'INT16' should be good enough for quantization values; + * for more precision, we go for the full 16 bits. 'INT16' provides a useful + * speedup on many machines (multiplication & division of JCOEFs by + * quantization values is a significant chunk of the runtime). + * Note: the values in a QUANT_TBL are always given in zigzag order. + */ +#ifdef EIGHT_BIT_SAMPLES +typedef INT16 QUANT_VAL; /* element of a quantization table */ +#else +typedef UINT16 QUANT_VAL; /* element of a quantization table */ +#endif +typedef QUANT_VAL QUANT_TBL[DCTSIZE2]; /* A quantization table */ +typedef QUANT_VAL * QUANT_TBL_PTR; /* pointer to same */ + + +typedef struct { /* A Huffman coding table */ + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + */ + boolean sent_table; /* TRUE when table has been output */ + /* The remaining fields are computed from the above to allow more efficient + * coding and decoding. These fields should be considered private to the + * Huffman compression & decompression modules. + */ + UINT16 ehufco[256]; /* code for each symbol */ + char ehufsi[256]; /* length of code for each symbol */ + UINT16 mincode[17]; /* smallest code of length k */ + INT32 maxcode[17]; /* largest code of length k (-1 if none) */ + short valptr[17]; /* huffval[] index of 1st symbol of length k */ +} HUFF_TBL; + + +#define NUM_QUANT_TBLS 4 /* quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +#define MAX_BLOCKS_IN_MCU 10 /* JPEG limit on # of blocks in an MCU */ + + +/* Working data for compression */ + +struct compress_info_struct { +/* + * All of these fields shall be established by the user interface before + * calling jpeg_compress, or by the input_init or c_ui_method_selection + * methods. + * Most parameters can be set to reasonable defaults by j_default_compression. + * Note that the UI must supply the storage for the main methods struct, + * though it sets only a few of the methods there. + */ + compress_methods_ptr methods; /* Points to list of methods to use */ + + external_methods_ptr emethods; /* Points to list of methods to use */ + + IFILEREF input_file; /* tells input routines where to read image */ + JFILEREF output_file; /* tells output routines where to write JPEG */ + + long image_width; /* input image width */ + long image_height; /* input image height */ + short input_components; /* # of color components in input image */ + + short data_precision; /* bits of precision in image data */ + + COLOR_SPACE in_color_space; /* colorspace of input file */ + COLOR_SPACE jpeg_color_space; /* colorspace of JPEG file */ + + double input_gamma; /* image gamma of input file */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + /* These three values are not used by the JPEG code, only copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + + short num_components; /* # of color components in JPEG image */ + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + QUANT_TBL_PTR quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + HUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + HUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arithmetic-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arithmetic-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arithmetic-coding tables */ + + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean interleave; /* TRUE=interleaved output, FALSE=not */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + UINT16 restart_interval;/* MDUs per restart interval, or 0 for no restart */ + +/* + * These fields are computed during jpeg_compress startup + */ + short max_h_samp_factor; /* largest h_samp_factor */ + short max_v_samp_factor; /* largest v_samp_factor */ + +/* + * These fields are valid during any one scan + */ + short comps_in_scan; /* # of JPEG components output this time */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + long MCUs_per_row; /* # of MCUs across the image */ + long MCU_rows_in_scan; /* # of MCU rows in the image */ + + short blocks_in_MCU; /* # of DCT blocks per MCU */ + short MCU_membership[MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + /* these fields are private data for the entropy encoder */ + JCOEF last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each comp */ + JCOEF last_dc_diff[MAX_COMPS_IN_SCAN]; /* last DC diff for each comp */ + UINT16 restarts_to_go; /* MDUs left in this restart interval */ + short next_restart_num; /* # of next RSTn marker (0..7) */ +}; + +typedef struct compress_info_struct * compress_info_ptr; + + +/* Working data for decompression */ + +struct decompress_info_struct { +/* + * These fields shall be established by the user interface before + * calling jpeg_decompress. Note that the UI must supply the storage for + * the main methods struct, though it sets only a few of the methods there. + */ + decompress_methods_ptr methods; /* Points to list of methods to use */ + + external_methods_ptr emethods; /* Points to list of methods to use */ + + JFILEREF input_file; /* tells input routines where to read JPEG */ + IFILEREF output_file; /* tells output routines where to write image */ + + /* these can be set at d_ui_method_selection time: */ + + COLOR_SPACE out_color_space; /* colorspace of output */ + + double output_gamma; /* image gamma wanted in output */ + + boolean quantize_colors; /* T if output is a colormapped format */ + /* the following are ignored if not quantize_colors: */ + boolean two_pass_quantize; /* use two-pass color quantization? */ + boolean use_dithering; /* want color dithering? */ + int desired_number_of_colors; /* number of colors to use */ + + boolean do_block_smoothing; /* T = apply cross-block smoothing */ + boolean do_pixel_smoothing; /* T = apply post-subsampling smoothing */ + +/* + * These fields are used for efficient buffering of data between read_jpeg_data + * and the entropy decoding object. By using a shared buffer, we avoid copying + * data and eliminate the need for an "unget" operation at the end of a scan. + * The actual source of the data is known only to read_jpeg_data; see the + * JGETC macro, below. + * Note: the user interface is expected to allocate the input_buffer and + * initialize bytes_in_buffer to 0. Also, for JFIF/raw-JPEG input, the UI + * actually supplies the read_jpeg_data method. + */ + char * input_buffer; /* start of buffer (private to input code) */ + char * next_input_byte; /* => next byte to read from buffer */ + int bytes_in_buffer; /* # of bytes remaining in buffer */ + +/* + * These fields are set by read_file_header or read_scan_header + */ + long image_width; /* overall image width */ + long image_height; /* overall image height */ + + short data_precision; /* bits of precision in image data */ + + COLOR_SPACE jpeg_color_space; /* colorspace of JPEG file */ + + /* These three values are not used by the JPEG code, merely copied */ + /* from the JFIF APP0 marker (if any). */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + + short num_components; /* # of color components in JPEG image */ + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + QUANT_TBL_PTR quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + HUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + HUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + UINT16 restart_interval;/* MDUs per restart interval, or 0 for no restart */ + +/* + * These fields are computed during jpeg_decompress startup + */ + short max_h_samp_factor; /* largest h_samp_factor */ + short max_v_samp_factor; /* largest v_samp_factor */ + + short color_out_comps; /* # of color components output by color_convert */ + /* (need not match num_components) */ + short final_out_comps; /* # of color components in output image */ + /* (1 when quantizing colors, else same as color_out_comps) */ + +/* + * These fields are valid during any one scan + */ + short comps_in_scan; /* # of JPEG components input this time */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + long MCUs_per_row; /* # of MCUs across the image */ + long MCU_rows_in_scan; /* # of MCU rows in the image */ + + short blocks_in_MCU; /* # of DCT blocks per MCU */ + short MCU_membership[MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + /* these fields are private data for the entropy encoder */ + JCOEF last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each comp */ + JCOEF last_dc_diff[MAX_COMPS_IN_SCAN]; /* last DC diff for each comp */ + UINT16 restarts_to_go; /* MDUs left in this restart interval */ + short next_restart_num; /* # of next RSTn marker (0..7) */ +}; + +typedef struct decompress_info_struct * decompress_info_ptr; + + +/* Macros for reading data from the decompression input buffer */ + +#ifdef CHAR_IS_UNSIGNED +#define JGETC(cinfo) ( --(cinfo)->bytes_in_buffer < 0 ? \ + (*(cinfo)->methods->read_jpeg_data) (cinfo) : \ + (int) *(cinfo)->next_input_byte++ ) +#else +#define JGETC(cinfo) ( --(cinfo)->bytes_in_buffer < 0 ? \ + (*(cinfo)->methods->read_jpeg_data) (cinfo) : \ + (int) (*(cinfo)->next_input_byte++) & 0xFF ) +#endif + +#define JUNGETC(ch,cinfo) ((cinfo)->bytes_in_buffer++, \ + *(--((cinfo)->next_input_byte)) = (ch)) + +#define MIN_UNGET 2 /* may always do at least 2 JUNGETCs */ + + +/* A virtual image has a control block whose contents are private to the + * memory manager module (and may differ between managers). The rest of the + * code only refers to virtual images by these pointer types. + */ + +typedef struct big_sarray_control * big_sarray_ptr; +typedef struct big_barray_control * big_barray_ptr; + + +/* Method types that need typedefs */ + +typedef METHOD(void, MCU_output_method_ptr, (compress_info_ptr cinfo, + JBLOCK *MCU_data)); +typedef METHOD(void, MCU_output_caller_ptr, (compress_info_ptr cinfo, + MCU_output_method_ptr output_method)); +typedef METHOD(void, subsample_ptr, (compress_info_ptr cinfo, + int which_component, + long input_cols, int input_rows, + long output_cols, int output_rows, + JSAMPARRAY above, + JSAMPARRAY input_data, + JSAMPARRAY below, + JSAMPARRAY output_data)); +typedef METHOD(void, unsubsample_ptr, (decompress_info_ptr cinfo, + int which_component, + long input_cols, int input_rows, + long output_cols, int output_rows, + JSAMPARRAY above, + JSAMPARRAY input_data, + JSAMPARRAY below, + JSAMPARRAY output_data)); +typedef METHOD(void, quantize_method_ptr, (decompress_info_ptr cinfo, + int num_rows, + JSAMPIMAGE input_data, + JSAMPARRAY output_workspace)); +typedef METHOD(void, quantize_caller_ptr, (decompress_info_ptr cinfo, + quantize_method_ptr quantize_method)); + + +/* These structs contain function pointers for the various JPEG methods. */ + +/* Routines to be provided by the surrounding application, rather than the + * portable JPEG code proper. These are the same for compression and + * decompression. + */ + +struct external_methods_struct { + /* User interface: error exit and trace message routines */ + /* NOTE: the string msgtext parameters will eventually be replaced */ + /* by an enumerated-type code so that non-English error messages */ + /* can be substituted easily. This will not be done until all the */ + /* code is in place, so that we know what messages are needed. */ + METHOD(void, error_exit, (char *msgtext)); + METHOD(void, trace_message, (char *msgtext)); + + /* Working data for error/trace facility */ + /* See macros below for the usage of these variables */ + int trace_level; /* level of detail of tracing messages */ + /* Use level 0 for unsuppressable messages (nonfatal errors) */ + /* Use levels 1, 2, 3 for successively more detailed trace options */ + + int message_parm[8]; /* store numeric parms for messages here */ + + /* Memory management */ + /* NB: alloc routines never return NULL. They exit to */ + /* error_exit if not successful. */ + METHOD(void *, alloc_small, (size_t sizeofobject)); + METHOD(void, free_small, (void *ptr)); +#ifdef NEED_FAR_POINTERS /* routines for getting far-heap space */ + METHOD(void FAR *, alloc_medium, (size_t sizeofobject)); + METHOD(void, free_medium, (void FAR *ptr)); +#else +#define alloc_medium alloc_small +#define free_medium free_small +#endif + METHOD(JSAMPARRAY, alloc_small_sarray, (long samplesperrow, + long numrows)); + METHOD(void, free_small_sarray, (JSAMPARRAY ptr, + long numrows)); + METHOD(JBLOCKARRAY, alloc_small_barray, (long blocksperrow, + long numrows)); + METHOD(void, free_small_barray, (JBLOCKARRAY ptr, + long numrows)); + METHOD(big_sarray_ptr, request_big_sarray, (long samplesperrow, + long numrows, + long unitheight)); + METHOD(big_barray_ptr, request_big_barray, (long blocksperrow, + long numrows, + long unitheight)); + METHOD(void, alloc_big_arrays, (long extra_small_samples, + long extra_small_blocks, + long extra_medium_space)); + METHOD(JSAMPARRAY, access_big_sarray, (big_sarray_ptr ptr, + long start_row, + boolean writable)); + METHOD(JBLOCKARRAY, access_big_barray, (big_barray_ptr ptr, + long start_row, + boolean writable)); + METHOD(void, free_big_sarray, (big_sarray_ptr ptr)); + METHOD(void, free_big_barray, (big_barray_ptr ptr)); +}; + +/* Macros to simplify using the error and trace message stuff */ +/* The first parameter is generally cinfo->emethods */ + +#define ERREXIT(emeth,msg) ((*(emeth)->error_exit) (msg)) +#define ERREXIT1(emeth,msg,p1) ((emeth)->message_parm[0] = (p1), \ + (*(emeth)->error_exit) (msg)) +#define ERREXIT2(emeth,msg,p1,p2) ((emeth)->message_parm[0] = (p1), \ + (emeth)->message_parm[1] = (p2), \ + (*(emeth)->error_exit) (msg)) +#define ERREXIT3(emeth,msg,p1,p2,p3) ((emeth)->message_parm[0] = (p1), \ + (emeth)->message_parm[1] = (p2), \ + (emeth)->message_parm[2] = (p3), \ + (*(emeth)->error_exit) (msg)) +#define ERREXIT4(emeth,msg,p1,p2,p3,p4) ((emeth)->message_parm[0] = (p1), \ + (emeth)->message_parm[1] = (p2), \ + (emeth)->message_parm[2] = (p3), \ + (emeth)->message_parm[3] = (p4), \ + (*(emeth)->error_exit) (msg)) + +#define TRACEMS(emeth,lvl,msg) \ + ( (emeth)->trace_level >= (lvl) ? \ + ((*(emeth)->trace_message) (msg), 0) : 0) +#define TRACEMS1(emeth,lvl,msg,p1) \ + ( (emeth)->trace_level >= (lvl) ? \ + ((emeth)->message_parm[0] = (p1), \ + (*(emeth)->trace_message) (msg), 0) : 0) +#define TRACEMS2(emeth,lvl,msg,p1,p2) \ + ( (emeth)->trace_level >= (lvl) ? \ + ((emeth)->message_parm[0] = (p1), \ + (emeth)->message_parm[1] = (p2), \ + (*(emeth)->trace_message) (msg), 0) : 0) +#define TRACEMS3(emeth,lvl,msg,p1,p2,p3) \ + ( (emeth)->trace_level >= (lvl) ? \ + ((emeth)->message_parm[0] = (p1), \ + (emeth)->message_parm[1] = (p2), \ + (emeth)->message_parm[2] = (p3), \ + (*(emeth)->trace_message) (msg), 0) : 0) +#define TRACEMS4(emeth,lvl,msg,p1,p2,p3,p4) \ + ( (emeth)->trace_level >= (lvl) ? \ + ((emeth)->message_parm[0] = (p1), \ + (emeth)->message_parm[1] = (p2), \ + (emeth)->message_parm[2] = (p3), \ + (emeth)->message_parm[3] = (p4), \ + (*(emeth)->trace_message) (msg), 0) : 0) +#define TRACEMS8(emeth,lvl,msg,p1,p2,p3,p4,p5,p6,p7,p8) \ + ( (emeth)->trace_level >= (lvl) ? \ + ((emeth)->message_parm[0] = (p1), \ + (emeth)->message_parm[1] = (p2), \ + (emeth)->message_parm[2] = (p3), \ + (emeth)->message_parm[3] = (p4), \ + (emeth)->message_parm[4] = (p5), \ + (emeth)->message_parm[5] = (p6), \ + (emeth)->message_parm[6] = (p7), \ + (emeth)->message_parm[7] = (p8), \ + (*(emeth)->trace_message) (msg), 0) : 0) + + +/* Methods used during JPEG compression. */ + +struct compress_methods_struct { + /* Hook for user interface to get control after input_init */ + METHOD(void, c_ui_method_selection, (compress_info_ptr cinfo)); + /* Input image reading & conversion to standard form */ + METHOD(void, input_init, (compress_info_ptr cinfo)); + METHOD(void, get_input_row, (compress_info_ptr cinfo, + JSAMPARRAY pixel_row)); + METHOD(void, input_term, (compress_info_ptr cinfo)); + /* Gamma and color space conversion */ + METHOD(void, colorin_init, (compress_info_ptr cinfo)); + METHOD(void, get_sample_rows, (compress_info_ptr cinfo, + int rows_to_read, + JSAMPIMAGE image_data)); + METHOD(void, colorin_term, (compress_info_ptr cinfo)); + /* Expand picture data at edges */ + METHOD(void, edge_expand, (compress_info_ptr cinfo, + long input_cols, int input_rows, + long output_cols, int output_rows, + JSAMPIMAGE image_data)); + /* Subsample pixel values of a single component */ + /* There can be a different subsample method for each component */ + METHOD(void, subsample_init, (compress_info_ptr cinfo)); + subsample_ptr subsample[MAX_COMPS_IN_SCAN]; + METHOD(void, subsample_term, (compress_info_ptr cinfo)); + /* Extract samples in MCU order, process & hand off to output_method */ + /* The input is always exactly N MCU rows worth of data */ + METHOD(void, extract_init, (compress_info_ptr cinfo)); + METHOD(void, extract_MCUs, (compress_info_ptr cinfo, + JSAMPIMAGE image_data, + int num_mcu_rows, + MCU_output_method_ptr output_method)); + METHOD(void, extract_term, (compress_info_ptr cinfo)); + /* Entropy encoding parameter optimization */ + METHOD(void, entropy_optimize, (compress_info_ptr cinfo, + MCU_output_caller_ptr source_method)); + /* Entropy encoding */ + METHOD(void, entropy_encoder_init, (compress_info_ptr cinfo)); + METHOD(void, entropy_encode, (compress_info_ptr cinfo, + JBLOCK *MCU_data)); + METHOD(void, entropy_encoder_term, (compress_info_ptr cinfo)); + /* JPEG file header construction */ + METHOD(void, write_file_header, (compress_info_ptr cinfo)); + METHOD(void, write_scan_header, (compress_info_ptr cinfo)); + METHOD(void, write_jpeg_data, (compress_info_ptr cinfo, + char *dataptr, + int datacount)); + METHOD(void, write_scan_trailer, (compress_info_ptr cinfo)); + METHOD(void, write_file_trailer, (compress_info_ptr cinfo)); + /* Pipeline control */ + METHOD(void, c_pipeline_controller, (compress_info_ptr cinfo)); + METHOD(void, entropy_output, (compress_info_ptr cinfo, + char *dataptr, + int datacount)); + /* Overall control */ + METHOD(void, c_per_scan_method_selection, (compress_info_ptr cinfo)); +}; + +/* Methods used during JPEG decompression. */ + +struct decompress_methods_struct { + /* Hook for user interface to get control after reading file header */ + METHOD(void, d_ui_method_selection, (decompress_info_ptr cinfo)); + /* JPEG file scanning */ + /* Note: user interface supplies read_jpeg_data for JFIF/raw-JPEG + * reading. For file formats that require random access (eg, TIFF) + * the JPEG file header module will override the UI read_jpeg_data. + */ + METHOD(void, read_file_header, (decompress_info_ptr cinfo)); + METHOD(boolean, read_scan_header, (decompress_info_ptr cinfo)); + METHOD(int, read_jpeg_data, (decompress_info_ptr cinfo)); + METHOD(void, read_scan_trailer, (decompress_info_ptr cinfo)); + METHOD(void, read_file_trailer, (decompress_info_ptr cinfo)); + /* Entropy decoding */ + METHOD(void, entropy_decoder_init, (decompress_info_ptr cinfo)); + METHOD(void, entropy_decode, (decompress_info_ptr cinfo, + JBLOCK *MCU_data)); + METHOD(void, entropy_decoder_term, (decompress_info_ptr cinfo)); + /* MCU disassembly: fetch MCUs from entropy_decode, build coef array */ + METHOD(void, disassemble_init, (decompress_info_ptr cinfo)); + METHOD(void, disassemble_MCU, (decompress_info_ptr cinfo, + JBLOCKIMAGE image_data)); + METHOD(void, disassemble_term, (decompress_info_ptr cinfo)); + /* Cross-block smoothing */ + METHOD(void, smooth_coefficients, (decompress_info_ptr cinfo, + jpeg_component_info *compptr, + JBLOCKROW above, + JBLOCKROW currow, + JBLOCKROW below, + JBLOCKROW output)); + /* Un-subsample pixel values of a single component */ + /* There can be a different unsubsample method for each component */ + METHOD(void, unsubsample_init, (decompress_info_ptr cinfo)); + unsubsample_ptr unsubsample[MAX_COMPS_IN_SCAN]; + METHOD(void, unsubsample_term, (decompress_info_ptr cinfo)); + /* Gamma and color space conversion */ + METHOD(void, colorout_init, (decompress_info_ptr cinfo)); + METHOD(void, color_convert, (decompress_info_ptr cinfo, + int num_rows, + JSAMPIMAGE input_data, + JSAMPIMAGE output_data)); + METHOD(void, colorout_term, (decompress_info_ptr cinfo)); + /* Color quantization */ + METHOD(void, color_quant_init, (decompress_info_ptr cinfo)); + METHOD(void, color_quantize, (decompress_info_ptr cinfo, + int num_rows, + JSAMPIMAGE input_data, + JSAMPARRAY output_data)); + METHOD(void, color_quant_prescan, (decompress_info_ptr cinfo, + int num_rows, + JSAMPIMAGE image_data)); + METHOD(void, color_quant_doit, (decompress_info_ptr cinfo, + quantize_caller_ptr source_method)); + METHOD(void, color_quant_term, (decompress_info_ptr cinfo)); + /* Output image writing */ + METHOD(void, output_init, (decompress_info_ptr cinfo)); + METHOD(void, put_color_map, (decompress_info_ptr cinfo, + int num_colors, JSAMPARRAY colormap)); + METHOD(void, put_pixel_rows, (decompress_info_ptr cinfo, + int num_rows, + JSAMPIMAGE pixel_data)); + METHOD(void, output_term, (decompress_info_ptr cinfo)); + /* Pipeline control */ + METHOD(void, d_pipeline_controller, (decompress_info_ptr cinfo)); + /* Overall control */ + METHOD(void, d_per_scan_method_selection, (decompress_info_ptr cinfo)); +}; + + +/* External declarations for routines that aren't called via method ptrs. */ +/* Note: use "j" as first char of names to minimize namespace pollution. */ +/* The PP macro hides prototype parameters from compilers that can't cope. */ + +#ifdef PROTO +#define PP(arglist) arglist +#else +#define PP(arglist) () +#endif + + +/* main entry for compression */ +EXTERN void jpeg_compress PP((compress_info_ptr cinfo)); +/* default parameter setup for compression */ +EXTERN void j_default_compression PP((compress_info_ptr cinfo, int quality)); +EXTERN void j_monochrome_default PP((compress_info_ptr cinfo)); +EXTERN void j_set_quality PP((compress_info_ptr cinfo, int quality, + boolean force_baseline)); +EXTERN void j_free_defaults PP((compress_info_ptr cinfo)); + +/* main entry for decompression */ +EXTERN void jpeg_decompress PP((decompress_info_ptr cinfo)); + +/* forward DCT */ +EXTERN void j_fwd_dct PP((DCTBLOCK data)); +/* inverse DCT */ +EXTERN void j_rev_dct PP((DCTBLOCK data)); + +/* utility routines in jutils.c */ +EXTERN long jround_up PP((long a, long b)); +EXTERN void jcopy_sample_rows PP((JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, long num_cols)); +EXTERN void jcopy_block_row PP((JBLOCKROW input_row, JBLOCKROW output_row, + long num_blocks)); +EXTERN void jzero_far PP((void FAR * target, size_t bytestozero)); + +/* method selection routines for compression modules */ +EXTERN void jselcpipeline PP((compress_info_ptr cinfo)); /* jcpipe.c */ +EXTERN void jselchuffman PP((compress_info_ptr cinfo)); /* jchuff.c */ +EXTERN void jselcarithmetic PP((compress_info_ptr cinfo)); /* jcarith.c */ +EXTERN void jselexpand PP((compress_info_ptr cinfo)); /* jcexpand.c */ +EXTERN void jselsubsample PP((compress_info_ptr cinfo)); /* jcsample.c */ +EXTERN void jselcmcu PP((compress_info_ptr cinfo)); /* jcmcu.c */ +EXTERN void jselccolor PP((compress_info_ptr cinfo)); /* jccolor.c */ +/* The user interface should call one of these to select input format: */ +EXTERN void jselrgif PP((compress_info_ptr cinfo)); /* jrdgif.c */ +EXTERN void jselrppm PP((compress_info_ptr cinfo)); /* jrdppm.c */ +/* and one of these to select output header format: */ +EXTERN void jselwjfif PP((compress_info_ptr cinfo)); /* jwrjfif.c */ + +/* method selection routines for decompression modules */ +EXTERN void jseldpipeline PP((decompress_info_ptr cinfo)); /* jdpipe.c */ +EXTERN void jseldhuffman PP((decompress_info_ptr cinfo)); /* jdhuff.c */ +EXTERN void jseldarithmetic PP((decompress_info_ptr cinfo)); /* jdarith.c */ +EXTERN void jseldmcu PP((decompress_info_ptr cinfo)); /* jdmcu.c */ +EXTERN void jselbsmooth PP((decompress_info_ptr cinfo)); /* jbsmooth.c */ +EXTERN void jselunsubsample PP((decompress_info_ptr cinfo)); /* jdsample.c */ +EXTERN void jseldcolor PP((decompress_info_ptr cinfo)); /* jdcolor.c */ +EXTERN void jsel1quantize PP((decompress_info_ptr cinfo)); /* jquant1.c */ +EXTERN void jsel2quantize PP((decompress_info_ptr cinfo)); /* jquant2.c */ +/* The user interface should call one of these to select input format: */ +EXTERN void jselrjfif PP((decompress_info_ptr cinfo)); /* jrdjfif.c */ +/* and one of these to select output image format: */ +EXTERN void jselwgif PP((decompress_info_ptr cinfo)); /* jwrgif.c */ +EXTERN void jselwppm PP((decompress_info_ptr cinfo)); /* jwrppm.c */ + +/* method selection routines for system-dependent modules */ +EXTERN void jselerror PP((external_methods_ptr emethods)); /* jerror.c */ +EXTERN void jselvirtmem PP((external_methods_ptr emethods)); /* jvirtmem.c */ + +/* debugging hook in jvirtmem.c */ +#ifdef MEM_STATS +EXTERN void j_mem_stats PP((void)); +#endif + +/* Miscellaneous useful macros */ + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + + +#define RST0 0xD0 /* RST0 marker code */ diff --git a/jquant1.c b/jquant1.c new file mode 100644 index 0000000..49dfd97 --- /dev/null +++ b/jquant1.c @@ -0,0 +1,387 @@ +/* + * jquant1.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 1-pass color quantization (color mapping) routines. + * These routines are invoked via the methods color_quantize + * and color_quant_init/term. + */ + +#include "jinclude.h" + +#ifdef QUANT_1PASS_SUPPORTED + + +/* + * This implementation is a fairly dumb, quick-and-dirty quantizer; + * it's here mostly so that we can start working on colormapped output formats. + * + * We quantize to a color map that is selected in advance of seeing the image; + * the map depends only on the requested number of colors (at least 8). + * The map consists of all combinations of Ncolors[j] color values for each + * component j; we choose Ncolors[] based on the requested # of colors. + * We always use 0 and MAXJSAMPLE in each color (hence the minimum 8 colors). + * Any additional color values are equally spaced between these limits. + * + * The result almost always needs dithering to look decent. + */ + +#define MAX_COMPONENTS 4 /* max components I can handle */ + +static int total_colors; /* Number of distinct output colors */ +static int Ncolors[MAX_COMPONENTS]; /* # of values alloced to each component */ +/* total_colors is the product of the Ncolors[] values */ + +static JSAMPARRAY colormap; /* The actual color map */ +/* colormap[i][j] = value of i'th color component for output pixel value j */ + +static JSAMPARRAY colorindex; /* Precomputed mapping for speed */ +/* colorindex[i][j] = index of color closest to pixel value j in component i, + * premultiplied so that the correct mapped value for a pixel (r,g,b) is: + * colorindex[0][r] + colorindex[1][g] + colorindex[2][b] + */ + + +/* Declarations for Floyd-Steinberg dithering. + * Errors are accumulated into the arrays evenrowerrs[] and oddrowerrs[], + * each of which have #colors * (#columns + 2) entries (so that first/last + * pixels need not be special cases). These have resolutions of 1/16th of + * a pixel count. The error at a given pixel is propagated to its unprocessed + * neighbors using the standard F-S fractions, + * ... (here) 7/16 + * 3/16 5/16 1/16 + * We work left-to-right on even rows, right-to-left on odd rows. + * + * Note: on a wide image, we might not have enough room in a PC's near data + * segment to hold the error arrays; so they are allocated with alloc_medium. + */ + +#ifdef EIGHT_BIT_SAMPLES +typedef short FSERROR; /* 16 bits should be enough */ +#else +typedef INT32 FSERROR; /* may need more than 16 bits? */ +#endif + +typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */ + +static FSERRPTR evenrowerrs, oddrowerrs; /* current-row and next-row errors */ +static boolean on_odd_row; /* flag to remember which row we are on */ + + +/* + * Initialize for one-pass color quantization. + */ + +METHODDEF void +color_quant_init (decompress_info_ptr cinfo) +{ + int max_colors = cinfo->desired_number_of_colors; + int i,j,k, ntc, nci, blksize, blkdist, ptr, val; + + if (cinfo->color_out_comps > MAX_COMPONENTS) + ERREXIT1(cinfo->emethods, "Cannot quantize more than %d color components", + MAX_COMPONENTS); + if (max_colors > (MAXJSAMPLE+1)) + ERREXIT1(cinfo->emethods, "Cannot request more than %d quantized colors", + MAXJSAMPLE+1); + + /* Initialize to 2 color values for each component */ + total_colors = 1; + for (i = 0; i < cinfo->color_out_comps; i++) { + Ncolors[i] = 2; + total_colors *= 2; + } + if (total_colors > max_colors) + ERREXIT1(cinfo->emethods, "Cannot quantize to fewer than %d colors", + total_colors); + + /* Increase the number of color values until requested limit is reached. */ + /* Note that for standard RGB color space, we will have at least as many */ + /* red values as green, and at least as many green values as blue. */ + i = 0; /* component index to increase next */ + /* test calculates ntc = new total_colors if Ncolors[i] is incremented */ + while ((ntc = (total_colors / Ncolors[i]) * (Ncolors[i]+1)) <= max_colors) { + Ncolors[i]++; /* OK, apply the increment */ + total_colors = ntc; + i++; /* advance to next component */ + if (i >= cinfo->color_out_comps) i = 0; + } + + /* Report selected color counts */ + if (cinfo->color_out_comps == 3) + TRACEMS4(cinfo->emethods, 1, "Quantizing to %d = %d*%d*%d colors", + total_colors, Ncolors[0], Ncolors[1], Ncolors[2]); + else + TRACEMS1(cinfo->emethods, 1, "Quantizing to %d colors", total_colors); + + /* Allocate and fill in the colormap and color index. */ + /* The colors are ordered in the map in standard row-major order, */ + /* i.e. rightmost (highest-indexed) color changes most rapidly. */ + + colormap = (*cinfo->emethods->alloc_small_sarray) + ((long) total_colors, (long) cinfo->color_out_comps); + colorindex = (*cinfo->emethods->alloc_small_sarray) + ((long) (MAXJSAMPLE+1), (long) cinfo->color_out_comps); + + /* blksize is number of adjacent repeated entries for a component */ + /* blkdist is distance between groups of identical entries for a component */ + blkdist = total_colors; + + for (i = 0; i < cinfo->color_out_comps; i++) { + /* fill in colormap entries for i'th color component */ + nci = Ncolors[i]; /* # of distinct values for this color */ + blksize = blkdist / nci; + for (j = 0; j < nci; j++) { + val = (j * MAXJSAMPLE + (nci-1)/2) / (nci-1); /* j'th value of color */ + for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) { + /* fill in blksize entries beginning at ptr */ + for (k = 0; k < blksize; k++) + colormap[i][ptr+k] = val; + } + } + blkdist = blksize; /* blksize of this color is blkdist of next */ + + /* fill in colorindex entries for i'th color component */ + for (j = 0; j <= MAXJSAMPLE; j++) { + /* compute index of color closest to pixel value j */ + val = (j * (nci-1) + CENTERJSAMPLE) / MAXJSAMPLE; + /* premultiply so that no multiplication needed in main processing */ + val *= blksize; + colorindex[i][j] = val; + } + } + + /* Pass the colormap to the output module. Note that the output */ + /* module is allowed to save this pointer and use the map during */ + /* any put_pixel_rows call! */ + (*cinfo->methods->put_color_map) (cinfo, total_colors, colormap); + + /* Allocate Floyd-Steinberg workspace if necessary */ + if (cinfo->use_dithering) { + size_t arraysize = (cinfo->image_width + 2L) * cinfo->color_out_comps + * SIZEOF(FSERROR); + + evenrowerrs = (FSERRPTR) (*cinfo->emethods->alloc_medium) (arraysize); + oddrowerrs = (FSERRPTR) (*cinfo->emethods->alloc_medium) (arraysize); + /* we only need to zero the forward contribution for current row. */ + jzero_far((void FAR *) evenrowerrs, arraysize); + on_odd_row = FALSE; + } + +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +METHODDEF void +color_quantize (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE input_data, JSAMPARRAY output_data) +/* General case, no dithering */ +{ + register int pixcode, ci; + register long col; + register int row; + register long widthm1 = cinfo->image_width - 1; + register int nc = cinfo->color_out_comps; + + for (row = 0; row < num_rows; row++) { + for (col = widthm1; col >= 0; col--) { + pixcode = 0; + for (ci = 0; ci < nc; ci++) { + pixcode += GETJSAMPLE(colorindex[ci] + [GETJSAMPLE(input_data[ci][row][col])]); + } + output_data[row][col] = pixcode; + } + } +} + + +METHODDEF void +color_quantize3 (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE input_data, JSAMPARRAY output_data) +/* Fast path for color_out_comps==3, no dithering */ +{ + register int pixcode; + register JSAMPROW ptr0, ptr1, ptr2, ptrout; + register long col; + register int row; + register long width = cinfo->image_width; + + for (row = 0; row < num_rows; row++) { + ptr0 = input_data[0][row]; + ptr1 = input_data[1][row]; + ptr2 = input_data[2][row]; + ptrout = output_data[row]; + for (col = width; col > 0; col--) { + pixcode = GETJSAMPLE(colorindex[0][GETJSAMPLE(*ptr0++)]); + pixcode += GETJSAMPLE(colorindex[1][GETJSAMPLE(*ptr1++)]); + pixcode += GETJSAMPLE(colorindex[2][GETJSAMPLE(*ptr2++)]); + *ptrout++ = pixcode; + } + } +} + + +METHODDEF void +color_quantize_dither (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE input_data, JSAMPARRAY output_data) +/* General case, with Floyd-Steinberg dithering */ +{ + register int pixcode, ci; + register FSERROR val; + register FSERRPTR thisrowerr, nextrowerr; + register long col; + register int row; + register long width = cinfo->image_width; + register int nc = cinfo->color_out_comps; + + for (row = 0; row < num_rows; row++) { + if (on_odd_row) { + /* work right to left in this row */ + thisrowerr = oddrowerrs + width*nc; + nextrowerr = evenrowerrs + width*nc; + for (ci = 0; ci < nc; ci++) /* need only initialize this one entry */ + nextrowerr[ci] = 0; + for (col = width - 1; col >= 0; col--) { + /* select the output pixel value */ + pixcode = 0; + for (ci = 0; ci < nc; ci++) { + /* compute pixel value + accumulated error */ + val = (((FSERROR) GETJSAMPLE(input_data[ci][row][col])) << 4) + + thisrowerr[ci]; + if (val < 0) val = 0; /* must watch for range overflow! */ + else { + val += 8; /* divide by 16 with proper rounding */ + val >>= 4; + if (val > MAXJSAMPLE) val = MAXJSAMPLE; + } + thisrowerr[ci] = val; /* save for error propagation */ + pixcode += GETJSAMPLE(colorindex[ci][val]); + } + output_data[row][col] = pixcode; + /* propagate error to adjacent pixels */ + for (ci = 0; ci < nc; ci++) { + val = thisrowerr[ci] - GETJSAMPLE(colormap[ci][pixcode]); + thisrowerr[ci-nc] += val * 7; + nextrowerr[ci+nc] += val * 3; + nextrowerr[ci ] += val * 5; + nextrowerr[ci-nc] = val; /* not +=, since not initialized yet */ + } + thisrowerr -= nc; /* advance error ptrs to next pixel entry */ + nextrowerr -= nc; + } + on_odd_row = FALSE; + } else { + /* work left to right in this row */ + thisrowerr = evenrowerrs + nc; + nextrowerr = oddrowerrs + nc; + for (ci = 0; ci < nc; ci++) /* need only initialize this one entry */ + nextrowerr[ci] = 0; + for (col = 0; col < width; col++) { + /* select the output pixel value */ + pixcode = 0; + for (ci = 0; ci < nc; ci++) { + /* compute pixel value + accumulated error */ + val = (((FSERROR) GETJSAMPLE(input_data[ci][row][col])) << 4) + + thisrowerr[ci]; + if (val < 0) val = 0; /* must watch for range overflow! */ + else { + val += 8; /* divide by 16 with proper rounding */ + val >>= 4; + if (val > MAXJSAMPLE) val = MAXJSAMPLE; + } + thisrowerr[ci] = val; /* save for error propagation */ + pixcode += GETJSAMPLE(colorindex[ci][val]); + } + output_data[row][col] = pixcode; + /* propagate error to adjacent pixels */ + for (ci = 0; ci < nc; ci++) { + val = thisrowerr[ci] - GETJSAMPLE(colormap[ci][pixcode]); + thisrowerr[ci+nc] += val * 7; + nextrowerr[ci-nc] += val * 3; + nextrowerr[ci ] += val * 5; + nextrowerr[ci+nc] = val; /* not +=, since not initialized yet */ + } + thisrowerr += nc; /* advance error ptrs to next pixel entry */ + nextrowerr += nc; + } + on_odd_row = TRUE; + } + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +color_quant_term (decompress_info_ptr cinfo) +{ + /* We can't free the colormap until now, since output module may use it! */ + (*cinfo->emethods->free_small_sarray) + (colormap, (long) cinfo->color_out_comps); + (*cinfo->emethods->free_small_sarray) + (colorindex, (long) cinfo->color_out_comps); + if (cinfo->use_dithering) { + (*cinfo->emethods->free_medium) ((void FAR *) evenrowerrs); + (*cinfo->emethods->free_medium) ((void FAR *) oddrowerrs); + } +} + + +/* + * Prescan some rows of pixels. + * Not used in one-pass case. + */ + +METHODDEF void +color_quant_prescan (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE image_data) +{ + ERREXIT(cinfo->emethods, "Should not get here!"); +} + + +/* + * Do two-pass quantization. + * Not used in one-pass case. + */ + +METHODDEF void +color_quant_doit (decompress_info_ptr cinfo, quantize_caller_ptr source_method) +{ + ERREXIT(cinfo->emethods, "Should not get here!"); +} + + +/* + * The method selection routine for 1-pass color quantization. + */ + +GLOBAL void +jsel1quantize (decompress_info_ptr cinfo) +{ + if (! cinfo->two_pass_quantize) { + cinfo->methods->color_quant_init = color_quant_init; + if (cinfo->use_dithering) { + cinfo->methods->color_quantize = color_quantize_dither; + } else { + if (cinfo->color_out_comps == 3) + cinfo->methods->color_quantize = color_quantize3; + else + cinfo->methods->color_quantize = color_quantize; + } + cinfo->methods->color_quant_prescan = color_quant_prescan; + cinfo->methods->color_quant_doit = color_quant_doit; + cinfo->methods->color_quant_term = color_quant_term; + } +} + +#endif /* QUANT_1PASS_SUPPORTED */ diff --git a/jquant2.c b/jquant2.c new file mode 100644 index 0000000..2569b20 --- /dev/null +++ b/jquant2.c @@ -0,0 +1,122 @@ +/* + * jquant2.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 2-pass color quantization (color mapping) routines. + * These routines are invoked via the methods color_quant_prescan, + * color_quant_doit, and color_quant_init/term. + */ + +#include "jinclude.h" + +#ifdef QUANT_2PASS_SUPPORTED + + +/* + * Initialize for two-pass color quantization. + */ + +METHODDEF void +color_quant_init (decompress_info_ptr cinfo) +{ + TRACEMS(cinfo->emethods, 1, "color_quant_init 2 pass"); +} + + +/* + * Prescan some rows of pixels. + * Note: this could change the data being written into the big image array, + * if there were any benefit to doing so. The doit routine is not allowed + * to modify the big image array, because the memory manager is not required + * to support multiple write passes on a big image. + */ + +METHODDEF void +color_quant_prescan (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE image_data) +{ + TRACEMS1(cinfo->emethods, 2, "color_quant_prescan %d rows", num_rows); +} + + +/* + * This routine makes the final pass over the image data. + * output_workspace is a one-component array of pixel dimensions at least + * as large as the input image strip; it can be used to hold the converted + * pixels' colormap indexes. + */ + +METHODDEF void +final_pass (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE image_data, JSAMPARRAY output_workspace) +{ + TRACEMS1(cinfo->emethods, 2, "final_pass %d rows", num_rows); + /* for debug purposes, just emit input data */ + /* NB: this only works for PPM output */ + (*cinfo->methods->put_pixel_rows) (cinfo, num_rows, image_data); +} + + +/* + * Perform two-pass quantization: rescan the image data and output the + * converted data via put_color_map and put_pixel_rows. + * The source_method is a routine that can scan the image data; it can + * be called as many times as desired. The processing routine called by + * source_method has the same interface as color_quantize does in the + * one-pass case, except it must call put_pixel_rows itself. (This allows + * me to use multiple passes in which earlier passes don't output anything.) + */ + +METHODDEF void +color_quant_doit (decompress_info_ptr cinfo, quantize_caller_ptr source_method) +{ + TRACEMS(cinfo->emethods, 1, "color_quant_doit 2 pass"); + (*source_method) (cinfo, final_pass); +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +color_quant_term (decompress_info_ptr cinfo) +{ + TRACEMS(cinfo->emethods, 1, "color_quant_term 2 pass"); +} + + +/* + * Map some rows of pixels to the output colormapped representation. + * Not used in two-pass case. + */ + +METHODDEF void +color_quantize (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE input_data, JSAMPARRAY output_data) +{ + ERREXIT(cinfo->emethods, "Should not get here!"); +} + + +/* + * The method selection routine for 2-pass color quantization. + */ + +GLOBAL void +jsel2quantize (decompress_info_ptr cinfo) +{ + if (cinfo->two_pass_quantize) { + /* just one alternative for the moment */ + cinfo->methods->color_quant_init = color_quant_init; + cinfo->methods->color_quant_prescan = color_quant_prescan; + cinfo->methods->color_quant_doit = color_quant_doit; + cinfo->methods->color_quant_term = color_quant_term; + cinfo->methods->color_quantize = color_quantize; + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ diff --git a/jrdgif.c b/jrdgif.c new file mode 100644 index 0000000..e2d4b33 --- /dev/null +++ b/jrdgif.c @@ -0,0 +1,620 @@ +/* + * jrdgif.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in GIF format. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume input from + * an ordinary stdio stream. They further assume that reading begins + * at the start of the file; input_init may need work if the + * user interface has already read some data (e.g., to determine that + * the file is indeed GIF format). + * + * These routines are invoked via the methods get_input_row + * and input_init/term. + */ + +/* + * This code is loosely based on giftoppm from the PBMPLUS distribution + * of Feb. 1991. That file contains the following copyright notice: + * +-------------------------------------------------------------------+ + * | Copyright 1990, David Koblas. | + * | Permission to use, copy, modify, and distribute this software | + * | and its documentation for any purpose and without fee is hereby | + * | granted, provided that the above copyright notice appear in all | + * | copies and that both that copyright notice and this permission | + * | notice appear in supporting documentation. This software is | + * | provided "as is" without express or implied warranty. | + * +-------------------------------------------------------------------+ + * + * We are also required to state that + * "The Graphics Interchange Format(c) is the Copyright property of + * CompuServe Incorporated. GIF(sm) is a Service Mark property of + * CompuServe Incorporated." + */ + +#include "jinclude.h" + +#ifdef GIF_SUPPORTED + + +#define MAXCOLORMAPSIZE 256 /* max # of colors in a GIF colormap */ +#define NUMCOLORS 3 /* # of colors */ +#define CM_RED 0 /* color component numbers */ +#define CM_GREEN 1 +#define CM_BLUE 2 + +static JSAMPARRAY colormap; /* the colormap to use */ +/* colormap[i][j] = value of i'th color component for pixel value j */ + +#define MAX_LZW_BITS 12 /* maximum LZW code size */ +#define LZW_TABLE_SIZE (1< table of prefix symbols */ +static UINT8 FAR *symbol_tail; /* => table of suffix bytes */ +static UINT8 FAR *symbol_stack; /* stack for symbol expansions */ +static UINT8 FAR *sp; /* stack pointer */ + +/* Static state for interlaced image processing */ + +static boolean is_interlaced; /* TRUE if have interlaced image */ +static big_sarray_ptr interlaced_image; /* full image in interlaced order */ +static long cur_row_number; /* need to know actual row number */ +static long pass2_offset; /* # of pixel rows in pass 1 */ +static long pass3_offset; /* # of pixel rows in passes 1&2 */ +static long pass4_offset; /* # of pixel rows in passes 1,2,3 */ + + +/* Forward declarations */ +METHODDEF void load_interlaced_image PP((compress_info_ptr cinfo, JSAMPARRAY pixel_row)); +METHODDEF void get_interlaced_row PP((compress_info_ptr cinfo, JSAMPARRAY pixel_row)); + + + +LOCAL int +ReadByte (compress_info_ptr cinfo) +/* Read next byte from GIF file */ +{ + register FILE * infile = cinfo->input_file; + int c; + + if ((c = getc(infile)) == EOF) + ERREXIT(cinfo->emethods, "Premature EOF in GIF file"); + return c; +} + + +LOCAL int +GetDataBlock (compress_info_ptr cinfo, char *buf) +/* Read a GIF data block, which has a leading count byte */ +/* A zero-length block marks the end of a data block sequence */ +{ + int count; + + count = ReadByte(cinfo); + if (count > 0) { + if (! ReadOK(cinfo->input_file, buf, count)) + ERREXIT(cinfo->emethods, "Premature EOF in GIF file"); + } + return count; +} + + +LOCAL void +SkipDataBlocks (compress_info_ptr cinfo) +/* Skip a series of data blocks, until a block terminator is found */ +{ + char buf[256]; + + while (GetDataBlock(cinfo, buf) > 0) + /* skip */; +} + + +LOCAL void +ReInitLZW (void) +/* (Re)initialize LZW state; shared code for startup and Clear processing */ +{ + code_size = input_code_size+1; + limit_code = clear_code << 1; /* 2^code_size */ + max_code = clear_code + 2; /* first unused code value */ + sp = symbol_stack; /* init stack to empty */ +} + + +LOCAL void +InitLZWCode (void) +/* Initialize for a series of LZWReadByte (and hence GetCode) calls */ +{ + /* GetCode initialization */ + last_byte = 2; /* make safe to "recopy last two bytes" */ + last_bit = 0; /* nothing in the buffer */ + cur_bit = 0; /* force buffer load on first call */ + out_of_blocks = FALSE; + + /* LZWReadByte initialization */ + clear_code = 1 << input_code_size; /* compute special code values */ + end_code = clear_code + 1; /* note that these do not change */ + first_time = TRUE; + ReInitLZW(); +} + + +LOCAL int +GetCode (compress_info_ptr cinfo) +/* Fetch the next code_size bits from the GIF data */ +/* We assume code_size is less than 16 */ +{ + register INT32 accum; + int offs, ret, count; + + if ( (cur_bit+code_size) > last_bit) { + /* Time to reload the buffer */ + if (out_of_blocks) { + TRACEMS(cinfo->emethods, 1, "Ran out of GIF bits"); + return end_code; /* fake something useful */ + } + /* preserve last two bytes of what we have -- assume code_size <= 16 */ + code_buf[0] = code_buf[last_byte-2]; + code_buf[1] = code_buf[last_byte-1]; + /* Load more bytes; set flag if we reach the terminator block */ + if ((count = GetDataBlock(cinfo, &code_buf[2])) == 0) { + out_of_blocks = TRUE; + TRACEMS(cinfo->emethods, 1, "Ran out of GIF bits"); + return end_code; /* fake something useful */ + } + /* Reset counters */ + cur_bit = (cur_bit - last_bit) + 16; + last_byte = 2 + count; + last_bit = last_byte * 8; + } + + /* Form up next 24 bits in accum */ + offs = cur_bit >> 3; /* byte containing cur_bit */ +#ifdef CHAR_IS_UNSIGNED + accum = code_buf[offs+2]; + accum <<= 8; + accum |= code_buf[offs+1]; + accum <<= 8; + accum |= code_buf[offs]; +#else + accum = code_buf[offs+2] & 0xFF; + accum <<= 8; + accum |= code_buf[offs+1] & 0xFF; + accum <<= 8; + accum |= code_buf[offs] & 0xFF; +#endif + + /* Right-align cur_bit in accum, then mask off desired number of bits */ + accum >>= (cur_bit & 7); + ret = ((int) accum) & ((1 << code_size) - 1); + + cur_bit += code_size; + return ret; +} + + +LOCAL int +LZWReadByte (compress_info_ptr cinfo) +/* Read an LZW-compressed byte */ +{ + static int oldcode; /* previous LZW symbol */ + static int firstcode; /* first byte of oldcode's expansion */ + register int code; /* current working code */ + int incode; /* saves actual input code */ + + /* First time, just eat the expected Clear code(s) and return next code, */ + /* which is assumed to be a raw byte. */ + if (first_time) { + first_time = FALSE; + do { + code = GetCode(cinfo); + } while (code == clear_code); + firstcode = oldcode = code; /* make firstcode, oldcode valid! */ + return code; + } + + /* If any codes are stacked from a previously read symbol, return them */ + if (sp > symbol_stack) + return *(--sp); + + code = GetCode(cinfo); + + if (code == clear_code) { + /* Reinit static state, swallow any extra Clear codes, and return */ + ReInitLZW(); + do { + code = GetCode(cinfo); + } while (code == clear_code); + firstcode = oldcode = code; /* gotta reinit these too */ + return code; + } + + if (code == end_code) { + /* Skip the rest of the image, unless GetCode already read terminator */ + if (! out_of_blocks) + SkipDataBlocks(cinfo); + return -1; + } + + /* Normal raw byte or LZW symbol */ + incode = code; /* save for a moment */ + + if (code >= max_code) { /* special case for not-yet-defined symbol */ + *sp++ = firstcode; /* it will be defined as oldcode/firstcode */ + code = oldcode; + } + + /* If it's a symbol, expand it into the stack */ + while (code >= clear_code) { + *sp++ = symbol_tail[code]; /* tail of symbol: a simple byte value */ + code = symbol_head[code]; /* head of symbol: another LZW symbol */ + } + /* At this point code just represents a raw byte */ + firstcode = code; /* save for possible future use */ + + /* If there's room in table, */ + if ((code = max_code) < LZW_TABLE_SIZE) { + /* Define a new symbol = prev sym + head of this sym's expansion */ + symbol_head[code] = oldcode; + symbol_tail[code] = firstcode; + max_code++; + /* Is it time to increase code_size? */ + if ((max_code >= limit_code) && (code_size < MAX_LZW_BITS)) { + code_size++; + limit_code <<= 1; /* keep equal to 2^code_size */ + } + } + + oldcode = incode; /* save last input symbol for future use */ + return firstcode; /* return first byte of symbol's expansion */ +} + + +LOCAL void +ReadColorMap (compress_info_ptr cinfo, int cmaplen, JSAMPARRAY cmap) +/* Read a GIF colormap */ +{ + int i; + + for (i = 0; i < cmaplen; i++) { + cmap[CM_RED][i] = ReadByte(cinfo); + cmap[CM_GREEN][i] = ReadByte(cinfo); + cmap[CM_BLUE][i] = ReadByte(cinfo); + } +} + + +LOCAL void +DoExtension (compress_info_ptr cinfo) +/* Process an extension block */ +/* Currently we ignore 'em all */ +{ + int extlabel; + + /* Read extension label byte */ + extlabel = ReadByte(cinfo); + TRACEMS1(cinfo->emethods, 1, "Ignoring GIF extension block of type 0x%02x", + extlabel); + /* Skip the data block(s) associated with the extension */ + SkipDataBlocks(cinfo); +} + + +/* + * Read the file header; return image size and component count. + */ + +METHODDEF void +input_init (compress_info_ptr cinfo) +{ + char hdrbuf[10]; /* workspace for reading control blocks */ + UINT16 width, height; /* image dimensions */ + int colormaplen, aspectRatio; + int c; + + /* Allocate space to store the colormap */ + colormap = (*cinfo->emethods->alloc_small_sarray) + ((long) MAXCOLORMAPSIZE, (long) NUMCOLORS); + + /* Read and verify GIF Header */ + if (! ReadOK(cinfo->input_file, hdrbuf, 6)) + ERREXIT(cinfo->emethods, "Not a GIF file"); + if (strncmp(hdrbuf, "GIF", 3) != 0) + ERREXIT(cinfo->emethods, "Not a GIF file"); + /* Check for expected version numbers. + * If unknown version, give warning and try to process anyway; + * this is per recommendation in GIF89a standard. + */ + if ((strncmp(hdrbuf+3, "87a", 3) != 0) && + (strncmp(hdrbuf+3, "89a", 3) != 0)) + TRACEMS3(cinfo->emethods, 1, + "Warning: unexpected GIF version number '%c%c%c'", + hdrbuf[3], hdrbuf[4], hdrbuf[5]); + + /* Read and decipher Logical Screen Descriptor */ + if (! ReadOK(cinfo->input_file, hdrbuf, 7)) + ERREXIT(cinfo->emethods, "Premature EOF in GIF file"); + width = LM_to_uint(hdrbuf[0],hdrbuf[1]); + height = LM_to_uint(hdrbuf[2],hdrbuf[3]); + colormaplen = 2 << (hdrbuf[4] & 0x07); + /* we ignore the color resolution, sort flag, and background color index */ + aspectRatio = hdrbuf[6] & 0xFF; + if (aspectRatio != 0 && aspectRatio != 49) + TRACEMS(cinfo->emethods, 1, "Warning: nonsquare pixels in input"); + + /* Read global colormap if header indicates it is present */ + if (BitSet(hdrbuf[4], COLORMAPFLAG)) + ReadColorMap(cinfo, colormaplen, colormap); + + /* Scan until we reach start of desired image. + * We don't currently support skipping images, but could add it easily. + */ + for (;;) { + c = ReadByte(cinfo); + + if (c == ';') /* GIF terminator?? */ + ERREXIT(cinfo->emethods, "Too few images in GIF file"); + + if (c == '!') { /* Extension */ + DoExtension(cinfo); + continue; + } + + if (c != ',') { /* Not an image separator? */ + TRACEMS1(cinfo->emethods, 1, "Bogus input char 0x%02x, ignoring", c); + continue; + } + + /* Read and decipher Local Image Descriptor */ + if (! ReadOK(cinfo->input_file, hdrbuf, 9)) + ERREXIT(cinfo->emethods, "Premature EOF in GIF file"); + /* we ignore top/left position info, also sort flag */ + width = LM_to_uint(hdrbuf[4],hdrbuf[5]); + height = LM_to_uint(hdrbuf[6],hdrbuf[7]); + is_interlaced = BitSet(hdrbuf[8], INTERLACE); + colormaplen = 2 << (hdrbuf[8] & 0x07); + + /* Read local colormap if header indicates it is present */ + /* Note: if we wanted to support skipping images, */ + /* we'd need to skip rather than read colormap for ignored images */ + if (BitSet(hdrbuf[8], COLORMAPFLAG)) + ReadColorMap(cinfo, colormaplen, colormap); + + input_code_size = ReadByte(cinfo); /* get minimum-code-size byte */ + if (input_code_size < 2 || input_code_size >= MAX_LZW_BITS) + ERREXIT1(cinfo->emethods, "Bogus codesize %d", input_code_size); + + /* Reached desired image, so break out of loop */ + /* If we wanted to skip this image, */ + /* we'd call SkipDataBlocks and then continue the loop */ + break; + } + + /* Prepare to read selected image: first initialize LZW decompressor */ + symbol_head = (UINT16 FAR *) (*cinfo->emethods->alloc_medium) + (LZW_TABLE_SIZE * SIZEOF(UINT16)); + symbol_tail = (UINT8 FAR *) (*cinfo->emethods->alloc_medium) + (LZW_TABLE_SIZE * SIZEOF(UINT8)); + symbol_stack = (UINT8 FAR *) (*cinfo->emethods->alloc_medium) + (LZW_TABLE_SIZE * SIZEOF(UINT8)); + InitLZWCode(); + + /* + * If image is interlaced, we read it into a full-size sample array, + * decompressing as we go; then get_input_row selects rows from the + * sample array in the proper order. + */ + if (is_interlaced) { + /* We request the big array now, but can't access it until the pipeline + * controller causes all the big arrays to be allocated. Hence, the + * actual work of reading the image is postponed until the first call + * of get_input_row. + */ + interlaced_image = (*cinfo->emethods->request_big_sarray) + ((long) width, (long) height, (long) 1); + cinfo->methods->get_input_row = load_interlaced_image; + } + + /* Return info about the image. */ + cinfo->input_components = NUMCOLORS; + cinfo->in_color_space = CS_RGB; + cinfo->image_width = width; + cinfo->image_height = height; + cinfo->data_precision = 8; +} + + +/* + * Read one row of pixels. + * This version is used for noninterlaced GIF images: + * we read directly from the GIF file. + */ + +METHODDEF void +get_input_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row) +{ + register JSAMPROW ptr0, ptr1, ptr2; + register long col; + register int c; + + ptr0 = pixel_row[0]; + ptr1 = pixel_row[1]; + ptr2 = pixel_row[2]; + for (col = cinfo->image_width; col > 0; col--) { + if ((c = LZWReadByte(cinfo)) < 0) + ERREXIT(cinfo->emethods, "Premature end of GIF image"); + *ptr0++ = colormap[CM_RED][c]; + *ptr1++ = colormap[CM_GREEN][c]; + *ptr2++ = colormap[CM_BLUE][c]; + } +} + + +/* + * Read one row of pixels. + * This version is used for the first call on get_input_row when + * reading an interlaced GIF file: we read the whole image into memory. + */ + +METHODDEF void +load_interlaced_image (compress_info_ptr cinfo, JSAMPARRAY pixel_row) +{ + JSAMPARRAY image_ptr; + register JSAMPROW sptr; + register long col; + register int c; + long row; + + /* Read the interlaced image into the big array we've created. */ + for (row = 0; row < cinfo->image_height; row++) { + image_ptr = (*cinfo->emethods->access_big_sarray) + (interlaced_image, row, TRUE); + sptr = image_ptr[0]; + for (col = cinfo->image_width; col > 0; col--) { + if ((c = LZWReadByte(cinfo)) < 0) + ERREXIT(cinfo->emethods, "Premature end of GIF image"); + *sptr++ = c; + } + } + + /* Replace method pointer so subsequent calls don't come here. */ + cinfo->methods->get_input_row = get_interlaced_row; + /* Initialize for get_interlaced_row, and perform first call on it. */ + cur_row_number = 0; + pass2_offset = (cinfo->image_height + 7L) / 8L; + pass3_offset = pass2_offset + (cinfo->image_height + 3L) / 8L; + pass4_offset = pass3_offset + (cinfo->image_height + 1L) / 4L; + + get_interlaced_row(cinfo, pixel_row); +} + + +/* + * Read one row of pixels. + * This version is used for interlaced GIF images: + * we read from the big in-memory image. + */ + +METHODDEF void +get_interlaced_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row) +{ + JSAMPARRAY image_ptr; + register JSAMPROW sptr, ptr0, ptr1, ptr2; + register long col; + register int c; + long irow; + + /* Figure out which row of interlaced image is needed, and access it. */ + switch ((int) (cur_row_number & 7L)) { + case 0: /* first-pass row */ + irow = cur_row_number >> 3; + break; + case 4: /* second-pass row */ + irow = (cur_row_number >> 3) + pass2_offset; + break; + case 2: /* third-pass row */ + case 6: + irow = (cur_row_number >> 2) + pass3_offset; + break; + default: /* fourth-pass row */ + irow = (cur_row_number >> 1) + pass4_offset; + break; + } + image_ptr = (*cinfo->emethods->access_big_sarray) + (interlaced_image, irow, FALSE); + /* Scan the row, expand colormap, and output */ + sptr = image_ptr[0]; + ptr0 = pixel_row[0]; + ptr1 = pixel_row[1]; + ptr2 = pixel_row[2]; + for (col = cinfo->image_width; col > 0; col--) { + c = GETJSAMPLE(*sptr++); + *ptr0++ = colormap[CM_RED][c]; + *ptr1++ = colormap[CM_GREEN][c]; + *ptr2++ = colormap[CM_BLUE][c]; + } + cur_row_number++; /* for next time */ +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +input_term (compress_info_ptr cinfo) +{ + if (is_interlaced) { + (*cinfo->emethods->free_big_sarray) (interlaced_image); + } + (*cinfo->emethods->free_small_sarray) + (colormap, (long) NUMCOLORS); + (*cinfo->emethods->free_medium) ((void FAR *) symbol_head); + (*cinfo->emethods->free_medium) ((void FAR *) symbol_tail); + (*cinfo->emethods->free_medium) ((void FAR *) symbol_stack); +} + + +/* + * The method selection routine for GIF format input. + * Note that this must be called by the user interface before calling + * jpeg_compress. If multiple input formats are supported, the + * user interface is responsible for discovering the file format and + * calling the appropriate method selection routine. + */ + +GLOBAL void +jselrgif (compress_info_ptr cinfo) +{ + cinfo->methods->input_init = input_init; + cinfo->methods->get_input_row = get_input_row; /* assume uninterlaced */ + cinfo->methods->input_term = input_term; +} + +#endif /* GIF_SUPPORTED */ diff --git a/jrdjfif.c b/jrdjfif.c new file mode 100644 index 0000000..5ff14ba --- /dev/null +++ b/jrdjfif.c @@ -0,0 +1,733 @@ +/* + * jrdjfif.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to decode standard JPEG file headers/markers. + * This will handle baseline and JFIF-convention JPEG files. + * + * This module relies on the JGETC macro and the read_jpeg_data method (which + * is provided by the user interface) to read from the JPEG data stream. + * Therefore, this module is NOT dependent on any particular assumption about + * the data source. This fact does not carry over to more complex JPEG file + * formats such as JPEG-in-TIFF; those format control modules may well need to + * assume stdio input. + * + * read_file_header assumes that reading begins at the JPEG SOI marker + * (although it will skip non-FF bytes looking for a JPEG marker). + * The user interface must position the data stream appropriately. + * + * These routines are invoked via the methods read_file_header, + * read_scan_header, read_jpeg_data, read_scan_trailer, and read_file_trailer. + */ + +#include "jinclude.h" + +#ifdef JFIF_SUPPORTED + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* + * Reload the input buffer after it's been emptied, and return the next byte. + * This is exported for direct use by the entropy decoder. + * See the JGETC macro for calling conditions. + * + * For this header control module, read_jpeg_data is supplied by the + * user interface. However, header formats that require random access + * to the input file would need to supply their own code. This code is + * left here to indicate what is required. + */ + +#if 0 /* not needed in this module */ + +METHODDEF int +read_jpeg_data (decompress_info_ptr cinfo) +{ + cinfo->bytes_in_buffer = fread(cinfo->input_buffer + MIN_UNGET, + 1, JPEG_BUF_SIZE, + cinfo->input_file); + + cinfo->next_input_byte = cinfo->input_buffer + MIN_UNGET; + + if (cinfo->bytes_in_buffer <= 0) + ERREXIT(cinfo->emethods, "Unexpected EOF in JPEG file"); + + return JGETC(cinfo); +} + +#endif + + +/* + * Routines to parse JPEG markers & save away the useful info. + */ + + +LOCAL INT32 +get_2bytes (decompress_info_ptr cinfo) +/* Get a 2-byte unsigned integer (e.g., a marker parameter length field) */ +{ + INT32 a; + + a = JGETC(cinfo); + return (a << 8) + JGETC(cinfo); +} + + +LOCAL void +skip_variable (decompress_info_ptr cinfo, int code) +/* Skip over an unknown or uninteresting variable-length marker */ +{ + INT32 length; + + length = get_2bytes(cinfo); + + TRACEMS2(cinfo->emethods, 1, + "Skipping marker 0x%02x, length %d", code, length); + + for (length -= 2; length > 0; length--) + (void) JGETC(cinfo); +} + + +LOCAL void +get_dht (decompress_info_ptr cinfo) +/* Process a DHT marker */ +{ + INT32 length; + UINT8 bits[17]; + UINT8 huffval[256]; + int i, index, count; + HUFF_TBL **htblptr; + + length = get_2bytes(cinfo)-2; + + while (length > 0) { + index = JGETC(cinfo); + + TRACEMS1(cinfo->emethods, 1, "Define Huffman Table 0x%02x", index); + + bits[0] = 0; + count = 0; + for (i = 1; i <= 16; i++) { + bits[i] = JGETC(cinfo); + count += bits[i]; + } + + TRACEMS8(cinfo->emethods, 2, " %3d %3d %3d %3d %3d %3d %3d %3d", + bits[1], bits[2], bits[3], bits[4], + bits[5], bits[6], bits[7], bits[8]); + TRACEMS8(cinfo->emethods, 2, " %3d %3d %3d %3d %3d %3d %3d %3d", + bits[9], bits[10], bits[11], bits[12], + bits[13], bits[14], bits[15], bits[16]); + + if (count > 256) + ERREXIT(cinfo->emethods, "Bogus DHT counts"); + + for (i = 0; i < count; i++) + huffval[i] = JGETC(cinfo); + + length -= 1 + 16 + count; + + if (index & 0x10) { /* AC table definition */ + index -= 0x10; + htblptr = &cinfo->ac_huff_tbl_ptrs[index]; + } else { /* DC table definition */ + htblptr = &cinfo->dc_huff_tbl_ptrs[index]; + } + + if (index < 0 || index >= NUM_HUFF_TBLS) + ERREXIT1(cinfo->emethods, "Bogus DHT index %d", index); + + if (*htblptr == NULL) + *htblptr = (*cinfo->emethods->alloc_small) (SIZEOF(HUFF_TBL)); + + memcpy((void *) (*htblptr)->bits, (void *) bits, + SIZEOF((*htblptr)->bits)); + memcpy((void *) (*htblptr)->huffval, (void *) huffval, + SIZEOF((*htblptr)->huffval)); + } +} + + +LOCAL void +get_dac (decompress_info_ptr cinfo) +/* Process a DAC marker */ +{ + INT32 length; + int index, val; + + length = get_2bytes(cinfo)-2; + + while (length > 0) { + index = JGETC(cinfo); + val = JGETC(cinfo); + + TRACEMS2(cinfo->emethods, 1, + "Define Arithmetic Table 0x%02x: 0x%02x", index, val); + + if (index < 0 || index >= (2*NUM_ARITH_TBLS)) + ERREXIT1(cinfo->emethods, "Bogus DAC index %d", index); + + if (index >= NUM_ARITH_TBLS) { /* define AC table */ + cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = val; + } else { /* define DC table */ + cinfo->arith_dc_L[index] = val & 0x0F; + cinfo->arith_dc_U[index] = val >> 4; + if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index]) + ERREXIT1(cinfo->emethods, "Bogus DAC value 0x%x", val); + } + + length -= 2; + } +} + + +LOCAL void +get_dqt (decompress_info_ptr cinfo) +/* Process a DQT marker */ +{ + INT32 length; + int n, i, prec; + UINT16 tmp; + QUANT_TBL_PTR quant_ptr; + + length = get_2bytes(cinfo) - 2; + + while (length > 0) { + n = JGETC(cinfo); + prec = n >> 4; + n &= 0x0F; + + TRACEMS2(cinfo->emethods, 1, + "Define Quantization Table %d precision %d", n, prec); + + if (n >= NUM_QUANT_TBLS) + ERREXIT1(cinfo->emethods, "Bogus table number %d", n); + + if (cinfo->quant_tbl_ptrs[n] == NULL) + cinfo->quant_tbl_ptrs[n] = (*cinfo->emethods->alloc_small) (SIZEOF(QUANT_TBL)); + quant_ptr = cinfo->quant_tbl_ptrs[n]; + + for (i = 0; i < DCTSIZE2; i++) { + tmp = JGETC(cinfo); + if (prec) + tmp = (tmp<<8) + JGETC(cinfo); + quant_ptr[i] = tmp; + } + + for (i = 0; i < DCTSIZE2; i += 8) { + TRACEMS8(cinfo->emethods, 2, " %4d %4d %4d %4d %4d %4d %4d %4d", + quant_ptr[i ], quant_ptr[i+1], quant_ptr[i+2], quant_ptr[i+3], + quant_ptr[i+4], quant_ptr[i+5], quant_ptr[i+6], quant_ptr[i+7]); + } + + length -= DCTSIZE2+1; + if (prec) length -= DCTSIZE2; + } +} + + +LOCAL void +get_dri (decompress_info_ptr cinfo) +/* Process a DRI marker */ +{ + if (get_2bytes(cinfo) != 4) + ERREXIT(cinfo->emethods, "Bogus length in DRI"); + + cinfo->restart_interval = get_2bytes(cinfo); + + TRACEMS1(cinfo->emethods, 1, + "Define Restart Interval %d", cinfo->restart_interval); +} + + +LOCAL void +get_app0 (decompress_info_ptr cinfo) +/* Process an APP0 marker */ +{ +#define JFIF_LEN 14 + INT32 length; + UINT8 b[JFIF_LEN]; + int buffp; + + length = get_2bytes(cinfo) - 2; + + /* See if a JFIF APP0 marker is present */ + + if (length >= JFIF_LEN) { + for (buffp = 0; buffp < JFIF_LEN; buffp++) + b[buffp] = JGETC(cinfo); + length -= JFIF_LEN; + + if (b[0]=='J' && b[1]=='F' && b[2]=='I' && b[3]=='F' && b[4]==0) { + /* Found JFIF APP0 marker: check version */ + /* Major version must be 1 */ + if (b[5] != 1) + ERREXIT2(cinfo->emethods, "Unsupported JFIF revision number %d.%02d", + b[5], b[6]); + /* Minor version should be 0 or 1, but try to process anyway if newer */ + if (b[6] != 0 && b[6] != 1) + TRACEMS2(cinfo->emethods, 0, "Warning: unknown JFIF revision number %d.%02d", + b[5], b[6]); + /* Save info */ + cinfo->density_unit = b[7]; + cinfo->X_density = (b[8] << 8) + b[9]; + cinfo->Y_density = (b[10] << 8) + b[11]; + /* Assume colorspace is YCbCr, unless UI has overridden me */ + if (cinfo->jpeg_color_space == CS_UNKNOWN) + cinfo->jpeg_color_space = CS_YCbCr; + TRACEMS3(cinfo->emethods, 1, "JFIF APP0 marker, density %dx%d %d", + cinfo->X_density, cinfo->Y_density, cinfo->density_unit); + } else { + TRACEMS(cinfo->emethods, 1, "Unknown APP0 marker (not JFIF)"); + } + } else { + TRACEMS1(cinfo->emethods, 1, + "Short APP0 marker, length %d", (int) length); + } + + while (length-- > 0) /* skip any remaining data */ + (void) JGETC(cinfo); +} + + +LOCAL void +get_sof (decompress_info_ptr cinfo, int code) +/* Process a SOFn marker */ +{ + INT32 length; + short ci; + int c; + jpeg_component_info * compptr; + + length = get_2bytes(cinfo); + + cinfo->data_precision = JGETC(cinfo); + cinfo->image_height = get_2bytes(cinfo); + cinfo->image_width = get_2bytes(cinfo); + cinfo->num_components = JGETC(cinfo); + + TRACEMS4(cinfo->emethods, 1, + "Start Of Frame 0x%02x: width=%d, height=%d, components=%d", + code, cinfo->image_width, cinfo->image_height, + cinfo->num_components); + + /* We don't support files in which the image height is initially specified */ + /* as 0 and is later redefined by DNL. As long as we have to check that, */ + /* might as well have a general sanity check. */ + if (cinfo->image_height <= 0 || cinfo->image_width <= 0 + || cinfo->num_components <= 0) + ERREXIT(cinfo->emethods, "Empty JPEG image (DNL not supported)"); + +#ifdef EIGHT_BIT_SAMPLES + if (cinfo->data_precision != 8) + ERREXIT(cinfo->emethods, "Unsupported JPEG data precision"); +#endif +#ifdef TWELVE_BIT_SAMPLES + if (cinfo->data_precision != 12) /* this needs more thought?? */ + ERREXIT(cinfo->emethods, "Unsupported JPEG data precision"); +#endif +#ifdef SIXTEEN_BIT_SAMPLES + if (cinfo->data_precision != 16) /* this needs more thought?? */ + ERREXIT(cinfo->emethods, "Unsupported JPEG data precision"); +#endif + + if (length != (cinfo->num_components * 3 + 8)) + ERREXIT(cinfo->emethods, "Bogus SOF length"); + + cinfo->comp_info = (*cinfo->emethods->alloc_small) + (cinfo->num_components * SIZEOF(jpeg_component_info)); + + for (ci = 0; ci < cinfo->num_components; ci++) { + compptr = &cinfo->comp_info[ci]; + compptr->component_index = ci; + compptr->component_id = JGETC(cinfo); + c = JGETC(cinfo); + compptr->h_samp_factor = (c >> 4) & 15; + compptr->v_samp_factor = (c ) & 15; + compptr->quant_tbl_no = JGETC(cinfo); + + TRACEMS4(cinfo->emethods, 1, " Component %d: %dhx%dv q=%d", + compptr->component_id, compptr->h_samp_factor, + compptr->v_samp_factor, compptr->quant_tbl_no); + } +} + + +LOCAL void +get_sos (decompress_info_ptr cinfo) +/* Process a SOS marker */ +{ + INT32 length; + int i, ci, n, c, cc; + jpeg_component_info * compptr; + + length = get_2bytes(cinfo); + + n = JGETC(cinfo); /* Number of components */ + cinfo->comps_in_scan = n; + length -= 3; + + if (length != (n * 2 + 3) || n < 1 || n > MAX_COMPS_IN_SCAN) + ERREXIT(cinfo->emethods, "Bogus SOS length"); + + TRACEMS1(cinfo->emethods, 1, "Start Of Scan: %d components", n); + + for (i = 0; i < n; i++) { + cc = JGETC(cinfo); + c = JGETC(cinfo); + length -= 2; + + for (ci = 0; ci < cinfo->num_components; ci++) + if (cc == cinfo->comp_info[ci].component_id) + break; + + if (ci >= cinfo->num_components) + ERREXIT(cinfo->emethods, "Invalid component number in SOS"); + + compptr = &cinfo->comp_info[ci]; + cinfo->cur_comp_info[i] = compptr; + compptr->dc_tbl_no = (c >> 4) & 15; + compptr->ac_tbl_no = (c ) & 15; + + TRACEMS3(cinfo->emethods, 1, " c%d: [dc=%d ac=%d]", cc, + compptr->dc_tbl_no, compptr->ac_tbl_no); + } + + while (length > 0) { + (void) JGETC(cinfo); + length--; + } +} + + +LOCAL void +get_soi (decompress_info_ptr cinfo) +/* Process an SOI marker */ +{ + int i; + + TRACEMS(cinfo->emethods, 1, "Start of Image"); + + /* Reset all parameters that are defined to be reset by SOI */ + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + cinfo->restart_interval = 0; + + cinfo->density_unit = 0; /* set default JFIF APP0 values */ + cinfo->X_density = 1; + cinfo->Y_density = 1; + + cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling */ +} + + +LOCAL int +next_marker (decompress_info_ptr cinfo) +/* Find the next JPEG marker */ +/* Note that the output might not be a valid marker code, */ +/* but it will never be 0 or FF */ +{ + int c, nbytes; + + nbytes = 0; + do { + do { /* skip any non-FF bytes */ + nbytes++; + c = JGETC(cinfo); + } while (c != 0xFF); + do { /* skip any duplicate FFs */ + nbytes++; + c = JGETC(cinfo); + } while (c == 0xFF); + } while (c == 0); /* repeat if it was a stuffed FF/00 */ + + if (nbytes != 2) + TRACEMS2(cinfo->emethods, 1, "Skipped %d bytes before marker 0x%02x", + nbytes-2, c); + + return c; +} + + +LOCAL JPEG_MARKER +process_tables (decompress_info_ptr cinfo) +/* Scan and process JPEG markers that can appear in any order */ +/* Return when an SOI, EOI, SOFn, or SOS is found */ +{ + int c; + + while (TRUE) { + c = next_marker(cinfo); + + switch (c) { + case M_SOF0: + case M_SOF1: + case M_SOF2: + case M_SOF3: + case M_SOF5: + case M_SOF6: + case M_SOF7: + case M_JPG: + case M_SOF9: + case M_SOF10: + case M_SOF11: + case M_SOF13: + case M_SOF14: + case M_SOF15: + case M_SOI: + case M_EOI: + case M_SOS: + return c; + + case M_DHT: + get_dht(cinfo); + break; + + case M_DAC: + get_dac(cinfo); + break; + + case M_DQT: + get_dqt(cinfo); + break; + + case M_DRI: + get_dri(cinfo); + break; + + case M_APP0: + get_app0(cinfo); + break; + + case M_RST0: /* these are all parameterless */ + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + case M_TEM: + TRACEMS1(cinfo->emethods, 1, "Unexpected marker 0x%02x", c); + break; + + default: /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn */ + skip_variable(cinfo, c); + break; + } + } +} + + + +/* + * Initialize and read the file header (everything through the SOF marker). + */ + +METHODDEF void +read_file_header (decompress_info_ptr cinfo) +{ + int c; + + /* Expect an SOI marker first */ + if (next_marker(cinfo) == M_SOI) + get_soi(cinfo); + else + ERREXIT(cinfo->emethods, "File does not start with JPEG SOI marker"); + + /* Process markers until SOF */ + c = process_tables(cinfo); + + switch (c) { + case M_SOF0: + case M_SOF1: + get_sof(cinfo, c); + cinfo->arith_code = FALSE; + break; + + case M_SOF9: + get_sof(cinfo, c); + cinfo->arith_code = TRUE; + break; + + default: + ERREXIT1(cinfo->emethods, "Unsupported SOF marker type 0x%02x", c); + break; + } + + /* Figure out what colorspace we have */ + /* (too bad the JPEG committee didn't provide a real way to specify this) */ + + switch (cinfo->num_components) { + case 1: + cinfo->jpeg_color_space = CS_GRAYSCALE; + break; + + case 3: + /* if we saw a JFIF marker, leave it set to YCbCr; */ + /* also leave it alone if UI has provided a value */ + if (cinfo->jpeg_color_space == CS_UNKNOWN) { + short cid0 = cinfo->comp_info[0].component_id; + short cid1 = cinfo->comp_info[1].component_id; + short cid2 = cinfo->comp_info[2].component_id; + + if (cid0 == 1 && cid1 == 2 && cid2 == 3) + cinfo->jpeg_color_space = CS_YCbCr; /* assume it's JFIF w/out marker */ + else if (cid0 == 1 && cid1 == 4 && cid2 == 5) + cinfo->jpeg_color_space = CS_YIQ; /* prototype's YIQ matrix */ + else { + TRACEMS3(cinfo->emethods, 0, + "Unrecognized component IDs %d %d %d, assuming YCbCr", + cid0, cid1, cid2); + cinfo->jpeg_color_space = CS_YCbCr; + } + } + break; + + case 4: + cinfo->jpeg_color_space = CS_CMYK; + break; + + default: + cinfo->jpeg_color_space = CS_UNKNOWN; + break; + } +} + + +/* + * Read the start of a scan (everything through the SOS marker). + * Return TRUE if find SOS, FALSE if find EOI. + */ + +METHODDEF boolean +read_scan_header (decompress_info_ptr cinfo) +{ + int c; + + /* Process markers until SOS or EOI */ + c = process_tables(cinfo); + + switch (c) { + case M_SOS: + get_sos(cinfo); + return TRUE; + + case M_EOI: + TRACEMS(cinfo->emethods, 1, "End Of Image"); + return FALSE; + + default: + ERREXIT1(cinfo->emethods, "Unexpected marker 0x%02x", c); + break; + } + return FALSE; /* keeps lint happy */ +} + + +/* + * Finish up after a compressed scan (series of read_jpeg_data calls); + * prepare for another read_scan_header call. + */ + +METHODDEF void +read_scan_trailer (decompress_info_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +read_file_trailer (decompress_info_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * The method selection routine for standard JPEG header reading. + * Note that this must be called by the user interface before calling + * jpeg_decompress. When a non-JFIF file is to be decompressed (TIFF, + * perhaps), the user interface must discover the file type and call + * the appropriate method selection routine. + */ + +GLOBAL void +jselrjfif (decompress_info_ptr cinfo) +{ + cinfo->methods->read_file_header = read_file_header; + cinfo->methods->read_scan_header = read_scan_header; + /* For JFIF/raw-JPEG format, the user interface supplies read_jpeg_data. */ +#if 0 + cinfo->methods->read_jpeg_data = read_jpeg_data; +#endif + cinfo->methods->read_scan_trailer = read_scan_trailer; + cinfo->methods->read_file_trailer = read_file_trailer; +} + +#endif /* JFIF_SUPPORTED */ diff --git a/jrdppm.c b/jrdppm.c new file mode 100644 index 0000000..15e2393 --- /dev/null +++ b/jrdppm.c @@ -0,0 +1,124 @@ +/* + * jrdppm.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in PPM format. + * The PBMPLUS library is required (well, it will be in the real version). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume input from + * an ordinary stdio stream. They further assume that reading begins + * at the start of the file; input_init may need work if the + * user interface has already read some data (e.g., to determine that + * the file is indeed PPM format). + * + * These routines are invoked via the methods get_input_row + * and input_init/term. + */ + +#include "jinclude.h" + +#ifdef PPM_SUPPORTED + + +/* + * Read the file header; return image size and component count. + */ + +METHODDEF void +input_init (compress_info_ptr cinfo) +{ + int c, w, h, prec; + + if (getc(cinfo->input_file) != 'P') + ERREXIT(cinfo->emethods, "Not a PPM file"); + + c = getc(cinfo->input_file); + switch (c) { + case '5': /* it's a PGM file */ + cinfo->input_components = 1; + cinfo->in_color_space = CS_GRAYSCALE; + break; + + case '6': /* it's a PPM file */ + cinfo->input_components = 3; + cinfo->in_color_space = CS_RGB; + break; + + default: + ERREXIT(cinfo->emethods, "Not a PPM file"); + break; + } + + if (fscanf(cinfo->input_file, " %d %d %d", &w, &h, &prec) != 3) + ERREXIT(cinfo->emethods, "Not a PPM file"); + + if (getc(cinfo->input_file) != '\n' || w <= 0 || h <= 0 || prec != 255) + ERREXIT(cinfo->emethods, "Not a PPM file"); + + cinfo->image_width = w; + cinfo->image_height = h; + cinfo->data_precision = 8; +} + + +/* + * Read one row of pixels. + */ + +METHODDEF void +get_input_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row) +{ + register FILE * infile = cinfo->input_file; + register JSAMPROW ptr0, ptr1, ptr2; + register long col; + + if (cinfo->input_components == 1) { + ptr0 = pixel_row[0]; + for (col = cinfo->image_width; col > 0; col--) { + *ptr0++ = getc(infile); + } + } else { + ptr0 = pixel_row[0]; + ptr1 = pixel_row[1]; + ptr2 = pixel_row[2]; + for (col = cinfo->image_width; col > 0; col--) { + *ptr0++ = getc(infile); + *ptr1++ = getc(infile); + *ptr2++ = getc(infile); + } + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +input_term (compress_info_ptr cinfo) +{ + /* no work required */ +} + + +/* + * The method selection routine for PPM format input. + * Note that this must be called by the user interface before calling + * jpeg_compress. If multiple input formats are supported, the + * user interface is responsible for discovering the file format and + * calling the appropriate method selection routine. + */ + +GLOBAL void +jselrppm (compress_info_ptr cinfo) +{ + cinfo->methods->input_init = input_init; + cinfo->methods->get_input_row = get_input_row; + cinfo->methods->input_term = input_term; +} + +#endif /* PPM_SUPPORTED */ diff --git a/jrevdct.c b/jrevdct.c new file mode 100644 index 0000000..bafbf55 --- /dev/null +++ b/jrevdct.c @@ -0,0 +1,171 @@ +/* + * jrevdct.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the basic inverse-DCT transformation subroutine. + * + * This implementation is based on Appendix A.2 of the book + * "Discrete Cosine Transform---Algorithms, Advantages, Applications" + * by K.R. Rao and P. Yip (Academic Press, Inc, London, 1990). + * It uses scaled fixed-point arithmetic instead of floating point. + */ + +#include "jinclude.h" + + +/* The poop on this scaling stuff is as follows: + * + * Most of the numbers (after multiplication by the constants) are + * (logically) shifted left by LG2_DCT_SCALE. This is undone by UNFIXH + * before assignment to the output array. Note that we want an additional + * division by 2 on the output (required by the equations). + * + * If right shifts are unsigned, then there is a potential problem. + * However, shifting right by 16 and then assigning to a short + * (assuming short = 16 bits) will keep the sign right!! + * + * For other shifts, + * + * ((x + (1 << 30)) >> shft) - (1 << (30 - shft)) + * + * gives a nice right shift with sign (assuming no overflow). However, all the + * scaling is such that this isn't a problem. (Is this true?) + */ + + +#define ONE 1L /* remove L if long > 32 bits */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define LG2_DCT_SCALE 15 +#define RIGHT_SHIFT(_x,_shft) ((((_x) + (ONE << 30)) >> (_shft)) - (ONE << (30 - (_shft)))) +#else +#define LG2_DCT_SCALE 16 +#define RIGHT_SHIFT(_x,_shft) ((_x) >> (_shft)) +#endif + +#define DCT_SCALE (ONE << LG2_DCT_SCALE) + +#define LG2_OVERSCALE 2 +#define OVERSCALE (ONE << LG2_OVERSCALE) + +#define FIX(x) ((INT32) ((x) * DCT_SCALE + 0.5)) +#define FIXO(x) ((INT32) ((x) * DCT_SCALE / OVERSCALE + 0.5)) +#define UNFIX(x) RIGHT_SHIFT((x) + (ONE << (LG2_DCT_SCALE-1)), LG2_DCT_SCALE) +#define UNFIXH(x) RIGHT_SHIFT((x) + (ONE << LG2_DCT_SCALE), LG2_DCT_SCALE+1) +#define UNFIXO(x) RIGHT_SHIFT((x) + (ONE << (LG2_DCT_SCALE-1-LG2_OVERSCALE)), LG2_DCT_SCALE-LG2_OVERSCALE) +#define OVERSH(x) ((x) << LG2_OVERSCALE) + +#define SIN_1_4 FIX(0.7071067811856476) +#define COS_1_4 SIN_1_4 + +#define SIN_1_8 FIX(0.3826834323650898) +#define COS_1_8 FIX(0.9238795325112870) +#define SIN_3_8 COS_1_8 +#define COS_3_8 SIN_1_8 + +#define SIN_1_16 FIX(0.1950903220161282) +#define COS_1_16 FIX(0.9807852804032300) +#define SIN_7_16 COS_1_16 +#define COS_7_16 SIN_1_16 + +#define SIN_3_16 FIX(0.5555702330196022) +#define COS_3_16 FIX(0.8314696123025450) +#define SIN_5_16 COS_3_16 +#define COS_5_16 SIN_3_16 + +#define OSIN_1_4 FIXO(0.707106781185647) +#define OCOS_1_4 OSIN_1_4 + +#define OSIN_1_8 FIXO(0.3826834323650898) +#define OCOS_1_8 FIXO(0.9238795325112870) +#define OSIN_3_8 OCOS_1_8 +#define OCOS_3_8 OSIN_1_8 + +#define OSIN_1_16 FIXO(0.1950903220161282) +#define OCOS_1_16 FIXO(0.9807852804032300) +#define OSIN_7_16 OCOS_1_16 +#define OCOS_7_16 OSIN_1_16 + +#define OSIN_3_16 FIXO(0.5555702330196022) +#define OCOS_3_16 FIXO(0.8314696123025450) +#define OSIN_5_16 OCOS_3_16 +#define OCOS_5_16 OSIN_3_16 + + +INLINE +LOCAL void +fast_idct_8 (DCTELEM *in, int stride) +{ + /* tmp1x are new values of tmpx -- flashy register colourers + * should be able to do this lot very well + */ + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 tmp20, tmp21, tmp22, tmp23; + INT32 tmp30, tmp31; + INT32 tmp40, tmp41, tmp42, tmp43; + INT32 tmp50, tmp51, tmp52, tmp53; + INT32 in0, in1, in2, in3, in4, in5, in6, in7; + + in0 = in[ 0]; + in1 = in[stride ]; + in2 = in[stride*2]; + in3 = in[stride*3]; + in4 = in[stride*4]; + in5 = in[stride*5]; + in6 = in[stride*6]; + in7 = in[stride*7]; + + tmp10 = (in0 + in4) * COS_1_4; + tmp11 = (in0 - in4) * COS_1_4; + tmp12 = in2 * SIN_1_8 - in6 * COS_1_8; + tmp13 = in6 * SIN_1_8 + in2 * COS_1_8; + + tmp20 = tmp10 + tmp13; + tmp21 = tmp11 + tmp12; + tmp22 = tmp11 - tmp12; + tmp23 = tmp10 - tmp13; + + tmp30 = UNFIXO((in3 + in5) * COS_1_4); + tmp31 = UNFIXO((in3 - in5) * COS_1_4); + + tmp40 = OVERSH(in1) + tmp30; + tmp41 = OVERSH(in7) + tmp31; + tmp42 = OVERSH(in1) - tmp30; + tmp43 = OVERSH(in7) - tmp31; + + tmp50 = tmp40 * OCOS_1_16 + tmp41 * OSIN_1_16; + tmp51 = tmp40 * OSIN_1_16 - tmp41 * OCOS_1_16; + tmp52 = tmp42 * OCOS_5_16 + tmp43 * OSIN_5_16; + tmp53 = tmp42 * OSIN_5_16 - tmp43 * OCOS_5_16; + + in[ 0] = UNFIXH(tmp20 + tmp50); + in[stride ] = UNFIXH(tmp21 + tmp53); + in[stride*2] = UNFIXH(tmp22 + tmp52); + in[stride*3] = UNFIXH(tmp23 + tmp51); + in[stride*4] = UNFIXH(tmp23 - tmp51); + in[stride*5] = UNFIXH(tmp22 - tmp52); + in[stride*6] = UNFIXH(tmp21 - tmp53); + in[stride*7] = UNFIXH(tmp20 - tmp50); +} + + +/* + * Perform the inverse DCT on one block of coefficients. + * + * Note that this code is specialized to the case DCTSIZE = 8. + */ + +GLOBAL void +j_rev_dct (DCTBLOCK data) +{ + int i; + + for (i = 0; i < DCTSIZE; i++) + fast_idct_8(data+i*DCTSIZE, 1); + + for (i = 0; i < DCTSIZE; i++) + fast_idct_8(data+i, DCTSIZE); +} diff --git a/jutils.c b/jutils.c new file mode 100644 index 0000000..aebcaa9 --- /dev/null +++ b/jutils.c @@ -0,0 +1,106 @@ +/* + * jutils.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains miscellaneous utility routines needed for both + * compression and decompression. + * Note we prefix all global names with "j" to minimize conflicts with + * a surrounding application. + */ + +#include "jinclude.h" + + +GLOBAL long +jround_up (long a, long b) +/* Compute a rounded up to next multiple of b; a >= 0, b > 0 */ +{ + a += b-1; + return a - (a % b); +} + + +GLOBAL void +jcopy_sample_rows (JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, long num_cols) +/* Copy some rows of samples from one place to another. + * num_rows rows are copied from input_array[source_row++] + * to output_array[dest_row++]; these areas should not overlap. + * The source and destination arrays must be at least as wide as num_cols. + */ +{ + /* On normal machines we can use memcpy(). This won't work on 80x86 because + * the sample arrays are FAR and we're assuming a small-pointer memory model. + */ + register JSAMPROW inptr, outptr; +#ifdef NEED_FAR_POINTERS + register long count; +#else + register size_t count = num_cols * SIZEOF(JSAMPLE); +#endif + register int row; + + input_array += source_row; + output_array += dest_row; + + for (row = num_rows; row > 0; row--) { + inptr = *input_array++; + outptr = *output_array++; +#ifdef NEED_FAR_POINTERS + for (count = num_cols; count > 0; count--) + *outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */ +#else + memcpy((void *) outptr, (void *) inptr, count); +#endif + } +} + + +GLOBAL void +jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row, long num_blocks) +/* Copy a row of coefficient blocks from one place to another. */ +{ + /* On normal machines we can use memcpy(). This won't work on 80x86 because + * the block arrays are FAR and we're assuming a small-pointer memory model. + */ +#ifdef NEED_FAR_POINTERS + register JCOEFPTR inptr, outptr; + register int i; + register long count; + + for (count = num_blocks; count > 0; count--) { + inptr = *input_row++; + outptr = *output_row++; + for (i = DCTSIZE2; i > 0; i--) + *outptr++ = *inptr++; + } +#else + memcpy((void *) output_row, (void *) input_row, + (size_t) (num_blocks * (DCTSIZE2 * SIZEOF(JCOEF)))); +#endif +} + + +GLOBAL void +jzero_far (void FAR * target, size_t bytestozero) +/* Zero out a chunk of FAR memory. */ +/* This might be sample-array data, block-array data, or alloc_medium data. */ +{ + /* On normal machines we can use MEMZERO(). This won't work on 80x86 + * because we're assuming a small-pointer memory model. + */ +#ifdef NEED_FAR_POINTERS + register char FAR * ptr = (char FAR *) target; + register size_t count; + + for (count = bytestozero; count > 0; count--) { + *ptr++ = 0; + } +#else + MEMZERO((void *) target, bytestozero); +#endif +} diff --git a/jvirtmem.c b/jvirtmem.c new file mode 100644 index 0000000..4a0627c --- /dev/null +++ b/jvirtmem.c @@ -0,0 +1,548 @@ +/* + * jvirtmem.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides the system-dependent memory allocation routines + * for the case where we can rely on virtual memory to handle large arrays. + * + * This includes some MS-DOS code just for trial purposes; "big" arrays will + * have to be handled with temp files on MS-DOS, so a real implementation of + * a DOS memory manager will probably be a separate file. (See additional + * comments about big arrays, below.) + * + * NB: allocation routines never return NULL. + * They should exit to error_exit if unsuccessful. + */ + +#include "jinclude.h" + +#ifdef __STDC__ +#include /* to declare malloc(), free() */ +#else +extern void * malloc PP((size_t size)); +extern void free PP((void *ptr)); +#endif + + +/* Insert system-specific definitions of far_malloc, far_free here. */ + +#ifndef NEED_FAR_POINTERS /* Generic for non-braindamaged CPUs */ + +#define far_malloc(x) malloc(x) +#define far_free(x) free(x) + +#else /* NEED_FAR_POINTERS */ + +#ifdef __TURBOC__ +/* These definitions work for Turbo C */ +#include /* need farmalloc(), farfree() */ +#define far_malloc(x) farmalloc(x) +#define far_free(x) farfree(x) +#else +#ifdef MSDOS +/* These definitions work for Microsoft C and compatible compilers */ +#include /* need _fmalloc(), _ffree() */ +#define far_malloc(x) _fmalloc(x) +#define far_free(x) _ffree(x) +#endif +#endif + +#endif /* NEED_FAR_POINTERS */ + + +/* + * Some important notes: + * The array alloc/dealloc routines are not merely a convenience; + * on 80x86 machines the bottom-level pointers in an array are FAR + * and thus may not be allocatable by alloc_small. + * + * Also, it's not a good idea to try to merge the sarray and barray + * routines, even though they are textually almost the same, because + * samples are usually stored as bytes while coefficients are shorts. + * Thus, in machines where byte pointers have a different representation + * from word pointers, the resulting machine code could not be the same. + */ + + +static external_methods_ptr methods; /* saved for access to error_exit */ + + +#ifdef MEM_STATS /* optional extra stuff for statistics */ + +#define MALLOC_OVERHEAD (SIZEOF(char *)) /* assumed overhead per request */ +#define MALLOC_FAR_OVERHEAD (SIZEOF(char FAR *)) /* for "far" storage */ + +static long total_num_small = 0; /* total # of small objects alloced */ +static long total_bytes_small = 0; /* total bytes requested */ +static long cur_num_small = 0; /* # currently alloced */ +static long max_num_small = 0; /* max simultaneously alloced */ + +#ifdef NEED_FAR_POINTERS +static long total_num_medium = 0; /* total # of medium objects alloced */ +static long total_bytes_medium = 0; /* total bytes requested */ +static long cur_num_medium = 0; /* # currently alloced */ +static long max_num_medium = 0; /* max simultaneously alloced */ +#endif + +static long total_num_sarray = 0; /* total # of sarray objects alloced */ +static long total_bytes_sarray = 0; /* total bytes requested */ +static long cur_num_sarray = 0; /* # currently alloced */ +static long max_num_sarray = 0; /* max simultaneously alloced */ + +static long total_num_barray = 0; /* total # of barray objects alloced */ +static long total_bytes_barray = 0; /* total bytes requested */ +static long cur_num_barray = 0; /* # currently alloced */ +static long max_num_barray = 0; /* max simultaneously alloced */ + + +GLOBAL void +j_mem_stats (void) +{ + /* since this is only a debugging stub, we can cheat a little on the + * trace message mechanism... helps 'cuz trace can't handle longs. + */ + fprintf(stderr, "total_num_small = %ld\n", total_num_small); + fprintf(stderr, "total_bytes_small = %ld\n", total_bytes_small); + if (cur_num_small) + fprintf(stderr, "CUR_NUM_SMALL = %ld\n", cur_num_small); + fprintf(stderr, "max_num_small = %ld\n", max_num_small); + +#ifdef NEED_FAR_POINTERS + fprintf(stderr, "total_num_medium = %ld\n", total_num_medium); + fprintf(stderr, "total_bytes_medium = %ld\n", total_bytes_medium); + if (cur_num_medium) + fprintf(stderr, "CUR_NUM_MEDIUM = %ld\n", cur_num_medium); + fprintf(stderr, "max_num_medium = %ld\n", max_num_medium); +#endif + + fprintf(stderr, "total_num_sarray = %ld\n", total_num_sarray); + fprintf(stderr, "total_bytes_sarray = %ld\n", total_bytes_sarray); + if (cur_num_sarray) + fprintf(stderr, "CUR_NUM_SARRAY = %ld\n", cur_num_sarray); + fprintf(stderr, "max_num_sarray = %ld\n", max_num_sarray); + + fprintf(stderr, "total_num_barray = %ld\n", total_num_barray); + fprintf(stderr, "total_bytes_barray = %ld\n", total_bytes_barray); + if (cur_num_barray) + fprintf(stderr, "CUR_NUM_BARRAY = %ld\n", cur_num_barray); + fprintf(stderr, "max_num_barray = %ld\n", max_num_barray); +} + +#endif /* MEM_STATS */ + + +LOCAL void +out_of_memory (int which) +/* Report an out-of-memory error and stop execution */ +/* If we compiled MEM_STATS support, report alloc requests before dying */ +{ +#ifdef MEM_STATS + j_mem_stats(); +#endif + ERREXIT1(methods, "Insufficient memory (case %d)", which); +} + + + +METHODDEF void * +alloc_small (size_t sizeofobject) +/* Allocate a "small" (all-in-memory) object */ +{ + void * result; + +#ifdef MEM_STATS + total_num_small++; + total_bytes_small += sizeofobject + MALLOC_OVERHEAD; + cur_num_small++; + if (cur_num_small > max_num_small) max_num_small = cur_num_small; +#endif + + result = malloc(sizeofobject); + if (result == NULL) + out_of_memory(1); + return result; +} + + +METHODDEF void +free_small (void *ptr) +/* Free a "small" (all-in-memory) object */ +{ + free(ptr); + +#ifdef MEM_STATS + cur_num_small--; +#endif +} + + +#ifdef NEED_FAR_POINTERS + +METHODDEF void FAR * +alloc_medium (size_t sizeofobject) +/* Allocate a "medium" (all in memory, but in far heap) object */ +{ + void FAR * result; + +#ifdef MEM_STATS + total_num_medium++; + total_bytes_medium += sizeofobject + MALLOC_FAR_OVERHEAD; + cur_num_medium++; + if (cur_num_medium > max_num_medium) max_num_medium = cur_num_medium; +#endif + + result = far_malloc(sizeofobject); + if (result == NULL) + out_of_memory(2); + return result; +} + + +METHODDEF void +free_medium (void FAR *ptr) +/* Free a "medium" (all in memory, but in far heap) object */ +{ + far_free(ptr); + +#ifdef MEM_STATS + cur_num_medium--; +#endif +} + +#endif /* NEED_FAR_POINTERS */ + + +METHODDEF JSAMPARRAY +alloc_small_sarray (long samplesperrow, long numrows) +/* Allocate a "small" (all-in-memory) 2-D sample array */ +{ + JSAMPARRAY result; + long i; + +#ifdef MEM_STATS + total_num_sarray++; + total_bytes_sarray += (samplesperrow * SIZEOF(JSAMPLE) + MALLOC_FAR_OVERHEAD) + * numrows; + cur_num_sarray++; + if (cur_num_sarray > max_num_sarray) max_num_sarray = cur_num_sarray; +#endif + + /* Get space for row pointers; this is always "near" on 80x86 */ + result = (JSAMPARRAY) alloc_small((size_t) (numrows * SIZEOF(JSAMPROW))); + + /* Get the rows themselves; on 80x86 these are "far" */ + for (i = 0; i < numrows; i++) { + result[i] = (JSAMPROW) far_malloc((size_t) (samplesperrow * SIZEOF(JSAMPLE))); + if (result[i] == NULL) + out_of_memory(3); + } + + return result; +} + + +METHODDEF void +free_small_sarray (JSAMPARRAY ptr, long numrows) +/* Free a "small" (all-in-memory) 2-D sample array */ +{ + long i; + + /* Free the rows themselves; on 80x86 these are "far" */ + for (i = 0; i < numrows; i++) { + far_free((void FAR *) ptr[i]); + } + + /* Free space for row pointers; this is always "near" on 80x86 */ + free_small((void *) ptr); + +#ifdef MEM_STATS + cur_num_sarray--; +#endif +} + + +METHODDEF JBLOCKARRAY +alloc_small_barray (long blocksperrow, long numrows) +/* Allocate a "small" (all-in-memory) 2-D coefficient-block array */ +{ + JBLOCKARRAY result; + long i; + +#ifdef MEM_STATS + total_num_barray++; + total_bytes_barray += (blocksperrow * SIZEOF(JBLOCK) + MALLOC_FAR_OVERHEAD) + * numrows; + cur_num_barray++; + if (cur_num_barray > max_num_barray) max_num_barray = cur_num_barray; +#endif + + /* Get space for row pointers; this is always "near" on 80x86 */ + result = (JBLOCKARRAY) alloc_small((size_t) (numrows * SIZEOF(JBLOCKROW))); + + /* Get the rows themselves; on 80x86 these are "far" */ + for (i = 0; i < numrows; i++) { + result[i] = (JBLOCKROW) far_malloc((size_t) (blocksperrow * SIZEOF(JBLOCK))); + if (result[i] == NULL) + out_of_memory(4); + } + + return result; +} + + +METHODDEF void +free_small_barray (JBLOCKARRAY ptr, long numrows) +/* Free a "small" (all-in-memory) 2-D coefficient-block array */ +{ + long i; + + /* Free the rows themselves; on 80x86 these are "far" */ + for (i = 0; i < numrows; i++) { + far_free((void FAR *) ptr[i]); + } + + /* Free space for row pointers; this is always "near" on 80x86 */ + free_small((void *) ptr); + +#ifdef MEM_STATS + cur_num_barray--; +#endif +} + + + +/* + * About "big" array management: + * + * To allow machines with limited memory to handle large images, + * all processing in the JPEG system is done a few pixel or block rows + * at a time. The above "small" array routines are only used to allocate + * strip buffers (as wide as the image, but just a few rows high). + * In some cases multiple passes must be made over the data. In these + * cases the "big" array routines are used. The array is still accessed + * a strip at a time, but the memory manager must save the whole array + * for repeated accesses. The intended implementation is that there is + * a strip buffer in memory (as high as is possible given the desired memory + * limit), plus a backing file that holds the rest of the array. + * + * The request_big_array routines are told the total size of the image (in case + * it is useful to know the total file size that will be needed). They are + * also given the unit height, which is the number of rows that will be + * accessed at once; the in-memory buffer should usually be made a multiple of + * this height for best efficiency. + * + * The request routines create control blocks (and may open backing files), + * but they don't create the in-memory buffers. This is postponed until + * alloc_big_arrays is called. At that time the total amount of space needed + * is known (approximately, anyway), so free memory can be divided up fairly. + * + * The access_big_array routines are responsible for making a specific strip + * area accessible (after reading or writing the backing file, if necessary). + * Note that the access routines are told whether the caller intends to modify + * the accessed strip; during a read-only pass this saves having to rewrite + * data to disk. + * + * The typical access pattern is one top-to-bottom pass to write the data, + * followed by one or more read-only top-to-bottom passes. However, other + * access patterns may occur while reading. For example, translation of image + * formats that use bottom-to-top scan order will require bottom-to-top read + * passes. The memory manager need not support multiple write passes nor + * funny write orders (meaning that rearranging rows must be handled while + * reading data out of the big array, not while putting it in). + * + * In current usage, the access requests are always for nonoverlapping strips; + * that is, successive access start_row numbers always differ by exactly the + * unitheight. This allows fairly simple buffer dump/reload logic if the + * in-memory buffer is made a multiple of the unitheight. It would be + * possible to keep subsampled rather than fullsize data in the "big" arrays, + * thus reducing temp file size, if we supported overlapping strip access + * (access requests differing by less than the unitheight). At the moment + * I don't believe this is worth the extra complexity. + * + * This particular implementation doesn't use temp files; the whole of a big + * array is allocated in (virtual) memory, and any swapping is done behind the + * scenes by the operating system. + */ + + + +/* The control blocks for virtual arrays. + * These are pretty minimal in this implementation. + * Note: in this implementation we could realize big arrays + * at request time and make alloc_big_arrays a no-op; + * however, doing it separately keeps callers honest. + */ + +struct big_sarray_control { + JSAMPARRAY mem_buffer; /* memory buffer (the whole thing, here) */ + long rows_in_mem; /* Height of memory buffer */ + long samplesperrow; /* Width of memory buffer */ + long unitheight; /* # of rows accessed by access_big_sarray() */ + big_sarray_ptr next; /* list link for unrealized arrays */ +}; + +struct big_barray_control { + JBLOCKARRAY mem_buffer; /* memory buffer (the whole thing, here) */ + long rows_in_mem; /* Height of memory buffer */ + long blocksperrow; /* Width of memory buffer */ + long unitheight; /* # of rows accessed by access_big_barray() */ + big_barray_ptr next; /* list link for unrealized arrays */ +}; + + +/* Headers of lists of control blocks for unrealized big arrays */ +static big_sarray_ptr unalloced_sarrays; +static big_barray_ptr unalloced_barrays; + + +METHODDEF big_sarray_ptr +request_big_sarray (long samplesperrow, long numrows, long unitheight) +/* Request a "big" (virtual-memory) 2-D sample array */ +{ + big_sarray_ptr result; + + /* get control block */ + result = (big_sarray_ptr) alloc_small(SIZEOF(struct big_sarray_control)); + + result->mem_buffer = NULL; /* lets access routine spot premature access */ + result->rows_in_mem = numrows; + result->samplesperrow = samplesperrow; + result->unitheight = unitheight; + result->next = unalloced_sarrays; /* add to list of unallocated arrays */ + unalloced_sarrays = result; + + return result; +} + + +METHODDEF big_barray_ptr +request_big_barray (long blocksperrow, long numrows, long unitheight) +/* Request a "big" (virtual-memory) 2-D coefficient-block array */ +{ + big_barray_ptr result; + + /* get control block */ + result = (big_barray_ptr) alloc_small(SIZEOF(struct big_barray_control)); + + result->mem_buffer = NULL; /* lets access routine spot premature access */ + result->rows_in_mem = numrows; + result->blocksperrow = blocksperrow; + result->unitheight = unitheight; + result->next = unalloced_barrays; /* add to list of unallocated arrays */ + unalloced_barrays = result; + + return result; +} + + +METHODDEF void +alloc_big_arrays (long extra_small_samples, long extra_small_blocks, + long extra_medium_space) +/* Allocate the in-memory buffers for any unrealized "big" arrays */ +/* 'extra' values are upper bounds for total future small-array requests */ +/* and far-heap requests */ +{ + /* In this implementation we just malloc the whole arrays */ + /* and expect the system's virtual memory to worry about swapping them */ + big_sarray_ptr sptr; + big_barray_ptr bptr; + + for (sptr = unalloced_sarrays; sptr != NULL; sptr = sptr->next) { + sptr->mem_buffer = alloc_small_sarray(sptr->samplesperrow, + sptr->rows_in_mem); + } + + for (bptr = unalloced_barrays; bptr != NULL; bptr = bptr->next) { + bptr->mem_buffer = alloc_small_barray(bptr->blocksperrow, + bptr->rows_in_mem); + } + + unalloced_sarrays = NULL; /* reset for possible future cycles */ + unalloced_barrays = NULL; +} + + +METHODDEF JSAMPARRAY +access_big_sarray (big_sarray_ptr ptr, long start_row, boolean writable) +/* Access the part of a "big" sample array starting at start_row */ +/* and extending for ptr->unitheight rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + /* debugging check */ + if (start_row < 0 || start_row+ptr->unitheight > ptr->rows_in_mem || + ptr->mem_buffer == NULL) + ERREXIT(methods, "Bogus access_big_sarray request"); + + return ptr->mem_buffer + start_row; +} + + +METHODDEF JBLOCKARRAY +access_big_barray (big_barray_ptr ptr, long start_row, boolean writable) +/* Access the part of a "big" coefficient-block array starting at start_row */ +/* and extending for ptr->unitheight rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + /* debugging check */ + if (start_row < 0 || start_row+ptr->unitheight > ptr->rows_in_mem || + ptr->mem_buffer == NULL) + ERREXIT(methods, "Bogus access_big_barray request"); + + return ptr->mem_buffer + start_row; +} + + +METHODDEF void +free_big_sarray (big_sarray_ptr ptr) +/* Free a "big" (virtual-memory) 2-D sample array */ +{ + free_small_sarray(ptr->mem_buffer, ptr->rows_in_mem); + free_small((void *) ptr); /* free the control block too */ +} + + +METHODDEF void +free_big_barray (big_barray_ptr ptr) +/* Free a "big" (virtual-memory) 2-D coefficient-block array */ +{ + free_small_barray(ptr->mem_buffer, ptr->rows_in_mem); + free_small((void *) ptr); /* free the control block too */ +} + + + +/* + * The method selection routine for virtual memory systems. + * The system-dependent setup routine should call this routine + * to install the necessary method pointers in the supplied struct. + */ + +GLOBAL void +jselvirtmem (external_methods_ptr emethods) +{ + methods = emethods; /* save struct addr for error exit access */ + + emethods->alloc_small = alloc_small; + emethods->free_small = free_small; +#ifdef NEED_FAR_POINTERS + emethods->alloc_medium = alloc_medium; + emethods->free_medium = free_medium; +#endif + emethods->alloc_small_sarray = alloc_small_sarray; + emethods->free_small_sarray = free_small_sarray; + emethods->alloc_small_barray = alloc_small_barray; + emethods->free_small_barray = free_small_barray; + emethods->request_big_sarray = request_big_sarray; + emethods->request_big_barray = request_big_barray; + emethods->alloc_big_arrays = alloc_big_arrays; + emethods->access_big_sarray = access_big_sarray; + emethods->access_big_barray = access_big_barray; + emethods->free_big_sarray = free_big_sarray; + emethods->free_big_barray = free_big_barray; + + unalloced_sarrays = NULL; /* make sure list headers are empty */ + unalloced_barrays = NULL; +} diff --git a/jwrgif.c b/jwrgif.c new file mode 100644 index 0000000..44062ec --- /dev/null +++ b/jwrgif.c @@ -0,0 +1,497 @@ +/* + * jwrgif.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in GIF format. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + * + * These routines are invoked via the methods put_pixel_rows, put_color_map, + * and output_init/term. + */ + +/* + * This code is loosely based on ppmtogif from the PBMPLUS distribution + * of Feb. 1991. That file contains the following copyright notice: + * Based on GIFENCODE by David Rowley . + * Lempel-Ziv compression based on "compress" by Spencer W. Thomas et al. + * Copyright (C) 1989 by Jef Poskanzer. + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "as is" without express or + * implied warranty. + * + * We are also required to state that + * "The Graphics Interchange Format(c) is the Copyright property of + * CompuServe Incorporated. GIF(sm) is a Service Mark property of + * CompuServe Incorporated." + */ + +#include "jinclude.h" + +#ifdef GIF_SUPPORTED + + +static decompress_info_ptr dcinfo; /* to avoid passing to all functions */ + +#define MAX_LZW_BITS 12 /* maximum LZW code size (4096 symbols) */ + +typedef INT16 code_int; /* must hold -1 .. 2**MAX_LZW_BITS */ + +#define LZW_TABLE_SIZE ((code_int) 1 << MAX_LZW_BITS) + +#define HSIZE 5003 /* hash table size for 80% occupancy */ + +typedef int hash_int; /* must hold -2*HSIZE..2*HSIZE */ + +static int n_bits; /* current number of bits/code */ +static code_int maxcode; /* maximum code, given n_bits */ +#define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1) + +static int init_bits; /* initial n_bits ... restored after clear */ + +static code_int ClearCode; /* clear code (doesn't change) */ +static code_int EOFCode; /* EOF code (ditto) */ + +static code_int free_code; /* first not-yet-used symbol code */ + +/* + * The LZW hash table consists of three parallel arrays: + * hash_code[i] code of symbol in slot i, or 0 if empty slot + * hash_prefix[i] symbol's prefix code; undefined if empty slot + * hash_suffix[i] symbol's suffix character; undefined if empty slot + * where slot values (i) range from 0 to HSIZE-1. + * + * Algorithm: use open addressing double hashing (no chaining) on the + * prefix code / suffix character combination. We do a variant of Knuth's + * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime + * secondary probe. + * + * The hash tables are allocated from FAR heap space since they would use up + * rather a lot of the near data space in a PC. + */ + +static code_int FAR *hash_code; /* => hash table of symbol codes */ +static code_int FAR *hash_prefix; /* => hash table of prefix symbols */ +static UINT8 FAR *hash_suffix; /* => hash table of suffix bytes */ + + +/* + * Routines to package compressed data bytes into GIF data blocks. + * A data block consists of a count byte (1..255) and that many data bytes. + */ + +static int bytesinpkt; /* # of bytes in current packet */ +static char packetbuf[256]; /* workspace for accumulating packet */ + + +LOCAL void +flush_packet (void) +/* flush any accumulated data */ +{ + if (bytesinpkt > 0) { /* never write zero-length packet */ + packetbuf[0] = bytesinpkt++; + if (fwrite(packetbuf, 1, bytesinpkt, dcinfo->output_file) != bytesinpkt) + ERREXIT(dcinfo->emethods, "Output file write error"); + bytesinpkt = 0; + } +} + + +LOCAL void +char_out (int c) +/* Add a character to current packet; flush to disk if necessary */ +{ + packetbuf[++bytesinpkt] = c; + if (bytesinpkt >= 255) + flush_packet(); +} + + +/* Routine to convert variable-width codes into a byte stream */ + +static INT32 cur_accum; /* holds bits not yet output */ +static int cur_bits; /* # of bits in cur_accum */ + + +LOCAL void +output (code_int code) +/* Emit a code of n_bits bits */ +/* Uses cur_accum and cur_bits to reblock into 8-bit bytes */ +{ + if (cur_bits > 0) + cur_accum |= ((INT32) code << cur_bits); + else + cur_accum = code; + cur_bits += n_bits; + + while (cur_bits >= 8) { + char_out((int) (cur_accum & 0xFF)); + cur_accum >>= 8; + cur_bits -= 8; + } + + /* + * If the next entry is going to be too big for the code size, + * then increase it, if possible. We do this here to ensure + * that it's done in sync with the decoder's codesize increases. + */ + if (free_code > maxcode) { + n_bits++; + if (n_bits == MAX_LZW_BITS) + maxcode = LZW_TABLE_SIZE; /* free_code will never exceed this */ + else + maxcode = MAXCODE(n_bits); + } +} + + +/* The LZW algorithm proper */ + +static code_int waiting_code; /* symbol not yet output; may be extendable */ +static boolean first_byte; /* if TRUE, waiting_code is not valid */ + + +LOCAL void +clear_hash (void) +/* Fill the hash table with empty entries */ +{ + /* It's sufficient to zero hash_code[] */ + jzero_far((void FAR *) hash_code, HSIZE * SIZEOF(code_int)); +} + + +LOCAL void +clear_block (void) +/* Reset compressor and issue a Clear code */ +{ + clear_hash(); /* delete all the symbols */ + free_code = ClearCode + 2; + output(ClearCode); /* inform decoder */ + n_bits = init_bits; /* reset code size */ + maxcode = MAXCODE(n_bits); +} + + +LOCAL void +compress_init (int i_bits) +/* Initialize LZW compressor */ +{ + /* init all the static variables */ + n_bits = init_bits = i_bits; + maxcode = MAXCODE(n_bits); + ClearCode = ((code_int) 1 << (init_bits - 1)); + EOFCode = ClearCode + 1; + free_code = ClearCode + 2; + first_byte = TRUE; /* no waiting symbol yet */ + /* init output buffering vars */ + bytesinpkt = 0; + cur_accum = 0; + cur_bits = 0; + /* clear hash table */ + clear_hash(); + /* GIF specifies an initial Clear code */ + output(ClearCode); +} + + +LOCAL void +compress_byte (int c) +/* Accept and compress one 8-bit byte */ +{ + register hash_int i; + register hash_int disp; + + if (first_byte) { /* need to initialize waiting_code */ + waiting_code = c; + first_byte = FALSE; + return; + } + + /* Probe hash table to see if a symbol exists for + * waiting_code followed by c. + * If so, replace waiting_code by that symbol and return. + */ + i = ((hash_int) c << (MAX_LZW_BITS-8)) + waiting_code; + /* i is less than twice 2**MAX_LZW_BITS, therefore less than twice HSIZE */ + if (i >= HSIZE) + i -= HSIZE; + + if (hash_code[i] != 0) { /* is first probed slot empty? */ + if (hash_prefix[i] == waiting_code && hash_suffix[i] == c) { + waiting_code = hash_code[i]; + return; + } + if (i == 0) /* secondary hash (after G. Knott) */ + disp = 1; + else + disp = HSIZE - i; + while (1) { + i -= disp; + if (i < 0) + i += HSIZE; + if (hash_code[i] == 0) + break; /* hit empty slot */ + if (hash_prefix[i] == waiting_code && hash_suffix[i] == c) { + waiting_code = hash_code[i]; + return; + } + } + } + + /* here when hashtable[i] is an empty slot; desired symbol not in table */ + output(waiting_code); + if (free_code < LZW_TABLE_SIZE) { + hash_code[i] = free_code++; /* add symbol to hashtable */ + hash_prefix[i] = waiting_code; + hash_suffix[i] = c; + } else + clear_block(); + waiting_code = c; +} + + +LOCAL void +compress_term (void) +/* Clean up at end */ +{ + /* Flush out the buffered code */ + if (! first_byte) + output(waiting_code); + /* Send an EOF code */ + output(EOFCode); + /* Flush the bit-packing buffer */ + if (cur_bits > 0) { + char_out((int) (cur_accum & 0xFF)); + } + /* Flush the packet buffer */ + flush_packet(); +} + + +/* GIF header construction */ + + +LOCAL void +put_word (UINT16 w) +/* Emit a 16-bit word, LSB first */ +{ + putc(w & 0xFF, dcinfo->output_file); + putc((w >> 8) & 0xFF, dcinfo->output_file); +} + + +LOCAL void +put_3bytes (int val) +/* Emit 3 copies of same byte value --- handy subr for colormap construction */ +{ + putc(val, dcinfo->output_file); + putc(val, dcinfo->output_file); + putc(val, dcinfo->output_file); +} + + +LOCAL void +emit_header (int num_colors, JSAMPARRAY colormap) +/* Output the GIF file header, including color map */ +/* If colormap==NULL, synthesize a gray-scale colormap */ +{ + int BitsPerPixel, ColorMapSize, InitCodeSize, FlagByte; + int i; + + if (num_colors > 256) + ERREXIT(dcinfo->emethods, "GIF can only handle 256 colors"); + /* Compute bits/pixel and related values */ + if (num_colors <= 2) + BitsPerPixel = 1; + else if (num_colors <= 4) + BitsPerPixel = 2; + else if (num_colors <= 8) + BitsPerPixel = 3; + else if (num_colors <= 16) + BitsPerPixel = 4; + else if (num_colors <= 32) + BitsPerPixel = 5; + else if (num_colors <= 64) + BitsPerPixel = 6; + else if (num_colors <= 128) + BitsPerPixel = 7; + else + BitsPerPixel = 8; + ColorMapSize = 1 << BitsPerPixel; + if (BitsPerPixel <= 1) + InitCodeSize = 2; + else + InitCodeSize = BitsPerPixel; + /* + * Write the GIF header. + * Note that we generate a plain GIF87 header for maximum compatibility. + */ + fwrite("GIF87a", 1, 6, dcinfo->output_file); + /* Write the Logical Screen Descriptor */ + put_word((UINT16) dcinfo->image_width); + put_word((UINT16) dcinfo->image_height); + FlagByte = 0x80; /* Yes, there is a global color table */ + FlagByte |= (BitsPerPixel-1) << 4; /* color resolution */ + FlagByte |= (BitsPerPixel-1); /* size of global color table */ + putc(FlagByte, dcinfo->output_file); + putc(0, dcinfo->output_file); /* Background color index */ + putc(0, dcinfo->output_file); /* Reserved in GIF87 (aspect ratio in GIF89) */ + /* Write the Global Color Map */ + for (i=0; i < ColorMapSize; i++) { + if (i < num_colors) { + if (colormap != NULL) { + if (dcinfo->out_color_space == CS_RGB) { + /* Normal case: RGB color map */ + putc(GETJSAMPLE(colormap[0][i]), dcinfo->output_file); + putc(GETJSAMPLE(colormap[1][i]), dcinfo->output_file); + putc(GETJSAMPLE(colormap[2][i]), dcinfo->output_file); + } else { + /* Grayscale "color map": possible if quantizing grayscale image */ + put_3bytes(GETJSAMPLE(colormap[0][i])); + } + } else { + /* Create a gray-scale map of num_colors values, range 0..255 */ + put_3bytes((i * 255 + (num_colors-1)/2) / (num_colors-1)); + } + } else { + /* fill out the map to a power of 2 */ + put_3bytes(0); + } + } + /* Write image separator and Image Descriptor */ + putc(',', dcinfo->output_file); /* separator */ + put_word((UINT16) 0); /* left/top offset */ + put_word((UINT16) 0); + put_word((UINT16) dcinfo->image_width); /* image size */ + put_word((UINT16) dcinfo->image_height); + /* flag byte: not interlaced, no local color map */ + putc(0x00, dcinfo->output_file); + /* Write Initial Code Size byte */ + putc(InitCodeSize, dcinfo->output_file); + + /* Initialize for LZW compression of image data */ + compress_init(InitCodeSize+1); +} + + + +/* + * Initialize for GIF output. + */ + +METHODDEF void +output_init (decompress_info_ptr cinfo) +{ + dcinfo = cinfo; /* save for use by local routines */ + if (cinfo->final_out_comps != 1) /* safety check */ + ERREXIT(cinfo->emethods, "GIF output got confused"); + /* Allocate space for hash table */ + hash_code = (code_int FAR *) (*cinfo->emethods->alloc_medium) + (HSIZE * SIZEOF(code_int)); + hash_prefix = (code_int FAR *) (*cinfo->emethods->alloc_medium) + (HSIZE * SIZEOF(code_int)); + hash_suffix = (UINT8 FAR *) (*cinfo->emethods->alloc_medium) + (HSIZE * SIZEOF(UINT8)); + /* + * If we aren't quantizing, put_color_map won't be called, + * so emit the header now. This only happens with gray scale output. + * (If we are quantizing, wait for the color map to be provided.) + */ + if (! cinfo->quantize_colors) + emit_header(256, (JSAMPARRAY) NULL); +} + + +/* + * Write the color map. + */ + +METHODDEF void +put_color_map (decompress_info_ptr cinfo, int num_colors, JSAMPARRAY colormap) +{ + emit_header(num_colors, colormap); +} + + +/* + * Write some pixel data. + */ + +METHODDEF void +put_pixel_rows (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE pixel_data) +{ + register JSAMPROW ptr; + register long col; + register long width = cinfo->image_width; + register int row; + + for (row = 0; row < num_rows; row++) { + ptr = pixel_data[0][row]; + for (col = width; col > 0; col--) { + compress_byte(GETJSAMPLE(*ptr)); + ptr++; + } + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +output_term (decompress_info_ptr cinfo) +{ + /* Flush LZW mechanism */ + compress_term(); + /* Write a zero-length data block to end the series */ + putc(0, cinfo->output_file); + /* Write the GIF terminator mark */ + putc(';', cinfo->output_file); + /* Make sure we wrote the output file OK */ + fflush(cinfo->output_file); + if (ferror(cinfo->output_file)) + ERREXIT(cinfo->emethods, "Output file write error"); + /* Free space */ + (*cinfo->emethods->free_medium) ((void FAR *) hash_code); + (*cinfo->emethods->free_medium) ((void FAR *) hash_prefix); + (*cinfo->emethods->free_medium) ((void FAR *) hash_suffix); +} + + +/* + * The method selection routine for GIF format output. + * This should be called from d_ui_method_selection if GIF output is wanted. + */ + +GLOBAL void +jselwgif (decompress_info_ptr cinfo) +{ + cinfo->methods->output_init = output_init; + cinfo->methods->put_color_map = put_color_map; + cinfo->methods->put_pixel_rows = put_pixel_rows; + cinfo->methods->output_term = output_term; + + if (cinfo->out_color_space != CS_GRAYSCALE && + cinfo->out_color_space != CS_RGB) + ERREXIT(cinfo->emethods, "GIF output must be grayscale or RGB"); + + /* Force quantization if color or if > 8 bits input */ + if (cinfo->out_color_space == CS_RGB || cinfo->data_precision > 8) { + /* Force quantization to at most 256 colors */ + cinfo->quantize_colors = TRUE; + if (cinfo->desired_number_of_colors > 256) + cinfo->desired_number_of_colors = 256; + } +} + +#endif /* GIF_SUPPORTED */ diff --git a/jwrjfif.c b/jwrjfif.c new file mode 100644 index 0000000..cc379ac --- /dev/null +++ b/jwrjfif.c @@ -0,0 +1,468 @@ +/* + * jwrjfif.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write standard JPEG file headers/markers. + * The file format created is a raw JPEG data stream with (optionally) an + * APP0 marker per the JFIF spec. This will handle baseline and + * JFIF-convention JPEG files, although there is currently no provision + * for inserting a thumbnail image in the JFIF header. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. However, the changes to write to something + * else are localized in the macros appearing just below. + * + * These routines are invoked via the methods write_file_header, + * write_scan_header, write_jpeg_data, write_scan_trailer, and + * write_file_trailer. + */ + +#include "jinclude.h" + +#ifdef JFIF_SUPPORTED + + +/* + * To output to something other than a stdio stream, you'd need to redefine + * these macros. + */ + +/* Write a single byte */ +#define emit_byte(cinfo,x) putc((x), cinfo->output_file) + +/* Write some bytes from a (char *) buffer */ +#define WRITE_BYTES(cinfo,dataptr,datacount) \ + { if (fwrite((dataptr), 1, (datacount), cinfo->output_file) != (datacount)) \ + ERREXIT(cinfo->emethods, "Output file write error"); } + +/* Clean up and verify successful output */ +#define CHECK_OUTPUT(cinfo) \ + { fflush(cinfo->output_file); \ + if (ferror(cinfo->output_file)) \ + ERREXIT(cinfo->emethods, "Output file write error"); } + + +/* End of stdio-specific code. */ + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +LOCAL void +emit_marker (compress_info_ptr cinfo, JPEG_MARKER mark) +/* Emit a marker code */ +{ + emit_byte(cinfo, 0xFF); + emit_byte(cinfo, mark); +} + + +LOCAL void +emit_2bytes (compress_info_ptr cinfo, int value) +/* Emit a 2-byte integer; these are always MSB first in JPEG files */ +{ + emit_byte(cinfo, (value >> 8) & 0xFF); + emit_byte(cinfo, value & 0xFF); +} + + +LOCAL int +emit_dqt (compress_info_ptr cinfo, int index) +/* Emit a DQT marker */ +/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */ +{ + QUANT_TBL_PTR data = cinfo->quant_tbl_ptrs[index]; + int prec = 0; + int i; + + for (i = 0; i < DCTSIZE2; i++) { + if (data[i] > 255) + prec = 1; + } + + emit_marker(cinfo, M_DQT); + + emit_2bytes(cinfo, prec ? DCTSIZE2*2 + 1 + 2 : DCTSIZE2 + 1 + 2); + + emit_byte(cinfo, index + (prec<<4)); + + for (i = 0; i < DCTSIZE2; i++) { + if (prec) + emit_byte(cinfo, data[i] >> 8); + emit_byte(cinfo, data[i] & 0xFF); + } + + return prec; +} + + +LOCAL void +emit_dht (compress_info_ptr cinfo, int index, boolean is_ac) +/* Emit a DHT marker */ +{ + HUFF_TBL * htbl; + int length, i; + + if (is_ac) { + htbl = cinfo->ac_huff_tbl_ptrs[index]; + index += 0x10; /* output index has AC bit set */ + } else { + htbl = cinfo->dc_huff_tbl_ptrs[index]; + } + + if (! htbl->sent_table) { + emit_marker(cinfo, M_DHT); + + length = 0; + for (i = 1; i <= 16; i++) + length += htbl->bits[i]; + + emit_2bytes(cinfo, length + 2 + 1 + 16); + emit_byte(cinfo, index); + + for (i = 1; i <= 16; i++) + emit_byte(cinfo, htbl->bits[i]); + + for (i = 0; i < length; i++) + emit_byte(cinfo, htbl->huffval[i]); + + htbl->sent_table = TRUE; + } +} + + +LOCAL void +emit_dac (compress_info_ptr cinfo) +/* Emit a DAC marker */ +/* Since the useful info is so small, we want to emit all the tables in */ +/* one DAC marker. Therefore this routine does its own scan of the table. */ +{ + char dc_in_use[NUM_ARITH_TBLS]; + char ac_in_use[NUM_ARITH_TBLS]; + int length, i; + + for (i = 0; i < NUM_ARITH_TBLS; i++) + dc_in_use[i] = ac_in_use[i] = 0; + + for (i = 0; i < cinfo->num_components; i++) { + dc_in_use[cinfo->comp_info[i].dc_tbl_no] = 1; + ac_in_use[cinfo->comp_info[i].ac_tbl_no] = 1; + } + + length = 0; + for (i = 0; i < NUM_ARITH_TBLS; i++) + length += dc_in_use[i] + ac_in_use[i]; + + emit_marker(cinfo, M_DAC); + + emit_2bytes(cinfo, length*2 + 2); + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + if (dc_in_use[i]) { + emit_byte(cinfo, i); + emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4)); + } + if (ac_in_use[i]) { + emit_byte(cinfo, i + 0x10); + emit_byte(cinfo, cinfo->arith_ac_K[i]); + } + } +} + + +LOCAL void +emit_dri (compress_info_ptr cinfo) +/* Emit a DRI marker */ +{ + emit_marker(cinfo, M_DRI); + + emit_2bytes(cinfo, 4); /* fixed length */ + + emit_2bytes(cinfo, (int) cinfo->restart_interval); +} + + +LOCAL void +emit_sof (compress_info_ptr cinfo, JPEG_MARKER code) +/* Emit a SOF marker */ +{ + int i; + + emit_marker(cinfo, code); + + emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */ + + emit_byte(cinfo, cinfo->data_precision); + emit_2bytes(cinfo, (int) cinfo->image_height); + emit_2bytes(cinfo, (int) cinfo->image_width); + + emit_byte(cinfo, cinfo->num_components); + + for (i = 0; i < cinfo->num_components; i++) { + emit_byte(cinfo, cinfo->comp_info[i].component_id); + emit_byte(cinfo, (cinfo->comp_info[i].h_samp_factor << 4) + + cinfo->comp_info[i].v_samp_factor); + emit_byte(cinfo, cinfo->comp_info[i].quant_tbl_no); + } +} + + +LOCAL void +emit_sos (compress_info_ptr cinfo) +/* Emit a SOS marker */ +{ + int i; + + emit_marker(cinfo, M_SOS); + + emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */ + + emit_byte(cinfo, cinfo->comps_in_scan); + + for (i = 0; i < cinfo->comps_in_scan; i++) { + emit_byte(cinfo, cinfo->cur_comp_info[i]->component_id); + emit_byte(cinfo, (cinfo->cur_comp_info[i]->dc_tbl_no << 4) + + cinfo->cur_comp_info[i]->ac_tbl_no); + } + + emit_byte(cinfo, 0); /* Spectral selection start */ + emit_byte(cinfo, DCTSIZE2-1); /* Spectral selection end */ + emit_byte(cinfo, 0); /* Successive approximation */ +} + + +LOCAL void +emit_jfif_app0 (compress_info_ptr cinfo) +/* Emit a JFIF-compliant APP0 marker */ +{ + /* + * Length of APP0 block (2 bytes) + * Block ID (4 bytes - ASCII "JFIF") + * Zero byte (1 byte to terminate the ID string) + * Version Major, Minor (2 bytes - 0x01, 0x01) + * Units (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm) + * Xdpu (2 bytes - dots per unit horizontal) + * Ydpu (2 bytes - dots per unit vertical) + * Thumbnail X size (1 byte) + * Thumbnail Y size (1 byte) + */ + + emit_marker(cinfo, M_APP0); + + emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */ + + emit_byte(cinfo, 'J'); /* Identifier */ + emit_byte(cinfo, 'F'); + emit_byte(cinfo, 'I'); + emit_byte(cinfo, 'F'); + emit_byte(cinfo, 0); + emit_byte(cinfo, 1); /* Major version */ + emit_byte(cinfo, 1); /* Minor version */ + emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */ + emit_2bytes(cinfo, (int) cinfo->X_density); + emit_2bytes(cinfo, (int) cinfo->Y_density); + emit_byte(cinfo, 0); /* No thumbnail image */ + emit_byte(cinfo, 0); +} + + +/* + * Write the file header. + */ + + +METHODDEF void +write_file_header (compress_info_ptr cinfo) +{ + char qt_in_use[NUM_QUANT_TBLS]; + int i, prec; + boolean is_baseline; + + emit_marker(cinfo, M_SOI); /* first the SOI */ + + if (cinfo->write_JFIF_header) /* next an optional JFIF APP0 */ + emit_jfif_app0(cinfo); + + /* Emit DQT for each quantization table. */ + /* Note that doing it here means we can't adjust the QTs on-the-fly. */ + /* If we did want to do that, we'd have a problem with checking precision */ + /* for the is_baseline determination. */ + + for (i = 0; i < NUM_QUANT_TBLS; i++) + qt_in_use[i] = 0; + + for (i = 0; i < cinfo->num_components; i++) + qt_in_use[cinfo->comp_info[i].quant_tbl_no] = 1; + + prec = 0; + for (i = 0; i < NUM_QUANT_TBLS; i++) { + if (qt_in_use[i]) + prec += emit_dqt(cinfo, i); + } + /* now prec is nonzero iff there are any 16-bit quant tables. */ + + if (cinfo->restart_interval) + emit_dri(cinfo); + + /* Check for a non-baseline specification. */ + /* Note we assume that Huffman table numbers won't be changed later. */ + is_baseline = TRUE; + if (cinfo->arith_code || (cinfo->data_precision != 8)) + is_baseline = FALSE; + for (i = 0; i < cinfo->num_components; i++) { + if (cinfo->comp_info[i].dc_tbl_no > 1 || cinfo->comp_info[i].ac_tbl_no > 1) + is_baseline = FALSE; + } + if (prec && is_baseline) { + is_baseline = FALSE; + /* If it's baseline except for quantizer size, warn the user */ + TRACEMS(cinfo->emethods, 0, + "Caution: quantization tables are too coarse for baseline JPEG"); + } + + + /* Emit the proper SOF marker */ + if (cinfo->arith_code) + emit_sof(cinfo, M_SOF9); /* SOF code for arithmetic coding */ + else if (is_baseline) + emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */ + else + emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */ +} + + +/* + * Write the start of a scan (everything through the SOS marker). + */ + +METHODDEF void +write_scan_header (compress_info_ptr cinfo) +{ + int i; + + if (cinfo->arith_code) { + /* Emit arith conditioning info. We will have some duplication + * if the file has multiple scans, but it's so small it's hardly + * worth worrying about. + */ + emit_dac(cinfo); + } else { + /* Emit Huffman tables. Note that emit_dht takes care of + * suppressing duplicate tables. + */ + for (i = 0; i < cinfo->comps_in_scan; i++) { + emit_dht(cinfo, cinfo->cur_comp_info[i]->dc_tbl_no, FALSE); + emit_dht(cinfo, cinfo->cur_comp_info[i]->ac_tbl_no, TRUE); + } + } + + emit_sos(cinfo); +} + + +/* + * Write some bytes of compressed data within a scan. + */ + +METHODDEF void +write_jpeg_data (compress_info_ptr cinfo, char *dataptr, int datacount) +{ + WRITE_BYTES(cinfo, dataptr, datacount); +} + + +/* + * Finish up after a compressed scan (series of write_jpeg_data calls). + */ + +METHODDEF void +write_scan_trailer (compress_info_ptr cinfo) +{ + /* no work needed in this format */ +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +write_file_trailer (compress_info_ptr cinfo) +{ + emit_marker(cinfo, M_EOI); + /* Make sure we wrote the output file OK */ + CHECK_OUTPUT(cinfo); +} + + +/* + * The method selection routine for standard JPEG header writing. + * This should be called from c_ui_method_selection if appropriate. + */ + +GLOBAL void +jselwjfif (compress_info_ptr cinfo) +{ + cinfo->methods->write_file_header = write_file_header; + cinfo->methods->write_scan_header = write_scan_header; + cinfo->methods->write_jpeg_data = write_jpeg_data; + cinfo->methods->write_scan_trailer = write_scan_trailer; + cinfo->methods->write_file_trailer = write_file_trailer; +} + +#endif /* JFIF_SUPPORTED */ diff --git a/jwrppm.c b/jwrppm.c new file mode 100644 index 0000000..41687fe --- /dev/null +++ b/jwrppm.c @@ -0,0 +1,167 @@ +/* + * jwrppm.c + * + * Copyright (C) 1991, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in PPM format. + * The PBMPLUS library is required (well, it will be in the real version). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + * + * These routines are invoked via the methods put_pixel_rows, put_color_map, + * and output_init/term. + */ + +#include "jinclude.h" + +#ifdef PPM_SUPPORTED + + +static JSAMPARRAY color_map; /* saves color map passed by quantizer */ + + +/* + * Write the file header. + */ + +METHODDEF void +output_init (decompress_info_ptr cinfo) +{ + if (cinfo->out_color_space == CS_GRAYSCALE) { + /* emit header for raw PGM format */ + fprintf(cinfo->output_file, "P5\n%ld %ld\n%d\n", + cinfo->image_width, cinfo->image_height, 255); + } else if (cinfo->out_color_space == CS_RGB) { + /* emit header for raw PPM format */ + fprintf(cinfo->output_file, "P6\n%ld %ld\n%d\n", + cinfo->image_width, cinfo->image_height, 255); + } else { + ERREXIT(cinfo->emethods, "PPM output must be grayscale or RGB"); + } +} + + +/* + * Write some pixel data. + */ + +METHODDEF void +put_pixel_rows (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE pixel_data) +{ + register FILE * outfile = cinfo->output_file; + register JSAMPROW ptr0, ptr1, ptr2; + register long col; + register long width = cinfo->image_width; + register int row; + + if (cinfo->out_color_space == CS_GRAYSCALE) { + for (row = 0; row < num_rows; row++) { + ptr0 = pixel_data[0][row]; + for (col = width; col > 0; col--) { + putc(GETJSAMPLE(*ptr0), outfile); + ptr0++; + } + } + } else { + for (row = 0; row < num_rows; row++) { + ptr0 = pixel_data[0][row]; + ptr1 = pixel_data[1][row]; + ptr2 = pixel_data[2][row]; + for (col = width; col > 0; col--) { + putc(GETJSAMPLE(*ptr0), outfile); + ptr0++; + putc(GETJSAMPLE(*ptr1), outfile); + ptr1++; + putc(GETJSAMPLE(*ptr2), outfile); + ptr2++; + } + } + } +} + + +/* + * Write some pixel data when color quantization is in effect. + */ + +METHODDEF void +put_demapped_rows (decompress_info_ptr cinfo, int num_rows, + JSAMPIMAGE pixel_data) +{ + register FILE * outfile = cinfo->output_file; + register JSAMPROW ptr; + register long col; + register long width = cinfo->image_width; + register int row; + + if (cinfo->out_color_space == CS_GRAYSCALE) { + for (row = 0; row < num_rows; row++) { + ptr = pixel_data[0][row]; + for (col = width; col > 0; col--) { + putc(GETJSAMPLE(color_map[0][GETJSAMPLE(*ptr)]), outfile); + ptr++; + } + } + } else { + for (row = 0; row < num_rows; row++) { + ptr = pixel_data[0][row]; + for (col = width; col > 0; col--) { + register int pixval = GETJSAMPLE(*ptr); + + putc(GETJSAMPLE(color_map[0][pixval]), outfile); + putc(GETJSAMPLE(color_map[1][pixval]), outfile); + putc(GETJSAMPLE(color_map[2][pixval]), outfile); + ptr++; + } + } + } +} + + +/* + * Write the color map. + * For PPM output, we just demap the output data! + */ + +METHODDEF void +put_color_map (decompress_info_ptr cinfo, int num_colors, JSAMPARRAY colormap) +{ + color_map = colormap; /* save for use in output */ + cinfo->methods->put_pixel_rows = put_demapped_rows; +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF void +output_term (decompress_info_ptr cinfo) +{ + /* No work except to make sure we wrote the output file OK */ + fflush(cinfo->output_file); + if (ferror(cinfo->output_file)) + ERREXIT(cinfo->emethods, "Output file write error"); +} + + +/* + * The method selection routine for PPM format output. + * This should be called from d_ui_method_selection if PPM output is wanted. + */ + +GLOBAL void +jselwppm (decompress_info_ptr cinfo) +{ + cinfo->methods->output_init = output_init; + cinfo->methods->put_color_map = put_color_map; + cinfo->methods->put_pixel_rows = put_pixel_rows; + cinfo->methods->output_term = output_term; +} + +#endif /* PPM_SUPPORTED */ diff --git a/makcjpeg.cf b/makcjpeg.cf new file mode 100644 index 0000000..ea93ce4 --- /dev/null +++ b/makcjpeg.cf @@ -0,0 +1,5 @@ +L jcmain.mix jerror.mix jcdeflts.mix jrdgif.mix jrdppm.mix jwrjfif.mix +L jcarith.mix jccolor.mix jcexpand.mix jchuff.mix jcmaster.mix jcmcu.mix +L jcpipe.mix jcsample.mix jfwddct.mix jutils.mix jvirtmem.mix +fa; +b cjpeg,8K,48K, diff --git a/makcjpeg.lnk b/makcjpeg.lnk new file mode 100644 index 0000000..23702b2 --- /dev/null +++ b/makcjpeg.lnk @@ -0,0 +1,21 @@ +jcmain.obj + +jerror.obj + +jcdeflts.obj + +jrdgif.obj + +jrdppm.obj + +jwrjfif.obj + +jcarith.obj + +jccolor.obj + +jcexpand.obj + +jchuff.obj + +jcmaster.obj + +jcmcu.obj + +jcpipe.obj + +jcsample.obj + +jfwddct.obj + +jutils.obj + +jvirtmem.obj +cjpeg.exe /NOI +nul.map + +nul.def diff --git a/makdjpeg.cf b/makdjpeg.cf new file mode 100644 index 0000000..968af31 --- /dev/null +++ b/makdjpeg.cf @@ -0,0 +1,6 @@ +L jdmain.mix jerror.mix jrdjfif.mix jwrgif.mix jwrppm.mix +L jbsmooth.mix jdarith.mix jdcolor.mix jdhuff.mix jdmaster.mix jdmcu.mix +L jdpipe.mix jdsample.mix jquant1.mix jquant2.mix jrevdct.mix jutils.mix +L jvirtmem.mix +fa; +b djpeg,8K,48K, diff --git a/makdjpeg.lnk b/makdjpeg.lnk new file mode 100644 index 0000000..6e9107c --- /dev/null +++ b/makdjpeg.lnk @@ -0,0 +1,22 @@ +jdmain.obj + +jerror.obj + +jrdjfif.obj + +jwrgif.obj + +jwrppm.obj + +jbsmooth.obj + +jdarith.obj + +jdcolor.obj + +jdhuff.obj + +jdmaster.obj + +jdmcu.obj + +jdpipe.obj + +jdsample.obj + +jquant1.obj + +jquant2.obj + +jrevdct.obj + +jutils.obj + +jvirtmem.obj /NOI +djpeg.exe +nul.map + +nul.def diff --git a/makefile.amiga b/makefile.amiga new file mode 100644 index 0000000..2fde93a --- /dev/null +++ b/makefile.amiga @@ -0,0 +1,143 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is suitable for Amiga systems using Manx Aztec C ver 5.x. +# Thanks to D.J. James for this version. + +# See README and edit jconfig.h before saying "make" !! + +CC= cc + +# You may need to adjust these cc options: +CFLAGS= -MC -MD -DTWO_FILE_COMMANDLINE +LDFLAGS= +LDLIBS= -lml -lcl + +# miscellaneous OS-dependent stuff +LN= ln # linker +RM= delete quiet # file deletion command +AR= lb # library (.lib) file creation command + + +# source files +INCLUDES= jinclude.h jconfig.h jpegdata.h +SOURCES= jbsmooth.c jcarith.c jccolor.c jcdeflts.c jcexpand.c \ + jchuff.c jcmain.c jcmaster.c jcmcu.c jcpipe.c jcsample.c \ + jdarith.c jdcolor.c jdhuff.c jdmain.c jdmaster.c jdmcu.c \ + jdpipe.c jdsample.c jerror.c jfwddct.c jquant1.c jquant2.c \ + jrdjfif.c jrdgif.c jrdppm.c jrevdct.c jutils.c jvirtmem.c \ + jwrjfif.c jwrgif.c jwrppm.c egetopt.c +DOCS= README architecture codingrules +MAKEFILES= makefile.unix makefile.amiga \ + makefile.mc5 makefile.mc6 makcjpeg.lnk makdjpeg.lnk \ + makefile.pwc makcjpeg.cf makdjpeg.cf makljpeg.cf +TESTFILES= testorig.jpg testimg.ppm testimg.jpg +DISTFILES= $(DOCS) $(MAKEFILES) ansi2knr.c $(SOURCES) $(INCLUDES) $(TESTFILES) + +# compression objectfiles +COBJECTS = jcmain.o jcmaster.o jcdeflts.o jcarith.o jccolor.o jcexpand.o \ + jchuff.o jcmcu.o jcpipe.o jcsample.o jfwddct.o \ + jrdgif.o jrdppm.o jwrjfif.o \ + jutils.o jvirtmem.o jerror.o +# decompression objectfiles +DOBJECTS = jdmain.o jdmaster.o jbsmooth.o jdarith.o jdcolor.o jdhuff.o \ + jdmcu.o jdpipe.o jdsample.o jquant1.o jquant2.o jrevdct.o \ + jrdjfif.o jwrgif.o jwrppm.o \ + jutils.o jvirtmem.o jerror.o +# These objectfiles are included in libjpeg.lib (all but jcmain.o, jdmain.o) +LIBOBJECTS = jcmaster.o jcdeflts.o jcarith.o jccolor.o jcexpand.o \ + jchuff.o jcmcu.o jcpipe.o jcsample.o jfwddct.o \ + jrdgif.o jrdppm.o jwrjfif.o \ + jdmaster.o jbsmooth.o jdarith.o jdcolor.o jdhuff.o \ + jdmcu.o jdpipe.o jdsample.o jquant1.o jquant2.o jrevdct.o \ + jrdjfif.o jwrgif.o jwrppm.o \ + jutils.o jvirtmem.o jerror.o + + +all: cjpeg djpeg +# By default, libjpeg.lib is not built unless you explicitly request it. + + +# If you have a C compiler that doesn't understand function prototypes, +# uncomment the 5 lines below and make sure PROTO is not defined by jconfig.h. +# Then say "make ansi2knr" before "make". + +#.c.o: +# ./ansi2knr $*.c tmpansi.c +# $(CC) $(CFLAGS) -c tmpansi.c +# mv tmpansi.o $*.o +# $(RM) tmpansi.c + +ansi2knr: ansi2knr.c + $(CC) -o ansi2knr ansi2knr.c +# You may need to add one of -DBSD, -DVMS, or -DMSDOS to the line above. + + +cjpeg: $(COBJECTS) + $(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) $(LDLIBS) + +djpeg: $(DOBJECTS) + $(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) $(LDLIBS) + +# libjpeg.lib is useful if you are including the JPEG software in a larger +# program; you'd include it in your link, rather than the individual modules. +libjpeg.lib: $(LIBOBJECTS) + -$(RM) libjpeg.lib + $(AR) libjpeg.lib $(LIBOBJECTS) + +# Use the following to test the built library +#cjpeg: jcmain.o libjpeg.lib +# $(LN) $(LDFLAGS) -o cjpeg jcmain.o -llibjpeg $(LDLIBS) +# +#djpeg: jdmain.o libjpeg.lib +# $(LN) $(LDFLAGS) -o djpeg jdmain.o -llibjpeg $(LDLIBS) + +clean: + -$(RM) *.o cjpeg djpeg libjpeg.lib ansi2knr core tmpansi.* testout.ppm testout.jpg + +distribute: + -$(RM) jpegsrc.tar* + tar cvf jpegsrc.tar $(DISTFILES) + list jpegsrc.tar + compress -v jpegsrc.tar + list jpegsrc.tar* + +test: cjpeg djpeg + -$(RM) testout.ppm testout.jpg + ./djpeg testorig.jpg testout.ppm + ./cjpeg testimg.ppm testout.jpg + cmp testimg.ppm testout.ppm + cmp testimg.jpg testout.jpg + + +jbsmooth.o : jbsmooth.c jinclude.h jconfig.h jpegdata.h +jcarith.o : jcarith.c jinclude.h jconfig.h jpegdata.h +jccolor.o : jccolor.c jinclude.h jconfig.h jpegdata.h +jcdeflts.o : jcdeflts.c jinclude.h jconfig.h jpegdata.h +jcexpand.o : jcexpand.c jinclude.h jconfig.h jpegdata.h +jchuff.o : jchuff.c jinclude.h jconfig.h jpegdata.h +jcmain.o : jcmain.c jinclude.h jconfig.h jpegdata.h egetopt.c +jcmaster.o : jcmaster.c jinclude.h jconfig.h jpegdata.h +jcmcu.o : jcmcu.c jinclude.h jconfig.h jpegdata.h +jcpipe.o : jcpipe.c jinclude.h jconfig.h jpegdata.h +jcsample.o : jcsample.c jinclude.h jconfig.h jpegdata.h +jdarith.o : jdarith.c jinclude.h jconfig.h jpegdata.h +jdcolor.o : jdcolor.c jinclude.h jconfig.h jpegdata.h +jdhuff.o : jdhuff.c jinclude.h jconfig.h jpegdata.h +jdmain.o : jdmain.c jinclude.h jconfig.h jpegdata.h egetopt.c +jdmaster.o : jdmaster.c jinclude.h jconfig.h jpegdata.h +jdmcu.o : jdmcu.c jinclude.h jconfig.h jpegdata.h +jdpipe.o : jdpipe.c jinclude.h jconfig.h jpegdata.h +jdsample.o : jdsample.c jinclude.h jconfig.h jpegdata.h +jerror.o : jerror.c jinclude.h jconfig.h jpegdata.h +jfwddct.o : jfwddct.c jinclude.h jconfig.h jpegdata.h +jquant1.o : jquant1.c jinclude.h jconfig.h jpegdata.h +jquant2.o : jquant2.c jinclude.h jconfig.h jpegdata.h +jrdjfif.o : jrdjfif.c jinclude.h jconfig.h jpegdata.h +jrdgif.o : jrdgif.c jinclude.h jconfig.h jpegdata.h +jrdppm.o : jrdppm.c jinclude.h jconfig.h jpegdata.h +jrevdct.o : jrevdct.c jinclude.h jconfig.h jpegdata.h +jutils.o : jutils.c jinclude.h jconfig.h jpegdata.h +jvirtmem.o : jvirtmem.c jinclude.h jconfig.h jpegdata.h +jwrjfif.o : jwrjfif.c jinclude.h jconfig.h jpegdata.h +jwrgif.o : jwrgif.c jinclude.h jconfig.h jpegdata.h +jwrppm.o : jwrppm.c jinclude.h jconfig.h jpegdata.h diff --git a/makefile.mc5 b/makefile.mc5 new file mode 100644 index 0000000..eee9f21 --- /dev/null +++ b/makefile.mc5 @@ -0,0 +1,115 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is for Microsoft C for MS-DOS, version 5.x. + +# See README and edit jconfig.h before saying "make" !! + +# Microsoft's brain-damaged version of make uses nonstandard syntax (a blank +# line is needed to terminate a command list) and it simply scans the rules +# in order, rather than doing a true dependency-tree walk. Furthermore, +# expanded command lines can't exceed 128 chars (this is a DOS bug, not +# make's fault); so we can't just name all the objectfiles in the link steps. +# Instead we shove each objectfile into a library as it is made, and link +# from the library. The objectfiles are also kept separately as timestamps. + +# You may need to adjust these cc options: +CFLAGS= /AS /I. /W3 /Oail /Gs /DMEM_STATS # NB: /Gs turns off stack oflo checks +LDFLAGS= /Fm /F 2000 # /F hhhh sets stack size (in hex) +# In particular: +# Add /DMSDOS if your compiler doesn't automatically #define MSDOS. +# Add /DHAVE_GETOPT if your library includes getopt(3) (see jcmain.c, jdmain.c). +# /DMEM_STATS is optional -- it enables gathering of memory usage statistics. + +# compression objectfiles +COBJECTS = jcmain.obj jcmaster.obj jcdeflts.obj jcarith.obj jccolor.obj jcexpand.obj \ + jchuff.obj jcmcu.obj jcpipe.obj jcsample.obj jfwddct.obj \ + jrdgif.obj jrdppm.obj jwrjfif.obj \ + jutils.obj jvirtmem.obj jerror.obj +# decompression objectfiles +DOBJECTS = jdmain.obj jdmaster.obj jbsmooth.obj jdarith.obj jdcolor.obj jdhuff.obj \ + jdmcu.obj jdpipe.obj jdsample.obj jquant1.obj jquant2.obj jrevdct.obj \ + jrdjfif.obj jwrgif.obj jwrppm.obj \ + jutils.obj jvirtmem.obj jerror.obj + + +# inference rule used for all compilations except jcmain.c, jdmain.c +# notice that objectfile is also inserted into libjpeg.lib +.c.obj: + cl $(CFLAGS) /c $*.c + lib libjpeg -+$*.obj; + +# these two objectfiles are not inserted into libjpeg +# because they have duplicate global symbol names (notably main()). +jcmain.obj: jcmain.c jinclude.h jconfig.h jpegdata.h egetopt.c + cl $(CFLAGS) /c $*.c + +jdmain.obj: jdmain.c jinclude.h jconfig.h jpegdata.h egetopt.c + cl $(CFLAGS) /c $*.c + + +jbsmooth.obj: jbsmooth.c jinclude.h jconfig.h jpegdata.h + +jcarith.obj: jcarith.c jinclude.h jconfig.h jpegdata.h + +jccolor.obj: jccolor.c jinclude.h jconfig.h jpegdata.h + +jcdeflts.obj: jcdeflts.c jinclude.h jconfig.h jpegdata.h + +jcexpand.obj: jcexpand.c jinclude.h jconfig.h jpegdata.h + +jchuff.obj: jchuff.c jinclude.h jconfig.h jpegdata.h + +jcmaster.obj: jcmaster.c jinclude.h jconfig.h jpegdata.h + +jcmcu.obj: jcmcu.c jinclude.h jconfig.h jpegdata.h + +jcpipe.obj: jcpipe.c jinclude.h jconfig.h jpegdata.h + +jcsample.obj: jcsample.c jinclude.h jconfig.h jpegdata.h + +jdarith.obj: jdarith.c jinclude.h jconfig.h jpegdata.h + +jdcolor.obj: jdcolor.c jinclude.h jconfig.h jpegdata.h + +jdhuff.obj: jdhuff.c jinclude.h jconfig.h jpegdata.h + +jdmaster.obj: jdmaster.c jinclude.h jconfig.h jpegdata.h + +jdmcu.obj: jdmcu.c jinclude.h jconfig.h jpegdata.h + +jdpipe.obj: jdpipe.c jinclude.h jconfig.h jpegdata.h + +jdsample.obj: jdsample.c jinclude.h jconfig.h jpegdata.h + +jerror.obj: jerror.c jinclude.h jconfig.h jpegdata.h + +jfwddct.obj: jfwddct.c jinclude.h jconfig.h jpegdata.h + +jquant1.obj: jquant1.c jinclude.h jconfig.h jpegdata.h + +jquant2.obj: jquant2.c jinclude.h jconfig.h jpegdata.h + +jrdjfif.obj: jrdjfif.c jinclude.h jconfig.h jpegdata.h + +jrdgif.obj: jrdgif.c jinclude.h jconfig.h jpegdata.h + +jrdppm.obj: jrdppm.c jinclude.h jconfig.h jpegdata.h + +jrevdct.obj: jrevdct.c jinclude.h jconfig.h jpegdata.h + +jutils.obj: jutils.c jinclude.h jconfig.h jpegdata.h + +jvirtmem.obj: jvirtmem.c jinclude.h jconfig.h jpegdata.h + +jwrjfif.obj: jwrjfif.c jinclude.h jconfig.h jpegdata.h + +jwrgif.obj: jwrgif.c jinclude.h jconfig.h jpegdata.h + +jwrppm.obj: jwrppm.c jinclude.h jconfig.h jpegdata.h + + +cjpeg.exe: $(COBJECTS) + cl /Fecjpeg.exe jcmain.obj libjpeg.lib $(LDFLAGS) + +djpeg.exe: $(DOBJECTS) + cl /Fedjpeg.exe jdmain.obj libjpeg.lib $(LDFLAGS) diff --git a/makefile.mc6 b/makefile.mc6 new file mode 100644 index 0000000..b9ca60f --- /dev/null +++ b/makefile.mc6 @@ -0,0 +1,79 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is for Microsoft C for MS-DOS, version 6.x (use NMAKE). +# Thanks to Alan Wright and Chris Turner of Olivetti Research Ltd. + +# See README and edit jconfig.h before saying "make" !! + +all: cjpeg.exe djpeg.exe + +# compiler flags. -D gives a #define to the sources: +# -O default optimisation +# -W3 warning level 3 +# -Za ANSI conformance, defines__STDC__ but undefines far +# and near! +# -D__STDC__ pretend we have full ANSI compliance. MSC is near +# enough anyway +# -DMSDOS we are on an MSDOS machine +# -DMEM_STATS enable memory usage statistics (optional) +# -DHAVE_GETOPT library has getopt routine to parse cmnd line options +# -c compile, don't link (implicit in inference rules) + +CFLAGS = -c -O -W3 -DMSDOS -D__STDC__ -DMEM_STATS + + +# compression objectfiles +COBJECTS = jcmain.obj jcmaster.obj jcdeflts.obj jcarith.obj jccolor.obj jcexpand.obj \ + jchuff.obj jcmcu.obj jcpipe.obj jcsample.obj jfwddct.obj \ + jrdgif.obj jrdppm.obj jwrjfif.obj \ + jutils.obj jvirtmem.obj jerror.obj +# decompression objectfiles +DOBJECTS = jdmain.obj jdmaster.obj jbsmooth.obj jdarith.obj jdcolor.obj jdhuff.obj \ + jdmcu.obj jdpipe.obj jdsample.obj jquant1.obj jquant2.obj jrevdct.obj \ + jrdjfif.obj jwrgif.obj jwrppm.obj \ + jutils.obj jvirtmem.obj jerror.obj + + +# default rules in nmake will use cflags and compile the list below + +jbsmooth.o : jbsmooth.c jinclude.h jconfig.h jpegdata.h +jcarith.o : jcarith.c jinclude.h jconfig.h jpegdata.h +jccolor.o : jccolor.c jinclude.h jconfig.h jpegdata.h +jcdeflts.o : jcdeflts.c jinclude.h jconfig.h jpegdata.h +jcexpand.o : jcexpand.c jinclude.h jconfig.h jpegdata.h +jchuff.o : jchuff.c jinclude.h jconfig.h jpegdata.h +jcmain.o : jcmain.c jinclude.h jconfig.h jpegdata.h egetopt.c +jcmaster.o : jcmaster.c jinclude.h jconfig.h jpegdata.h +jcmcu.o : jcmcu.c jinclude.h jconfig.h jpegdata.h +jcpipe.o : jcpipe.c jinclude.h jconfig.h jpegdata.h +jcsample.o : jcsample.c jinclude.h jconfig.h jpegdata.h +jdarith.o : jdarith.c jinclude.h jconfig.h jpegdata.h +jdcolor.o : jdcolor.c jinclude.h jconfig.h jpegdata.h +jdhuff.o : jdhuff.c jinclude.h jconfig.h jpegdata.h +jdmain.o : jdmain.c jinclude.h jconfig.h jpegdata.h egetopt.c +jdmaster.o : jdmaster.c jinclude.h jconfig.h jpegdata.h +jdmcu.o : jdmcu.c jinclude.h jconfig.h jpegdata.h +jdpipe.o : jdpipe.c jinclude.h jconfig.h jpegdata.h +jdsample.o : jdsample.c jinclude.h jconfig.h jpegdata.h +jerror.o : jerror.c jinclude.h jconfig.h jpegdata.h +jfwddct.o : jfwddct.c jinclude.h jconfig.h jpegdata.h +jquant1.o : jquant1.c jinclude.h jconfig.h jpegdata.h +jquant2.o : jquant2.c jinclude.h jconfig.h jpegdata.h +jrdjfif.o : jrdjfif.c jinclude.h jconfig.h jpegdata.h +jrdgif.o : jrdgif.c jinclude.h jconfig.h jpegdata.h +jrdppm.o : jrdppm.c jinclude.h jconfig.h jpegdata.h +jrevdct.o : jrevdct.c jinclude.h jconfig.h jpegdata.h +jutils.o : jutils.c jinclude.h jconfig.h jpegdata.h +jvirtmem.o : jvirtmem.c jinclude.h jconfig.h jpegdata.h +jwrjfif.o : jwrjfif.c jinclude.h jconfig.h jpegdata.h +jwrgif.o : jwrgif.c jinclude.h jconfig.h jpegdata.h +jwrppm.o : jwrppm.c jinclude.h jconfig.h jpegdata.h + + +# use linker response files because file list > 128 chars + +cjpeg.exe: $(COBJECTS) + link /STACK:8192 @makcjpeg.lnk + +djpeg.exe: $(DOBJECTS) + link /STACK:8192 @makdjpeg.lnk diff --git a/makefile.pwc b/makefile.pwc new file mode 100644 index 0000000..f41dd48 --- /dev/null +++ b/makefile.pwc @@ -0,0 +1,100 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is for Mix Software's Power C, v2.1.1 +# and Dan Grayson's pd make 2.14 under MS-DOS. +# Thanks to Bob Hardy for this version. + +# See README and edit jconfig.h before saying "make" !! + +# NOTE: make sure you have converted end-of-line markers to CR/LF in this file +# and in the three mak*.cf files; otherwise pd make and the Mix linker will +# choke. Power C doesn't seem to care whether end-of-lines are CR/LF or just +# LF in the *.h and *.c files. If you blindly converted LF to CR/LF in ALL +# the files, then you broke the test*.* files, which contain binary data. + +CC=pc + +# You may need to adjust these cc options: +MODEL=m +CFLAGS=-dMEM_STATS -dMSDOS -m$(MODEL) +LDFLAGS= +# In particular: +# -dMEM_STATS is optional -- it enables gathering of memory usage statistics. +LDLIBS= + +# miscellaneous OS-dependent stuff +# linker +LN=pcl +# file deletion command +RM=del +# library (.mix) file creation command +AR=merge + + +# compression objectfiles +COBJECTS = jcmain.mix jcmaster.mix jcdeflts.mix jcarith.mix jccolor.mix jcexpand.mix jchuff.mix jcmcu.mix jcpipe.mix jcsample.mix jfwddct.mix jrdgif.mix jrdppm.mix jwrjfif.mix jutils.mix jvirtmem.mix jerror.mix +# decompression objectfiles +DOBJECTS = jdmain.mix jdmaster.mix jbsmooth.mix jdarith.mix jdcolor.mix jdhuff.mix jdmcu.mix jdpipe.mix jdsample.mix jquant1.mix jquant2.mix jrevdct.mix jrdjfif.mix jwrgif.mix jwrppm.mix jutils.mix jvirtmem.mix jerror.mix +# These objectfiles are included in libjpeg.mix (all but jcmain, jdmain) +LIBOBJECTS = jcmaster.mix jcdeflts.mix jcarith.mix jccolor.mix jcexpand.mix jchuff.mix jcmcu.mix jcpipe.mix jcsample.mix jfwddct.mix jrdgif.mix jrdppm.mix jwrjfif.mix jdmaster.mix jbsmooth.mix jdarith.mix jdcolor.mix jdhuff.mix jdmcu.mix jdpipe.mix jdsample.mix jquant1.mix jquant2.mix jrevdct.mix jrdjfif.mix jwrgif.mix jwrppm.mix jutils.mix jvirtmem.mix jerror.mix + + +all: cjpeg.exe djpeg.exe test +# By default, libjpeg.mix is not built unless you explicitly request it. + + +cjpeg.exe: $(COBJECTS) + $(LN) $(LDFLAGS) @makcjpeg.cf + +djpeg.exe: $(DOBJECTS) + $(LN) $(LDFLAGS) @makdjpeg.cf + +# libjpeg.mix is useful if you are including the JPEG software in a larger +# program; you'd include it in your link, rather than the individual modules. +libjpeg.mix: $(LIBOBJECTS) + @$(RM) libjpeg.mix + $(AR) libjpeg.mix @makljpeg.cf + +clean: + $(RM) *.mix cjpeg.exe djpeg.exe testout.* + +test: + @$(RM) testout.* + +djpeg testorig.jpg testout.ppm + +cjpeg testimg.ppm testout.jpg + fc testimg.ppm testout.ppm + fc testimg.jpg testout.jpg + + +jbsmooth.mix : jbsmooth.c jinclude.h jconfig.h jpegdata.h +jcarith.mix : jcarith.c jinclude.h jconfig.h jpegdata.h +jccolor.mix : jccolor.c jinclude.h jconfig.h jpegdata.h +jcdeflts.mix : jcdeflts.c jinclude.h jconfig.h jpegdata.h +jcexpand.mix : jcexpand.c jinclude.h jconfig.h jpegdata.h +jchuff.mix : jchuff.c jinclude.h jconfig.h jpegdata.h +jcmain.mix : jcmain.c jinclude.h jconfig.h jpegdata.h egetopt.c +jcmaster.mix : jcmaster.c jinclude.h jconfig.h jpegdata.h +jcmcu.mix : jcmcu.c jinclude.h jconfig.h jpegdata.h +jcpipe.mix : jcpipe.c jinclude.h jconfig.h jpegdata.h +jcsample.mix : jcsample.c jinclude.h jconfig.h jpegdata.h +jdarith.mix : jdarith.c jinclude.h jconfig.h jpegdata.h +jdcolor.mix : jdcolor.c jinclude.h jconfig.h jpegdata.h +jdhuff.mix : jdhuff.c jinclude.h jconfig.h jpegdata.h +jdmain.mix : jdmain.c jinclude.h jconfig.h jpegdata.h egetopt.c +jdmaster.mix : jdmaster.c jinclude.h jconfig.h jpegdata.h +jdmcu.mix : jdmcu.c jinclude.h jconfig.h jpegdata.h +jdpipe.mix : jdpipe.c jinclude.h jconfig.h jpegdata.h +jdsample.mix : jdsample.c jinclude.h jconfig.h jpegdata.h +jerror.mix : jerror.c jinclude.h jconfig.h jpegdata.h +jfwddct.mix : jfwddct.c jinclude.h jconfig.h jpegdata.h +jquant1.mix : jquant1.c jinclude.h jconfig.h jpegdata.h +jquant2.mix : jquant2.c jinclude.h jconfig.h jpegdata.h +jrdjfif.mix : jrdjfif.c jinclude.h jconfig.h jpegdata.h +jrdgif.mix : jrdgif.c jinclude.h jconfig.h jpegdata.h +jrdppm.mix : jrdppm.c jinclude.h jconfig.h jpegdata.h +jrevdct.mix : jrevdct.c jinclude.h jconfig.h jpegdata.h +jutils.mix : jutils.c jinclude.h jconfig.h jpegdata.h +jvirtmem.mix : jvirtmem.c jinclude.h jconfig.h jpegdata.h +jwrjfif.mix : jwrjfif.c jinclude.h jconfig.h jpegdata.h +jwrgif.mix : jwrgif.c jinclude.h jconfig.h jpegdata.h +jwrppm.mix : jwrppm.c jinclude.h jconfig.h jpegdata.h diff --git a/makefile.unix b/makefile.unix new file mode 100644 index 0000000..0f11afa --- /dev/null +++ b/makefile.unix @@ -0,0 +1,152 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is suitable for Unix-like systems. + +# See README and edit jconfig.h before saying "make" !! + +# Comment out this line if you don't have gcc: +CC=gcc + +# You may need to adjust these cc options: +CFLAGS= -O -g -Wall -DHAVE_GETOPT -DMEM_STATS +LDFLAGS= -g +# In particular: +# Remove -g and -Wall if not using gcc. +# Add -DBSD if on a pure BSD system (see jinclude.h). +# Remove -DHAVE_GETOPT if you don't have getopt(3) (see jcmain.c, jdmain.c). +# -DMEM_STATS is optional -- it enables gathering of memory usage statistics. +# You may also want to add -DTWO_FILE_COMMANDLINE or -D switches for other +# symbols listed in jconfig.h, if you prefer not to change jconfig.h. +# If your compiler is non-ANSI, also see the .c.o rule below. + +# On HP-UX (and probably other SysV systems) the alternate malloc(3X) is a lot +# faster than the standard malloc; this makes a noticeable difference in the +# startup time when handling big noninterleaved images. I say "-lmalloc" to +# get the alternate allocator. On most non-SysV systems you can just +# define LDLIBS as empty. +LDLIBS= -lmalloc + +# miscellaneous OS-dependent stuff +LN= $(CC) # linker +RM= rm -f # file deletion command +AR= ar rc # library (.a) file creation command +AR2= ranlib # second step in .a creation (use "touch" if not needed) + + +# source files +INCLUDES= jinclude.h jconfig.h jpegdata.h +SOURCES= jbsmooth.c jcarith.c jccolor.c jcdeflts.c jcexpand.c \ + jchuff.c jcmain.c jcmaster.c jcmcu.c jcpipe.c jcsample.c \ + jdarith.c jdcolor.c jdhuff.c jdmain.c jdmaster.c jdmcu.c \ + jdpipe.c jdsample.c jerror.c jfwddct.c jquant1.c jquant2.c \ + jrdjfif.c jrdgif.c jrdppm.c jrevdct.c jutils.c jvirtmem.c \ + jwrjfif.c jwrgif.c jwrppm.c egetopt.c +DOCS= README architecture codingrules +MAKEFILES= makefile.unix makefile.amiga \ + makefile.mc5 makefile.mc6 makcjpeg.lnk makdjpeg.lnk \ + makefile.pwc makcjpeg.cf makdjpeg.cf makljpeg.cf +TESTFILES= testorig.jpg testimg.ppm testimg.jpg +DISTFILES= $(DOCS) $(MAKEFILES) ansi2knr.c $(SOURCES) $(INCLUDES) $(TESTFILES) + +# compression objectfiles +COBJECTS = jcmain.o jcmaster.o jcdeflts.o jcarith.o jccolor.o jcexpand.o \ + jchuff.o jcmcu.o jcpipe.o jcsample.o jfwddct.o \ + jrdgif.o jrdppm.o jwrjfif.o \ + jutils.o jvirtmem.o jerror.o +# decompression objectfiles +DOBJECTS = jdmain.o jdmaster.o jbsmooth.o jdarith.o jdcolor.o jdhuff.o \ + jdmcu.o jdpipe.o jdsample.o jquant1.o jquant2.o jrevdct.o \ + jrdjfif.o jwrgif.o jwrppm.o \ + jutils.o jvirtmem.o jerror.o +# These objectfiles are included in libjpeg.a (all but jcmain.o, jdmain.o) +LIBOBJECTS = jcmaster.o jcdeflts.o jcarith.o jccolor.o jcexpand.o \ + jchuff.o jcmcu.o jcpipe.o jcsample.o jfwddct.o \ + jrdgif.o jrdppm.o jwrjfif.o \ + jdmaster.o jbsmooth.o jdarith.o jdcolor.o jdhuff.o \ + jdmcu.o jdpipe.o jdsample.o jquant1.o jquant2.o jrevdct.o \ + jrdjfif.o jwrgif.o jwrppm.o \ + jutils.o jvirtmem.o jerror.o + + +all: cjpeg djpeg +# By default, libjpeg.a is not built unless you explicitly request it. + + +# If you have a C compiler that doesn't understand function prototypes, +# uncomment the 5 lines below and make sure PROTO is not defined by jconfig.h. +# Then say "make ansi2knr" before "make". + +#.c.o: +# ./ansi2knr $*.c tmpansi.c +# $(CC) $(CFLAGS) -c tmpansi.c +# mv tmpansi.o $*.o +# $(RM) tmpansi.c + +ansi2knr: ansi2knr.c + $(CC) -o ansi2knr ansi2knr.c +# You may need to add one of -DBSD, -DVMS, or -DMSDOS to the line above. + + +cjpeg: $(COBJECTS) + $(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) $(LDLIBS) + +djpeg: $(DOBJECTS) + $(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) $(LDLIBS) + +# libjpeg.a is useful if you are including the JPEG software in a larger +# program; you'd include it in your link, rather than the individual modules. +libjpeg.a: $(LIBOBJECTS) + $(RM) libjpeg.a + $(AR) libjpeg.a $(LIBOBJECTS) + $(AR2) libjpeg.a + +clean: + $(RM) *.o cjpeg djpeg libjpeg.a ansi2knr core tmpansi.* testout.ppm testout.jpg + +distribute: + $(RM) jpegsrc.tar* + tar cvf jpegsrc.tar $(DISTFILES) + ls -l jpegsrc.tar + compress -v jpegsrc.tar + ls -l jpegsrc.tar* + +test: cjpeg djpeg + $(RM) testout.ppm testout.jpg + ./djpeg testorig.jpg >testout.ppm + ./cjpeg testimg.ppm >testout.jpg + cmp testimg.ppm testout.ppm + cmp testimg.jpg testout.jpg + + +jbsmooth.o : jbsmooth.c jinclude.h jconfig.h jpegdata.h +jcarith.o : jcarith.c jinclude.h jconfig.h jpegdata.h +jccolor.o : jccolor.c jinclude.h jconfig.h jpegdata.h +jcdeflts.o : jcdeflts.c jinclude.h jconfig.h jpegdata.h +jcexpand.o : jcexpand.c jinclude.h jconfig.h jpegdata.h +jchuff.o : jchuff.c jinclude.h jconfig.h jpegdata.h +jcmain.o : jcmain.c jinclude.h jconfig.h jpegdata.h egetopt.c +jcmaster.o : jcmaster.c jinclude.h jconfig.h jpegdata.h +jcmcu.o : jcmcu.c jinclude.h jconfig.h jpegdata.h +jcpipe.o : jcpipe.c jinclude.h jconfig.h jpegdata.h +jcsample.o : jcsample.c jinclude.h jconfig.h jpegdata.h +jdarith.o : jdarith.c jinclude.h jconfig.h jpegdata.h +jdcolor.o : jdcolor.c jinclude.h jconfig.h jpegdata.h +jdhuff.o : jdhuff.c jinclude.h jconfig.h jpegdata.h +jdmain.o : jdmain.c jinclude.h jconfig.h jpegdata.h egetopt.c +jdmaster.o : jdmaster.c jinclude.h jconfig.h jpegdata.h +jdmcu.o : jdmcu.c jinclude.h jconfig.h jpegdata.h +jdpipe.o : jdpipe.c jinclude.h jconfig.h jpegdata.h +jdsample.o : jdsample.c jinclude.h jconfig.h jpegdata.h +jerror.o : jerror.c jinclude.h jconfig.h jpegdata.h +jfwddct.o : jfwddct.c jinclude.h jconfig.h jpegdata.h +jquant1.o : jquant1.c jinclude.h jconfig.h jpegdata.h +jquant2.o : jquant2.c jinclude.h jconfig.h jpegdata.h +jrdjfif.o : jrdjfif.c jinclude.h jconfig.h jpegdata.h +jrdgif.o : jrdgif.c jinclude.h jconfig.h jpegdata.h +jrdppm.o : jrdppm.c jinclude.h jconfig.h jpegdata.h +jrevdct.o : jrevdct.c jinclude.h jconfig.h jpegdata.h +jutils.o : jutils.c jinclude.h jconfig.h jpegdata.h +jvirtmem.o : jvirtmem.c jinclude.h jconfig.h jpegdata.h +jwrjfif.o : jwrjfif.c jinclude.h jconfig.h jpegdata.h +jwrgif.o : jwrgif.c jinclude.h jconfig.h jpegdata.h +jwrppm.o : jwrppm.c jinclude.h jconfig.h jpegdata.h diff --git a/makljpeg.cf b/makljpeg.cf new file mode 100644 index 0000000..3325bf4 --- /dev/null +++ b/makljpeg.cf @@ -0,0 +1,5 @@ +jbsmooth.mix,jcarith.mix,jccolor.mix,jcdeflts.mix,jcexpand.mix,jchuff.mix +jcmaster.mix,jcmcu.mix,jcpipe.mix,jcsample.mix,jdarith.mix,jdcolor.mix +jdhuff.mix,jdmaster.mix,jdmcu.mix,jdpipe.mix,jdsample.mix,jerror.mix +jfwddct.mix,jquant1.mix,jquant2.mix,jrdgif.mix,jrdjfif.mix,jrdppm.mix +jrevdct.mix,jutils.mix,jvirtmem.mix,jwrgif.mix,jwrjfif.mix,jwrppm.mix diff --git a/testimg.jpg b/testimg.jpg new file mode 100644 index 0000000..b6b68bc Binary files /dev/null and b/testimg.jpg differ diff --git a/testimg.ppm b/testimg.ppm new file mode 100644 index 0000000..c7dab37 --- /dev/null +++ b/testimg.ppm @@ -0,0 +1,9 @@ +P6 +128 128 +255 +cUzlߦԼª²ϪrdbTYGeSʎvŮӹϵԹپ׼ϴʮϳ˯}vz~}wpp™xyf˪¥Œth}yzs{uwbXWQGF[JBfUMlVHhRDM6ZCnWmĖϡҥӦѦѦѧҨѪҫҭҭѵϳϲͰ̧̫ͬͨ{vn|iweucuhqdk^eXcScSeTfUhRdN^FX@|R9sI0h>%_5Y<]@ _E*_E*VC2S@/N@5OA6J;6G83N<8]KGqZTs\ViLFY<6cS{kᨔéɱƴϪtfcUZHfTȌr찖ؾջжʰʯγҷӸȬͱɭz}~uo~jz{hɨ~h}g|zzszf\ZTJHbPFm[QnWGdM=O8_Hw`tǙΠҥըҧӨөԪӬԭհհҶѵѴϲϮέϪΩǜęzrn~l}kr{nviqdp`qasbtct^pZjReM_FV=vL3mC*_@!cD%cH-bG,XC2T?.O>4P?5G83C4/H62UC?hQKlUOeJCW<5^Oufܢʰ®ɵΨvfcSZGeRĆmᣊѷͳɯĪ§ɮеɭ˯ɭ~}zrlvb}lƥu_~h{{ɽŹ`UQRGCeQFq]RqVEfK:T=iRmƖ˝͟ҥثԩժի׭֯رسٴչԸԷҵұѰҭѬХˠǘ~wuuv}zwtqrsum~iybt]pWhO^EV=kH*nK-lL3hH/ZC3U>.O=3O=3E61?0+@.*I73[D>bKE`E>W<5UCfTʎvߣȭîˢvdbPYDdOcԔxƬŪŪƫʯβͱʮ¦|wp~kr^nģzhsζnefSF@NA;dM?mVHqU@mQ<]Ft]zРϡ̞ҥڭ֫׬خڰٲ۴ܷݸؼ׻׺ոմӲհԯ֫Хʛ“zzÎ|Ő~~|~vrlh{cs[jRbJ|S7}T8wS;oK3_C5W;-N:1N:1G51@.*;)%@.*P93XA;Y@9V=6L8WCvZňlvr{ǝ|vdaO[BfMz\ȇitvϴѶͲγչϳ̰ƪ}¯Ǯ|un}jwcnƥy{ʵnefWNON?8QB;bH7eK:qQ:zZCjSiʚեѣ͟Ѥ٬׬حٯ۱۴޷ߺߺھٽػֹ׶մֱֱ׬Ѧ̝ĕÐ}Ð}Ƒȓ‘ÒxuolhxaoXhQ]D\CYCxN8dB6Z8,N5.N5.J73B/+:'#;($D0)M92S<4S<4J4RdG5dG5uQ7cIybr̜ԤҤϡѤ֩֫׬خ۱ܵ޷໫໫ھٽػֹ׶մֱֱ֫ҧΟșǔƓȓɔÏÏÏĐĐĐőőyvqok|et]mVhQeN^JP*#;' 3$/ ,,. /!J7\I΃l鞇ؾٿ˱{sāgłhɀ_}\zɣs|v˰γyŝ¨˱ͯxtȡyi}mƤ˴һÿ]caGID;=8C5*PB7rM:_LsYpĘƚʞ΢ѧөԫԫϩѫүֳشڶطط޸޸߷޶ݳڰج֪ҤѣϠ̜͞˛͚Λȡɢˡˡ͟˝̘˗˓ɑȍ{ĉwƒqm|jzhvWpQdJP6i@.[2 L.#L.#>*#;' 3$/ ,,-. I7P>pY׌uγպγèǒt|czaxXwWyy~efϵ}hɮͲt{Ûūͳϱyu{vfoǫʮͺľcghLPQ?>:984G5)SA5tN9ePdΛ~Ǜʞ͡ҦԪ֭֬׮ѫӭӰֳشڶططݷݷ޶ݵݳٯج֪ҤѣϠ̜͞͝ϜϜɢɢˡˡ̞ʜ˗ɕ˓ɑȍ{ĉwƒqm|jzhrSlM`FM3e<*W.H*H*=)":&2#.,,-. G6D3^G|eŧΰͰŨ˓rs[mUnNoOynjQlSδ}sγ˰wk~tūͳͯ~vsstdtϻɼ{zooqqqsA<9@;8O9,WA4uM4fMc͛zɝ˟΢ҦԪ֭֭֬ҬԮղ״ٵڶط׶ܶݷݵܴܲٯ׫թҤТϠ͞Ξ͝Нўɢɢˡʠ˝ȚʖȔʒȐnjzÈvp~l{iygoPhI\BI/a8&S*E'D&<(!9%1"-++,-L;D3YDydť˫˫ƦΓpjSaJcDgHzofM]DjxsϴǬwkwšĪ˱ɫ~yrpqueyƪû÷zuyA64D97T:-[A4yR5oRc˙tɝ˟΢ҦөԪԫԫԮְֳصڶڶ׶׶ܶܶݵܴ۱خ֪ԨѣТСΟϟϟҟӠɢɢˡɟʜǙȔƒǏ~Ǝ}ĉwsn|jxfwelMfGZ@|F,_6$Q(B$B$<(!9%0!-**+,RBJ:cNքo̪˩ʩȧҔpeOYC]?eGmiaHoM4|bIpWrZzbʯŪv̤ĪʰȪ{wp}nvyi˯ŭëĿ¼VLT<,,A11R5'_B4\>bǘnϠvʞ̠ϣҦөԪӪӪְزصٶڶڶ׶׶۵۵ܴ۳ڰ׭թԨѣТСϠϟРԡբʣɢˡɟɛŗƒĐČ{Šyto|jxftbsakLeFY?{E+^5#P'A#A#;' 8$0!,))*+PAK=!:-)"!G,@%K1[AybqūɹȪ{fvWmP̓fĘ{q|~{ufuhm`yktuɲȭ{ywɺŹ÷źsmE2,N2&W;/yTA|iÙΤҤӥددٰ۲۵ܷܷܶطٸٹٹظֶҵѴ׬֫ժժԩӨҧҧҧҧѦХϤϤΣΣИϗ̕ɒ~ƍz‰vpoh|ew^rYmSjPhNgMe@^9S4zC$e5!W'E@=!:-)"!B*B*R:fNćt՘ɪͮȷƬoawWŊjk~alhkW`LqWHY?0nXKdNAw`Ryuuȱʯ|xtȹȼĸũlYSJ71I-!^B6dQvʠө֨Ԧ۲۲ܳ޵ݷ߹ߺߺڹۺںںظֶҵѴӨӨѦѦѦҧӨӨҧҧҧҧХϤ̡͢ϗ͕ʓƏ{Êwsmkybw`rYnUiOfLdJdJc>\7Q2zC$e5!X(G!B=!:-)"!@&I/aJzc۞뮜׶ЯDzūvdtS`uXvYohwXD]>*T:+J0!_I<]G:v_Qz}{ǰɮ|yuy~˿¶DZsu_LFS@:G+fJ>r_ͣԪتשܳݴ޵߶߹ລ໨Ἡܻܻܼۻٹ׷ҵгҧѦϤϤϤѦӨժҧӨӨӨѦϤˠɞΖ̔ɒ~čytpj~hu^r[oVjQeKcIbHbHajMwwyZFS4 R8)[A2`J=l_ĭĩ}~ʱοô¶̲wy}xe_Q>8eI=pdŠȞͣש٫ܳܳݴ߶޸߹໨໨߾߾޾ݽں׷ҵгحժҧϤΣѦԩ׬ҧӨժ֫ӨΣɞŚ̔ɑƏ{up~kzdxbqZoXkRhOdJbHaGaG]8W2N/yB#f6"\,L&H"=!:-)"!D$E%F+N3r`ș̬ǧϮҪǟǓ~p[K2H/gJrU~~cOY:&T:+Z@1dNA|o|ì{~Ӻȹĸأn[UO<6uYMuơʥƜʠէت۲۲ܳ޵޸߹ߺߺ࿮࿮߿ݽں׷ҵг۰حԩХϤѦԩ׬ҧԩ֫֫ӨΣȝŚ˓ɑŎzto}jxbv`pYnWkRhOdJbHbHbH\7V1M.yB#f6"\,M'I#=!:-)"!VSWTYR^Wp_uƢүүvhe[g]wj{nvxj_;-U4%hYp`pup|éȮʮųùǯzxkI?mKAj]wjv}‘˛ե֩ثٯ޴߶෣޸޸⽭㾮Ὧ༮ܺٷյӳح֫ԩӨҧҧӨԩ֫ԩҧХ̡ʟǜƛƎ}Č{vrm|iycwar[qZpWmTiOgMeKdJZ;T5M1E)x@'n6[.S&E#?/, ')'&yyw~}}wʧΫv~t{vyvrN@jI:yjtwfsɯƬȬúønljH>iG=obwj}npqv͝ը֩ثۮܱൢḦ仩޹޹ݹݹضִӱѯح׬ժӨҧӨӨԩ֫ժӨХ͢ʟȝǜǏ~ō|‹wsn}jzdxbt]s\qXoVkQhNfLeKZ;T5M1F*yA(p8]0U(F$?/, ')&&ЩϨϩΨʦß~ƣʧĠbT|[Ltuzizé˱Īƪ˹˼Ǥxvx`^rPFzXN{n|ozkufqcugu͞͞Ρҥժ۰߶⹧ٲڳڴٳ׳ձѯϭٮ׬ժԩӨӨԩժ֫ժӨХ͢ˠȝǜɑǏ~čyupl|fzdw`v_t[qXlRiOgMfL[%d7$]0I'B 2.()&%ٿջؽڿеӸòڻҳΫɦǟԮҬݞ}}n~sctd{j~ūԺɯ¨¦Ӻȶӫkig]řĘē{~prdj^g[yfo{Ϝ֥کګ٪׫جٯ۱ٱذׯ֮گٮ׬ժԩժժ֫ح׬ժҧϤ̡ʟɞΖ̔ɒ~čyuqjizcybv]rYmSjPgMeK[TC^Mm]}m~ɕΜОҢեרة֪֪ܱگح׬֫֫׬حٮح֫ӨХΣˠʟӛљΗʓƍz‰vpnxav_sZnUhNdJ`F^D[+O-!G%7 0)*&$ѽǪæʩѰϩĜ׵ضǦʪxz[FgqäʫʫƦ¢¦ǾҸ~afejnhrl‰~}Ƅv€r|lwgqbn_YRTMJ@FbSmГ͔јѠԣϤХЫӮبק֦֦֦ק٩ڪ֦֦֦֦ԤҢϟΞљϗ̕ǐ|Êwslk{dxasZmTgMcI`F_EYSDjXweŠyϗРѡ͡΢ףףףؤף֢աԠҞѝϛ͙˗ʖʖʖ˓ɑƏ{Ìxtpjiybv_pWiPaG\BX>W=YyTN]WxwpfX^PXEdQva…pɏ{ϕқԝʐ|̒~ϕЖΔɏ{Ċvrl}ixds_r^s_vbxdwfvet`r^o\lYjTiSmVkTgNdK`F^D]C]CYcEE\>>ZAGbIOsYXml}ywol^j\]NeVvdńrʑј͜͜˙xȖuɒsȑȑsNJn€hyauanZfSaNdNfPfPeOcSdTeSeScPaN_J^IeOeOdMbK^F\D\A[@S>R=O8J3|F*v@$l=i:[8T1?)5$ +#  !"ϷѶػˮɨέɦǗԫլǧĤɯҸ͸ιкͷͱͱӳ׷ظҲĬôȿĖɿupscfV[RVMpPQgGHcJPjQWoUTedtq{xrjkcdVdVaRiZygdžtʑϖɘɘ˙xȖuɐsǎqɋrÅl|fu_lXdP\HUAT?S>S>~Q{P?}R?}R?M8O:P:O9~K0wD)l?"h;\7U0C*9 +) ( #$ ˳zsŨȫƥŤ}yÓد෱ͭūؾ˶̷ͷʴʮȬήѱͭ׷׿{Ѷ˻͵ǡӢ~}opgh_`b{WYwYaaionrqolkh`X\T[M^PbSk\|jʉw͔Зɘǖ̔yȐuÊoj~iu`iWaOR@I7s@-j7$]4 Z1R/O,E*#E*#F)!H+#K-%N0(R1(T3*W5)Z8,`<.eA3jE5kF6lE6lE6pA-sD0xH2zJ4zH/vD+m?%i;![5V0E*-f7%_0U2T1M1J.G,%F+$E( E( G)!H*"M,#O.%S1%V4(]9+a=/d?/c>.c<-a:+`5"d9&k<(o@,rB+qA*m?'j<$[5 V0G*?"1.))ӻ~Ѩ弶ٹƦ¨ѷɴʵʴưũçȨ˫µӳ˳͵ͤżDzooƛ͢Л͘|{npimfkojns|}zspd\\TTFQC[LfW{i͌zӚ֝Ϟ̒͜|ŋuoyfn]aPSDI:r=-k6&Z1V-P1R3L6!J4P/&O.%L,!K+ L*N, T0"W3%\7'`;+f?.jC2nC2lA0h=*f;(]4"_6$b7$d9&h;&i<'h;&h;&]4"X/J*C#62-,̴Ǭ{{w{™߶ݽʪéϵ͸ιθʴȬƪ˫ήٹϯƽ¥IJ|}͡ϣӛҚ{ymoilfmqnrx~zwnfd\XJRD^OiZ}kώ|ԛ՜̛ɘ͐}ƉvnuchYZKL>|A3i5'c/!R+O(I.L1F5!E4 U/"S- Q,Q,T-X1 _6$c:(k@-oD1xI5}N:P:~N8zJ3wG0c>,b=+b9'`7%b5 c6!c6!e8#\2"Y/L* F$9 4.-սԹĩģ~ssosoٰ޾ήĪͳѼҽҼͷ̰ɭήѱƦʪĵ¹~{΢͡ҚΖxujlficjnkovyqog`RWIbSm^oѐ~ӚӚɘŔ̏}Ɖw~lsaeVVGG9x=/b1#\+M(J%D+G.A2@1U+S)S*S*X-_4!h;&l?*vF0{K5R;XA[CZBWPJJ@KAP@YIaHaH]=Y9VW=T:}M6uE.n;(e2[,W(L%M&D(C'7'2"( %ؿŰ}ǩۻ̬ ŕ~t{q˟ʜҬѰֵ׺׺Ҹδ˴̵̬Ȩʲи~{|¼Ȼڟय़ߡؚΛȕ}rqih`\]YZ`WaXd[jarh{qyÉ~ÊʑӝܦܨףϛɕɄtzjlZ\JR=wC.c9#Y/N(O)P)R+W-Y/!\0#^2%`;)e@.wQDgZphmeickenhe_[NUHUAWCZ@[AW/pK.qL/tL2rJ0rE0l?*f8(c5%V,T*J(E#9!5/-ҵƩ¤ĦȨĤɧѯϫ˧׳ЬžЬֲֲܸܸϫʦȤƦ˫ɺlchȚ͟ڙ٘ܜߟҡҡʤȢ̜ȘϏ͍ˋˋʊɉĈ~Ç}ˆ}|ʑјآިު֢͙ƒwgiYWEF4r>)i5 ]3Y/X2_9&hA0oH7qG9kA3d8+^2%Z20]53dECuVTq[]gQS\LM\LMsa_n\ZoSOkOKpH@iA9h6+a/$`? cB#hE)kH,nD.kA+i;+e7'\2$Y/!P+"J%>":43ؿˮťʨ̪ұ¡âЯέßʦѭڴܶزҬͧ˥ϯ̬͵ȹ~zqv|Ǿ˛˛ۗޚߜߜѢСȣǢ̞̞ӘӘՕёˋƆ}†|Ĉ~Ǎʐҙ؟ݧ᫟ުԠɕn^`PM;|=+j6!d0Z0X.X2`:'mF5vO>zPBuK=mA4f:-lEFjCDkMOtVXgWXYIJJABI@A]QQYMM\DBYA?b;6^72_-&Z(!P3U8^< dB&kB,jA+j<,g9)]1$Z.!Q+"L&B$@";";"׾ֽ¥yovɩ̪ǥٹǧͬЯȤĠ̨ױ۵ڲխѩШں˫иɿ|mjxotxu|εÑٓ✚㠗ߜѢϠǢŠȜɝԙ՚Ғˋx{r{qyɏЖڡড়㭡寣߫ӟƒ}gWYIF4u6$d0a-X.W-U/_9&nG6zSBVH|RDtH;l@3}VYsLOeHLeHLWHKPADJFGRNORIJMDEO:9K65V0-V0-[($Y&"H+ N1V7_@#gA*gA*h=,e:)\0#Y- Q+"L&F%F%C(!C(!ϺnkpmʤФʞدͤɡ̥֮Ƥ̪ҳԵҴϱ˱̲ŷ}~yz|rdsv׻γèȗȗߘ㜖ٓҞҞˡʠϛ̘ԑҏɄuȃtÁuÁuċēȗ٬ڭܰݱ۬Οv}heQS?qA+g7!d:"f<$a<"]8d?%c>$pF.X@`J\FWCXDcP\I|VKrLA`LMaMNYS]\V`iis]]gQKM?9;>+$:' A'C)6! :%E*L1X4$[7'`6*a7+a2*_0(Z.%V*!O) M'I'J(̷˥ϣ˟׮Ϧ˜ĜШˤţʨбӴѳΰ˱˱ǵ˹zpbqē۔ߘߙܖӟӟˡɟ̘Ȕό̉ȃtȃt‚vÃwÊʑ˚Ϟ٬ۮ߰߰کʙpva_KP)h5 f9"h;$b=#_: d?%c>$rE.YBcNaL^J`LjWdQ^T}UKlWVmXWh^fkaipmvdajWNQE$?%9$<'D)J/U1#Y5'_5)`6*`1'^/%Z.%W+"Q+ P*L*L*ϺŰʤѫԨФӪѨƜĜƟ Ȧίҳвΰ˱̲ͻvfqwix¶ğwՎْݗݗӟӟʠȞʖƒ̉ʇɇwɇwŇzlj|ǐϘѢ֧ܯݰ౧ޯ٦Ɠ{gjVUBI6p<'j6!f9"i<%f>%c;"h@'g?&tG0[DfQgRdQgTp_kZf]aXcbfe~msqw~syrgmcUUPBBE1*<(!>"=!<'=(B'E*O+T0"\2&^4(\-#\-#Y-"X,!S- S- O.O.Կιǫͧױڮӧ̣Ϧǝĝţ̭Ѳвΰ̲ͳ˹w|lw}q»³Љԍٓݗѝѝʠɟ͙ʖюόϒΑʐˑ˖ҝզ٪ᴮ೭䲩߭֡|q^`MK9~C1q:&n7#j:$m='i?'h>&mC+kA)xH2ZDeQeQcQfTm_k]i^h]kipnyy}}vxlno[Z\HGO61C*%?#< ;%;%>"?#H$M)W,#Z/&X)X)W+X,T/T/P/P/Կȳѫج΢ěˢǝ{ĝĢ̭ѲѳвϵжIJótuscnuiwtƼǺψъ֐ڔΚϛʠˡҞѝۘڗמ՜ϚΙ͛ҠӦת縲䵯䯧ܧїsiWXFE3}@.t;(r9&o<'q>)m@)m@)tG0qD-{H3YDaNaN_McQgZfYf\f\kdpiwu{yrojgv]YeLHW<5J/(C&?"8"7!;<E J%S(W,#V(W)X-Z/V1V1Q1P0ιwtvϣƚȟǝ~ƟĢͮӴԶԶӹջñºƳxhiuep}o~u·ъԎ֐̘͙ɟ̢ա֢ߜܥ٢Ӡў͞ѢӦת縲Წݦњlj|uh^NO?@/~?.y>,x=+t@+t@+qC,qC,yK4uG0~J5YD`N_M^McRe[dZbYaXc[e]ickec]^XuTOiHCY:5N/*E("A$56;>!H#M("U*#W,%Z,\.!]2!_4#\8 [7U6S4͸DzvsriɝǛɠʠǠʣţϰն׹׹׽ٿ˹Ƹļ~pbqr§·ԍՏԎ̘͙ɟˡӟӟݚܙإ֣ѠПСԥתۮ䳮۪ӚŌymg[SDG8?/@0C1B0yB.xA-sC-tD.|L6wG1K7ZFcQeSdTiYkdhac[]UZQWNVLUKzOHwLElG?d?7W61N-(D'#@#57@#F)%Q+(U/,[0)\1*c5(e7*g<)i>+eA'b>$[<Y:Ѽũqhɝ΢ÚˢͣśȠΧΧƤбַغٻٿ´̻~vuvp{oap}Ǭ͆֏בԎ͙ΚɟʠМϛؕהբӠΟϠϣթۮ೭߮դ˒znb^RL=B3?/B2F4E3{D0yB.vC.wD/~K6yF1K7\HgUkYl\qarkngf_\USILB{G1nC0pE2lI-hE)`A"]>ؽؽֽռѽмͼͼϺɴƭŠæŤģşְƪͱ˸Ѿ˻֥}t_fltvahwhmɽǻːієӖӘ֛՝՝ҞҞޠڜ՛؞קݭݱ޲ᱥԤȐ}njW[HK4C,D/G2J5J5E0C.C.E0G2J5O:S>WB^IhSp[vmqhh_]TTII>xC5t?1rC3m>.b9']4"X3 U0N.J*L(L(O*S.]3#g=-sF3yL9}M7|L6}K2M4L2}G-v>#o7ؽؽֽռѽмͼͼѼDzΩ¥ŤŤşկ˰׼ƹ˾ëlswbit|nu||Œ̑іӖԗԙל֞ןԠӟޠ۝՝ؠئݫݮݮԤǗso`^KQ>E-?'F1I4K6I4E0B-B-D/J5N9R=VAYDaLkVr]vktioch\`RVHO@J;yH7tC2j?,f;(a;&_9$Z7!V3W0!V/ U.X1 b7&lA0xK6~Q"n8ؽؽֽռѽмͼͼԿɴytͨĥäȤ˧ƠÞЫ¡ʹĽ۶ɰ~rvxcjnu}zckmtŶ|uy|Ď̑͒ԗ֛֙ٞؠ١֢աڡ؟֞١ڥީ۩٧˗tfbTT@K7E+A'H3J5L7I4D/}@+~A,D/M8QN9K0H-J5K6L7H3B-|?*~A,D/N9QO:N2L0J5K6J5F1~A,}@+C.F1M8P;T?VAYD_JhSoZr_vc{hllzgvbr^nZgS_JWBR=L7{G1vB,L0~H,yC'wA%yC)I/R7W<\AWO8L-{H)G2G2F1C.~A,C.I4N9QJ:~C3v>1t/s@/vC2zE5~I9K;M=TBXF]J`M`LcOhUlYvfyi|jmm}kydwbs]r\oXlUiPgNeLdK^D]C\BZ@X?V=U=T.q6&k3&i1$e4%e4%f3"j7&r=-{F6M=SCXF\JaNdQdPgSlYp]~nononm|g{fwau_r[nWkRhOeLdK`F^D[AV.s8(n6)l4'd3$b1"b/e2!n9)zE5N>VFZH_MdQfSgSjVn[s`ppnnm}k|g{fwav`r[nWjQfMcJbI_E^DZ@U;Q8L3J2H0yC+v@(m='h8"a4^1[1Z0ͷͷ˶ʵŶŶµµƷDZ˵ϱñɻȷóͣaKWpXet\isr{u~}}͋}яχyҊ|яӑϕԚ֤ݫ㶱߲ڪ͝yse`NUCR.v>1u=0i8)d3$a.b/j5%xC3QAZJ^LcQhUkXkWnZr_wdpo}k{iygxfxcxcu_s]nWjSeL`G]D[BS9Q7N4J0G.C*z@(y?'o9!m7d4`0Z-X+U+U+ϹϹ͸͸ȹǸŸķĮů˳ݤjT`pZfrZglyzr~yist~ɕ̘Ґ̊|Ԍ~ؐؖٗЖϕ˙͛{zpj\_QUCP>H2F0D/B-{@0y>.w?2w?2k:+f5&b/b/j5%xC3QA[K_MdRiVlYlXo[s`xepo|jygwevdvawbs]q[mVhQcJ^E[BY@L2K1G-D*A(|>%v<$u;#k5i3`0\,V)T'Q'Q'ø·ĵôȱɲϱвɩήвϱĭ»ҿ亰tjrywgqzfqoz{jtrakv~riwҍҍԎؒנϘĔǗԘӗԉ|nwfm[`NUEM=J1s?2sB4uD6iE9^:.Y.Y.m9$|H3P9U>bHgMlToWp^r`wh|mzczczcybw`t]qZoXpYkTeNaJ_H[DU>P9F*D(B(>$}=$y9 p8!o7 b/a.Y.W,R+P)L(K'÷¶ijòɯʰΰϱ˫˫ǬȭŰȳǶȷ¾ÿǷҟvltueop{ualm\fnxzpx΋юՑؔқϘș͞؞Ҙ̓urhUcP[JQ@I8@/w<,t9)q<,o:*j9*h7(g9*j<-k?2mA4fB6[7+V+W,l8#|H3Q:V?cIhNlTnVo]q_vgzkybybxaw`u^r[oXnWlUgPaJ]F[DW@Q:L5F)D'A&>#y;"v8o7 n6_/^.Y.W,P+N)L(K'³ð¯Ƭǭ̬ͭҴ˭éɶ˾ͼ~rblt`kjVawfp{xnvu}ˋА̘͙֒ؔ͠ԧݥҚȁ}qmWDS@L:~C1s;*k3"c0`-_0 ^/Y/Y/Y4$]8(`<.c?1`<0V2&R'T)k7"}I4S,e4#^-Z,Y+P)P)N*O+O/ T4%W:,Z=/Z6*Q-!P%U*n:%M8W@\EfLiOlTmUkYkYn_rcr[r[r[qZoXkTiRgPcL^GXAT=R;N7H1C,@&?%}=$y9 q7!m3g3e1[-Z,S,Q*K)H&F&E%§ĤťƦǧͯȪ˶ľ¾ÿ¾״ófV`UALzfqujrvksДҖӕϑ̜ΞͤѨڦ֢ڗԑyik[VErA0a2"[,X-Z/N)M(J(K)K. O2$S7+V:.S/#N*Q&\1!vB-U@^GbKhNkQmUlTiWhVj[m^nWnWnWmVkTgPeNcLaJ\EV?R;P9L5F/A*~>%|<#x:#t6m4 i0b/a.W,V+Q+N(H(F&B$A#¡âģŤ¯ѾíſοҴبgWa{grkvzisrakujrЖїіϔ˞̟ɣ˥ӢԣޝޝŠ}zmbT}H:g6(^-[- ]/"S+!R* N) M(K+ N.#O1'Q3)N*M)V+f;+N9`KfOgPiOlRmUkSfTdRfWhYjSjSjSiRgPdMaJ_H]FXAR;O8L5I2C,>'y;$w9"t7"p3i2e.],\+U+T*L*J(E'B$@#?"žâèɸÿӸЇwzjt|hskZdyhr}͔̓ҙ֝ɜ˞ȤɥϠΟٚٚ̐xncWLyC9l6,b0'`.%Z.%X,#Q)!N&K&L'L)#M*$K'N*\1!qF6ZEkVmVlUkQmSmUjReSbPcTeVgPgPgPfOdMaJ^G\EXAS#="ǬϴļپȾtdnwcntcmãȏɐӚݤÙȞȤɥΟʛђђёȈxod[QI{@8k4-e.'_.)],'U(#P#J!J!J#J#J&N*`5%wL(t:&r8$l5!j3d1a.[-Z,T-T-P0#I)B'C(:&35">+%ÝƠģʵǾĿ½®Єyj_gpclxrblǷİȴ˯ƠȢ͞ƗϗƎ}Ŋz̑Ж͓̓Зؗ֕LjwradR_MXGN=t@2f2$Y)\,^2%_3&d:,nD6O?WG`NfTfTfTgRhSmWkUgPcL`G^E]D]D^?[ZFZJ^NcQeSdRdRfQiThRfPbK`I^E^E^E^EZ;W8T7R5R7O4I/C)G.E,C+|@(v<&r8"p6"n4 i2h1a._,X*W)R+R+H(H(F+"E*!5!-4!D1+ĩʷĿŽȽŒ]PYy{ĵŗ}{kjZ]PeXmekcc]_Yrm|Ώԕٚܝ՗ɋuffW[JYHXCS>R>WCZJ^NbPdRcQdRgRkVfPeOaJ`I^E^E^E_F[(t:$r8$p6"h1g0a.^+W)V(Q*Q*J*H(D) E*!A-&N:3p]Wy¨ж½¾½ÿüܩmae{os}nsdUZģ{qp^aO^QoblhTP>A:=F?MFXQg`rhtjpgjaRESFVEXGYGZH\J\J^F`HaG`F^E_FdIhMdGeHeF`AZ:X8Y9\<\@[?Z>V:T9O4J1H/{E-zD,uA,s?*n;&l9$j7$h5"\2$[1#Y.W,X*W)V*V*M(T/&J0/?%$:+2ZKRuʳվĿſÿњ}quo`egX]±xu|jucqdylvrhdVYMP90:1?5E;LCKBGPCTGZL\NV>ZB^F`H_FbIgLkPcGeIcG`DZ:W7Y9[;[?[?Y=V:S8O4J1H/{E-zD,uA,s?*n;&l9$j7$h5"]3%[1#Z/X-X*X*V*V*DL'E+*@&%=.5TELi^lujxDzº½ĽʿÈ}¶\MRo`eɸòvyÄrȉw΄w~q{wzvorbe@4<08-6+8-6+3)z-#v3+u2*n3+p5-p>7wE>}LGQLQY=XB7@6<2:26.q0*n-'f,(e+'d3/k:6oAAuGGN:S?YE\HZFYE[E]G_FaHcH`E[?W;W;X0I9RBXG]LaO`N[EU?R;=::45/2*2*~8,=1H6M;WA^HbG`EZ?W9 #R96E9J>L:P>[D`IbH_EZ?WF=I@QDWJR?VC^GaJcI_E[@W,g9)b4$g7#c3^/[,V,Y/!W5,Z8/I,(dGCnpsw`MQ?075&-ĿſǸ³ܤƭƅxhrzйѲyŠ}ˌ{ņur_aNVDP>H:G9OH[Teajfa]WSRHOEI7=+;$A*?8B;FS:R9T-m>,k<*e7'a3#b3`1^0 \.T-T-N-$N-$K/+kOKqrpq`PS<,/- '3&-½ýŶȳȲxtu~vaV^w͸̮Ø~Žʍ{ÆtuafR\FS=E4?.@7F=KFNIQKGAC7D8D.='?%F,~>4B8F:HYAU=R9R9S;R:O9K5{H5wD1p?.m<+l=+j;)d6&_1!\/^1\3!\3!U0 O*C%> 3R;5hVVaOO>24, "1&,?4:½üĵ¾ƴÿ¾rlv^T\{khÒēɎ|‡u}hu`cKZBM:D1<3;27351?;626+:/>(z9#y=!E)|B6G;K=M?M?N@TCXGVBXD\E^G^E\CZAY@W?S;P7P7Q9P8M7}I3zG4uB/o>-l;*j;)h9'b4$^0 Z0[1Z4!Y3 R1 L+A%=!A-&VB;^NNP@@4*+* !,#(1(-ĿſǸ¾ڽÿ׿nktndlkgŖǘɐ}ŌyƉtƉtyarZdS[JPJGA<;5485|1.v3*{8/u<(p7#k< rC'{F8K=O?P@M>L=O>RAT?VAXA[D\C\C[BZAU=Q9N5M4O7N6~J4zF0yF3tA.m<+k:)i:(g8&a3#]/]4\3V1T/O.O.K0%L1&s_Xt`Y`RQE761'(/%&*$(%#ʿ¼ʻôýݾĠ涳olu}v}|wz|xxƗɚ˒ȏ|ϒ}֙ǐ{upxikg^ZOQEGAB;<~?8D={H5tA.lD*qI/yE7}I;MU>YBZA[BZBZBS;O7L3K2M5L4}I3yE/xE2tA.m<+j9(i:(g8&a3#\.`:#[5S.O*K,R3!V;0\A6}v~kdVHG4&%*!":12?9=:48Ǿ㫢¹涭̶ǾԶԽ˽þѭ½ʛӦwecñq^`xzb_ƚמΕޞؘʢˣˠǜ{xmpeaTYLOAI;J;M>M?M?L9I6F3C0C/D0F1H3K5L6O8Q:T+l=+i:(e7'b4$^3#^3#_3&`4'c-#c-#V.&M%6"8$92,E>8NMI651'"+&"<+$;*#<#<#̗żѤ¹żǾ¹־µ½Ӯʚڬ^NQhf֞љ㥐ݟխذܱ޳߰۬ڦ֢՝͕Ŋ|rvgm^bT[MXEUBP=J7H4F2G2H3F0G1I2J3L4M5N6O7{G1xD.t@+s?*s@-r?,l;*h7&f8(d6&`5%^3#]1$]1$]3']3'b3)\-#K) F$:'!?,&?74F>;40/($#&-%#7(#3$0.żĻӱĻθغһȽ簫եȺ▇aRWrvyxĨ™֡ќ䧔ݠӫխ۰ݲ౧߰ଡު՝И͒nj~ąv{loagYaN^KWDP=L8I5I4I4H2H2J3J3K3L4L4L4yF1uB-q>+p=*n=,l;*g8(c4$b7'a6&^4&^4&Z2&Z2&Z2(Z2(T2&K)>!?"@.*J84LBANDC0*,-')/%&2()7(%1"-(ԞѭǧѮͷϸŮþĹޔ봯؁v|shnkZ`ѷȡĝ֢ѝ⧕۠ҪԬحٮܭګܨۧӛИΓʏʋ|svhn`iVeR^KWDR>M9M8M8M7M7N7M6N6M5M5M5xG6tC2p?.n=,m>.k<,c8(_4$`6(`6(]5+]5+Z4)Y3(W1(V0'E. ;$14 <-*F74H<@F:>-"(,!',!%+ $0"!1#",%ȿŽΞҵǾ˧ůɫ̎ЩȾ|rzΞ_PWȥӡϝਗؠԬխحح٪ةڦ٥١՝і͒ˌ}ƒtwioao\kXdQ\IWCS?R=R=R.j?/h=-a7)]3%\4*\4*[5,Z4+V1(S.%N,#L*!6)0#*,2$#7)(4'.1$+$ %!#$/!!8**3%$(ا˺ŜúƨƽαԻ̻ԪЧĿĿŦĻ}ِbU^ġϟ̜ਙןӫӫժժר֧٥ؤؠԜϔʏȉzsxjrds`o\gT`M[GWCWBVAS=S=R;P9P8M5L4K3vH8rD4m?0j<-h.f;+d:,b8*Z2&V."S-$S-$R-%P+#I& C <9"#-)1-"6,-6,-8(27'1L:FM;GH8BK;EXLP`TXKA@-#"ĥ͛ۜʻͳþҶ§Ĺɾ̸ɿǽŵåi^d͹riСy㫔Қݤۢ٠מ֜֜ככ̍~ʋ|ɇwŃs~mziwfudmWkUgQbL_IZDWBU@UCQ?NQ>L9}J7{H5zI8xG6rD4n@0vB4o;-c3%]-W-!X."U3)V4*A&?$5".##&-#!0$(4(,6*.=15PDHbVZ\PTK?CnbfthlXLP:.2<04=157+/=15іִߧ۟ەЬܺ}y䘎ӛ~yܮqgoŻʆsujMI֣ǔ̓˒ʑɐȎǍNjƊƒts}myiudq`n]l[fPdNaM\HVDQ?P=M:K9|G5uD3sB1qC3oA1i>.e:*i=0f:-`6*[1%R-$O*!J,$J,$=$;"=+)D204)''0&'G=>UIMTHLI=AG;?dX\w{xlpVJNVJNbVZL@D-!%''0$(G;?ܶڊ㌀ӏŖɹĿź̺vqwĺ‘ȿĩʠyyjou[Z}ȚƍƍƍŌĊˆ}zyp}nyiueq`l[iXgVdObM^KYFUBP=M;K9xG6tC2k@/j?.g@/e>-`;+\7'T0$X4(Y7-X6,O1)F( ;"9 =('C.-ZJKueffZ^E9=A8=WNSswswg[_L@DVJNwkoxlp_SW:.2G;?8,0#$%0$(L@D¦ȇ{Ͽ檛ڙզȻ|źȟ㜒ꨟķqdk}vq‰Êʈ}zvuzkyjtdp`l[hWdScRaM_K\HWCR@M;{J9yH7pE4lA0e>-c<+a=-_;+Y8)U4%H+#K.&L1*J/(E.(G0*L76S>=@01N>?uhoi^fQGPXNWtx~rvYMQH<@VJN_SWYMQ/#'5)-)!"."&, $, $?37ŧձۢ䘉ϔУþīɺuuĢ͏ԏ͸tnr٫mclͺqphg~yzvxyzw~synwlsdqbm]iYeT`O]L\K[IYGWDR?|M;wH6qF5nC2hA0d=,\;*Z9(Y9*W7(P4&L0"F2+C/(<)#7$<*(R@>p`axyVJNaUYvmbrbWg`TXsgkznrfZ^L@DA59B6:E9=2&*2&*%%6*.-!%"-!%Ѱϵʿãϗȹ;åĿŵ¸Ⱥ~{ζĦ}؟nfqʻ|cfhk~~ritkvmxovkrgmbj_j[hYdT`P\KWFTCRAUAS?~O=yJ8sE5n@0e>-c<+_;+[7'T4%R2#O3%N2$H.!D*=0*22ZNNswpemmbjshv{zpgzVJNVJN[OS_SWRFJ<041%)4(,1%)/#'#&5)-)!+#ᢞȱƺҬԢ笧ުĿź}ru¸ؤ~៙tnzu_bqth_jamdnembi^cX_TcTbS]MYIUDQ@M