1 /* -*-C-*-
2 ******************************************************************************
3 *
4 * File: public.c
5 * RCS: $Header: /ImageMagick/delegates/fpx/jpeg/public.c,v 1.3 2000/12/23 22:37:48 bfriesen Exp $
6 * Description: A FlashPix-friendly interface for the HP JPEG Encoder.
7 * Author: Kirt Winter
8 * Created: Fri Mar 1 11:04:22 1995
9 * Initial Source Release: Thursday, March 7 1996
10 * Language: C
11 * Package: Hewlett-Packard JPEG Encoder/Decoder
12 *
13 * Copyright (c) 1999 Digital Imaging Group, Inc.
14 * For conditions of distribution and use, see copyright notice
15 * in Flashpix.h
16 *
17 ******************************************************************************
18 */
19 #define IMP_ENCODER
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include "jpegconf.h"
24
25 #include "ejpeg.h"
26
27 #include "enctile.h"
28 #include "encoder.h"
29 #include "public.h"
30 #include "process.h"
31 #include "fpxmem.h"
32
33 #ifndef FALSE
34 #define FALSE 0
35 #endif
36 #ifndef TRUE
37 #define TRUE 1
38 #endif
39
40 /*
41 The simplest JPEG scenario involves RGB data (no alpha) passed to the
42 encoder. With calls to eJPEG_Init, then eJPEG_InitCompression, then
43 eJPEG_EncodeTile, you get no subsampling, internal RGB->YCbCr, Q-Factor
44 of 50, internal Huffman and Q-tables. Other routines allow you to
45 disable some or all of the internal subsampling and YCbCr conversions.
46
47 A single call to eJPEG_DisableInternalYCbCr allows opponent color spaces
48 (like FlashPix-YCC) to be used. This new sequence would be eJPEG_Init,
49 eJPEG_DisableInternalYCbCr, eJPEG_InitCompression, then eJPEG_EncodeTile.
50
51 All modifications to the encoder's behavior come between the calls
52 eJPEG_Init and eJPEG_.
53 */
54
55 /*
56 ** No matter what else you do, you have to call this.
57 */
eJPEG_Init(void ** encoder)58 int eJPEG_Init(void **encoder)
59 {
60
61 ENCODER_STRUCT *jpg ;
62 int x;
63
64 if(!( *encoder = (ENCODER_STRUCT *)FPX_malloc( sizeof(ENCODER_STRUCT))))
65 return eJPEG_MEMORY_ERROR;
66 else
67 {
68 jpg = (ENCODER_STRUCT *)*encoder;
69 {
70 jpg->header = NULL;
71 jpg->headerBytes = 0;
72 jpg->ssDisabled = FALSE; /* internal subsampling is enabled */
73 jpg->YCrCbDisabled = FALSE; /* internal YCrCb is enabled */
74 jpg->xPixels = 64; /* defaulted to FlashPix baseline */
75 jpg->yPixels = 64; /* ditto */
76 jpg->bytes = 3; /* RGB is assumed */
77 jpg->scratch = (unsigned char *)
78 FPX_malloc(jpg->xPixels * jpg->yPixels * jpg->bytes);
79
80 if(jpg->scratch == NULL)
81 return eJPEG_MEMORY_ERROR; /* CHG_JPEG_MEM_FIX - added test */
82
83 jpg->subsampling = 0x11; /* no subsampling */
84
85 /* init iHsamp & iVsamp to reflect above defaults */
86 for(x = 0; x < 3; x++)
87 jpg->iHsamp[x] = jpg->iVsamp[x] = 1;
88
89 jpg->iHsamp[3] = jpg->iVsamp[3] = 0;
90 jpg->qFactor = 50; /* defaulted to 50 */
91 jpg->interleaveType = 0; /* interleaved */
92
93 SetDefaultTables((void *) jpg);
94
95 return eJPEG_NO_ERROR;
96 }
97 }
98 return eJPEG_MEMORY_ERROR;
99 }
100
101 /*
102 If you want to do any required subsampling, call this next. NOTE: Internal
103 subsampling will only be performed if you later call eJPEG_SetSubsampling with
104 arguments that will call for it.
105 Once more, with feeling...
106 By disabling internal subsampling, you're telling the eJPEG_EncodeTile
107 function that tile data passed to it has already been subsampled correctly,
108 and it is a very trusting function, so don't lie.
109 */
eJPEG_DisableInternalSubsampling(void * encoder)110 int eJPEG_DisableInternalSubsampling(void *encoder)
111 {
112 ENCODER_STRUCT *jpg = (ENCODER_STRUCT *)encoder;
113
114 if (jpg != NULL){
115 jpg->ssDisabled = TRUE;
116 return(eJPEG_NO_ERROR);
117 }
118 else
119 return(eJPEG_INVALID_ENCODER);
120 }
121
122 /*
123 If you already have opponent color data (like FlashPix-YCC), call this. You might
124 also want to pass RGB data to the encoder (in which case, you probably don't want
125 it subsampled either, see above), or for some strange reason you might want to
126 do the YCbCr conversion yourself. In any case, be sure to set the "Internal
127 color conversion" field of the compression subtype correctly.
128 */
eJPEG_DisableInternalYCbCr(void * encoder)129 int eJPEG_DisableInternalYCbCr(void *encoder)
130 {
131 ENCODER_STRUCT *jpg = (ENCODER_STRUCT *)encoder;
132
133 if(jpg != NULL){
134 jpg->YCrCbDisabled = TRUE;
135 return(eJPEG_NO_ERROR);
136 }
137 else
138 return(eJPEG_INVALID_ENCODER);
139 }
140
141 /*
142 Pass the same value to this function as you would put in the compression subtype's
143 "Chroma subsampling." Note, however, that this particular encoder will not support
144 */
eJPEG_SetSubsampling(void * encoder,unsigned char subSampling)145 int eJPEG_SetSubsampling(
146 void *encoder, /* same value returned by eJPEG_Init */
147 unsigned char subSampling /* pass the same value you'd put in the FlashPix
148 compression subtype field for JPEG data */
149 )
150 {
151 ENCODER_STRUCT *jpg = (ENCODER_STRUCT *)encoder;
152 int ret, x;
153
154 if(jpg != NULL){
155 if((subSampling == 0x11) || (subSampling == 0x22) || (subSampling == 0x21) )
156 {
157 for(x = 0; x < jpg->bytes; x++)
158 jpg->iHsamp[x] = jpg->iVsamp[x] = 1; /* default */
159 if((jpg->bytes == 4) && (subSampling == 0x22))
160 {
161 jpg->subsampling = subSampling;
162 jpg->iHsamp[0] = jpg->iVsamp[0] = 2;
163 jpg->iHsamp[3] = jpg->iVsamp[3] = 2; /* alpha channel */
164 ret = eJPEG_NO_ERROR;
165 }
166 else
167 {
168 if(jpg->bytes == 3)
169 jpg->iHsamp[3] = jpg->iVsamp[3] = 0;
170 if(subSampling == 0x22)
171 jpg->iHsamp[0] = jpg->iVsamp[0] = 2;
172 else if (subSampling == 0x21){
173 jpg->iHsamp[0] = 2;
174 jpg->iVsamp[0] = 1;
175 }
176 jpg->subsampling = subSampling;
177 ret = eJPEG_NO_ERROR;
178 }
179 }
180 else
181 ret = eJPEG_UNSUPPORTED_SUBSAMPLING;
182
183 return(ret);
184 }
185 else
186 return(eJPEG_INVALID_ENCODER);
187 }
188
eJPEG_EnableInternalYCbCr(void * encoder)189 int eJPEG_EnableInternalYCbCr(void *encoder)
190 {
191 ENCODER_STRUCT *jpg = (ENCODER_STRUCT *)encoder;
192
193 if(jpg != NULL ){
194 jpg->YCrCbDisabled = FALSE; /* not sure if this will work */
195 return(eJPEG_NO_ERROR);
196 }
197 else
198 return(eJPEG_INVALID_ENCODER);
199 }
200
201
202 /* default is for channel interleave to be on, hence there is
203 no need to call this routine if the interleave has never
204 been disabled.
205 */
eJPEG_EnableChannelInterleave(void * encoder)206 int eJPEG_EnableChannelInterleave(void *encoder)
207 {
208 ENCODER_STRUCT *jpg = (ENCODER_STRUCT *)encoder;
209
210 if(jpg != NULL ){
211 jpg->interleaveType = 0; /* channels are interleaved */
212 return(eJPEG_NO_ERROR);
213 }
214 else
215 return(eJPEG_INVALID_ENCODER);
216 }
217
eJPEG_DisableChannelInterleave(void * encoder)218 int eJPEG_DisableChannelInterleave(void *encoder)
219 {
220 ENCODER_STRUCT *jpg = (ENCODER_STRUCT *)encoder;
221
222 if(jpg != NULL ){
223 jpg->interleaveType = 1;
224 return(eJPEG_NO_ERROR);
225 }
226 else
227 return(eJPEG_INVALID_ENCODER);
228 }
229
230 /* Call this routine to change from the default Q factor. */
eJPEG_SetQFactor(void * encoder,int quality)231 int eJPEG_SetQFactor(
232 void *encoder, /* same value returned by eJPEG_Init */
233 int quality /* default is 50 */
234 )
235 {
236 ENCODER_STRUCT *jpg = (ENCODER_STRUCT *)encoder;
237
238 if(jpg != NULL){
239 if (quality > 255)
240 quality = 255;
241 else if (quality < 0)
242 quality = 0;
243 jpg->qFactor = quality;
244 return(eJPEG_NO_ERROR);
245 }
246 else
247 return(eJPEG_INVALID_ENCODER);
248 }
249
250 /* Call this routine if you want to use custom Huffman Tables.
251 The custom tables are specified in the HuffTables array of
252 huffman tables. The tables in that array should alternate
253 DC-AC-DC-AC ... (a maximum of eight tables).Be careful with
254 the 'ident' values set. JPEG requires that these values be
255 0,1,2,or 3 for extended JPEG systems, but only 0 or 1 for
256 baseline JPEG systems.
257 */
eJPEG_SetHuffTables(void * encoder,int NumbHuffTables,JPEGHuffTable ** HuffTables,unsigned char * CompDCHuffIdent,unsigned char * CompACHuffIdent)258 int eJPEG_SetHuffTables(void *encoder,
259 int NumbHuffTables,
260 JPEGHuffTable **HuffTables,
261 unsigned char * CompDCHuffIdent,
262 unsigned char * CompACHuffIdent)
263 {
264 ENCODER_STRUCT* jpg = (ENCODER_STRUCT *)encoder;
265 JPEGHuffTable *hufftable;
266 int i;
267
268 if (((NumbHuffTables%2)!=0) || (NumbHuffTables> 8) || (NumbHuffTables < 2))
269 return(eJPEG_BAD_HUFFMAN_TABLE);
270
271 jpg->nu_huff = NumbHuffTables;
272 hufftable = (JPEGHuffTable *) HuffTables;
273 for (i=0; i < NumbHuffTables; i++, hufftable++) {
274 jpg->HuffTables[i].bits = hufftable->bits;
275 jpg->HuffTables[i].vals = hufftable->vals;
276 jpg->HuffTables[i].hclass = hufftable->hclass;
277 jpg->HuffTables[i].ident = hufftable->ident;
278 }
279 for (i=NumbHuffTables; i < 8 ;i++) {
280 jpg->HuffTables[i].bits = NULL;
281 jpg->HuffTables[i].vals = NULL;
282 jpg->HuffTables[i].hclass = 0;
283 jpg->HuffTables[i].ident = 0;
284 }
285 for (i=0; i < 4; i++) {
286 jpg->CompDCHuffIdent[i] = CompDCHuffIdent[i];
287 jpg->CompACHuffIdent[i] = CompACHuffIdent[i];
288 }
289
290 return(eJPEG_NO_ERROR);
291 }
292
293
294 /* Call this routine if you want to use custom Quantization Tables.
295 The custom tables are specified in the QuantTables array of
296 QuantTables tables. The ident field of these tables
297 should have the values 0,1,2 or 3.
298 */
eJPEG_SetQuantTables(void * encoder,int NumbQuantTables,JPEGQuantTable ** QuantTables,unsigned char * CompQuantIdent)299 int eJPEG_SetQuantTables(void* encoder,
300 int NumbQuantTables, JPEGQuantTable **QuantTables,
301 unsigned char* CompQuantIdent)
302 {
303 ENCODER_STRUCT* jpg = (ENCODER_STRUCT *)encoder;
304 JPEGQuantTable *quant;
305 int i;
306
307 if (NumbQuantTables > 4 || NumbQuantTables < 1)
308 return(eJPEG_BAD_QUANT_TABLE);
309
310 jpg->nu_qtables = NumbQuantTables;
311
312 for (i=0, quant=(JPEGQuantTable *) QuantTables; i < NumbQuantTables; i++, quant++) {
313 jpg->QuantTables[i].quantizer = quant->quantizer;
314 jpg->QuantTables[i].ident = quant->ident;
315
316 }
317 for (i=NumbQuantTables; i < 4 ;i++) {
318 jpg->QuantTables[i].quantizer = NULL;
319 jpg->QuantTables[i].ident = 0;
320 }
321 for (i=0; i < 4; i++) {
322 jpg->CompQuantIdent[i] = CompQuantIdent[i];
323 }
324
325 return(eJPEG_NO_ERROR);
326 }
327
eJPEG_SetTileSize(void * encoder,int hSize,int vSize,int bytesPerPixel)328 int eJPEG_SetTileSize(
329 void *encoder,
330 int hSize, /* in pixels, the width of a tile */
331 int vSize, /* in pixels, the height of a tile */
332 int bytesPerPixel /* how many bytes per pixel */
333 )
334 {
335 ENCODER_STRUCT *jpg = (ENCODER_STRUCT *)encoder;
336 int ret, x;
337
338 if(jpg != NULL ){
339 if((bytesPerPixel > 4) || (bytesPerPixel < 1))
340 ret = eJPEG_UNSUPPORTED_BYTES_PER_PIXEL;
341 else{
342 jpg->xPixels = hSize;
343 jpg->yPixels = vSize;
344 jpg->bytes = bytesPerPixel;
345
346 if (jpg->scratch != NULL) FPX_free(jpg->scratch);
347 jpg->scratch =
348 (unsigned char *) FPX_malloc(hSize * vSize * bytesPerPixel);
349
350 if (jpg->scratch == NULL) /* CHG_JPEG_MEM_FIX - added check */
351 return (eJPEG_MEMORY_ERROR);
352
353 for(x = 0; x < jpg->bytes; x++)
354 jpg->iHsamp[x] = jpg->iVsamp[x] = 1;
355
356 /* Subsampling of 1 and 2-channel images is not supported, so */
357 /* disable internal subdsampling. Note that the FlashPix spec */
358 /* does not specify what subsampling values are valid for these */
359 /* cases, so we simply ignore them via the following override. */
360 if((jpg->bytes < 3) && (jpg->subsampling > 0x11)){
361 jpg->subsampling = 0x11;
362 ret = eJPEG_NO_ERROR;
363 }
364 else if (jpg->subsampling == 0x22)
365 {
366 if (jpg->bytes == 4) {
367 jpg->iHsamp[0] = jpg->iVsamp[0] = 2;
368 jpg->iHsamp[3] = jpg->iVsamp[3] = 2;
369 }
370 else {
371 jpg->iHsamp[0] = jpg->iVsamp[0] = 2;
372 }
373 ret = eJPEG_NO_ERROR;
374 }
375 else if (jpg->subsampling == 0x21)
376 {
377 if (jpg->bytes == 4) {
378 jpg->iHsamp[0] = 2;
379 jpg->iHsamp[3] = 2;
380 }
381 else {
382 jpg->iHsamp[0] = 2;
383 }
384 jpg->iHsamp[0] = 2;
385 ret = eJPEG_NO_ERROR;
386 }
387 else { /* must be non-subsampled (0x11) */
388
389 ret = eJPEG_NO_ERROR;
390 }
391 }
392
393 return(ret);
394 }
395 else
396 return(eJPEG_INVALID_ENCODER);
397
398 }
399
400 /*
401 The next two functions are an either/or situation. If you want the
402 data in each tile to be a fully compliant JFIF stream, you call
403 eJPEG_ConcatenateHeader. If you want to store the header separately
404 from all the tiles, you call eJPEG_CreateHeader, which will return
405 you a header that you can store in the JPEG Tables section of one
406 of the far too numerous FlashPix property sets (compression information
407 property group). Note that it is your responsibility to make certain
408 you put the proper ID in the JPEG tables selector of the tile's
409 compression subtype field.
410 */
eJPEG_CreateHeader(void * encoder,long hdrBufferSize,unsigned char * hdrBuffer,long * hdrBufferUsed)411 int eJPEG_CreateHeader(
412 void *encoder, /* same value returned by eJPEG_Init */
413 long hdrBufferSize, /* the size of the <hdrBuffer> in bytes */
414 unsigned char *hdrBuffer, /* the buffer itself */
415 long *hdrBufferUsed /* upon return shows the amount of
416 <hdrBuffer> that was used */
417 )
418 {
419 ENCODER_STRUCT *jpg = (ENCODER_STRUCT *)encoder;
420
421 if(jpg != NULL ){
422
423 JPEGEncodeTileInit(
424 NULL,
425 jpg->xPixels,
426 jpg->yPixels,
427 jpg->bytes, /* number of bytes per pixel */
428 jpg->qFactor,
429 jpg->iHsamp,
430 jpg->iVsamp, /* Hor. & Vert. subsampling factors */
431 jpg->interleaveType,
432 &jpg->tile_data,
433 jpg->nu_huff, /* # of Huffman Tables (a max of 8 tables, ie four DC-AC sets) */
434 jpg->HuffTables,
435 jpg->CompDCHuffIdent,
436 jpg->CompACHuffIdent,
437 jpg->nu_qtables, /* # of Q-tables (a max of 4 tables) */
438 jpg->QuantTables,
439 jpg->CompQuantIdent,
440 &jpg->jpegStruct,
441 hdrBuffer,
442 hdrBufferSize,
443 hdrBufferUsed);
444
445 return(eJPEG_NO_ERROR);
446 }
447 else
448 return(eJPEG_INVALID_ENCODER);
449 }
450
451 /* see explanation above */
452 #define HDR_BUFF_SIZE 1440
eJPEG_ConcatenateHeader(void * encoder)453 int eJPEG_ConcatenateHeader(
454 void *encoder /* same value returned by eJPEG_Init */
455 )
456 {
457 int ret;
458 long size,size_minus_eoi;
459 unsigned char tempBuf[HDR_BUFF_SIZE];
460 ENCODER_STRUCT *jpg = (ENCODER_STRUCT *)encoder;
461
462 ret = eJPEG_CreateHeader(encoder, HDR_BUFF_SIZE, tempBuf, &size);
463 size_minus_eoi = size-2;
464
465 if(ret)
466 return(ret);
467
468 if(jpg != NULL ){
469 jpg->headerBytes = size_minus_eoi;
470 jpg->header = (unsigned char *) FPX_malloc(size);
471 if (memcpy(jpg->header, tempBuf, (size_t) size_minus_eoi))
472 ret = eJPEG_NO_ERROR;
473 else
474 ret = eJPEG_MEMORY_ERROR;
475
476 }
477
478 return(ret);
479 }
480
eJPEG_EncodeTile(void * encoder,unsigned char * inbuf,unsigned char * outbuf,size_t outbuf_size)481 long eJPEG_EncodeTile(
482 void *encoder, /* same value returned by eJPEG_Init */
483 unsigned char *inbuf, /* assumed to be the size of a tile or sub-
484 sampled tile! */
485 unsigned char *outbuf, /* the buffer to put the compressed tile into */
486 size_t outbuf_size /* size of the output buffer */
487 )
488 {
489 int check;
490 long finalSize;
491 size_t inBufSize;
492 long offset;
493 ENCODER_STRUCT *jpg = (ENCODER_STRUCT *)encoder;
494
495 if(jpg != NULL ){
496 inBufSize = jpg->xPixels * jpg->yPixels * jpg->bytes;
497
498 /* initialize output buffer to input buffer (needed for
499 no color rotation, no subsample case)
500 */
501 if (inBufSize < outbuf_size)
502 return (-1);
503 memcpy(jpg->scratch, inbuf, inBufSize);
504
505 /* decide whether or not we need to subsample and/or YCrCb */
506 if(!jpg->YCrCbDisabled)
507 {
508 if(!jpg->ssDisabled && (jpg->subsampling == 0x22)){
509 /* subsample and YCrCb */
510 RGBtoYCrCb_SubSample411(
511 (unsigned char *) inbuf,
512 (unsigned char *) jpg->scratch,
513 jpg->xPixels,
514 jpg->bytes);
515 if (jpg->bytes == 3)
516 inBufSize = inBufSize >> 1;
517 else if (jpg->bytes == 4)
518 inBufSize = 10 * inBufSize / 16;
519 }
520 else if (!jpg->ssDisabled && (jpg->subsampling == 0x21)) {
521 RGBtoYCrCb_SubSample422(
522 (unsigned char *) inbuf,
523 (unsigned char *) jpg->scratch,
524 jpg->xPixels,
525 jpg->bytes);
526 if (jpg->bytes == 3)
527 inBufSize = 4 * inBufSize / 6;
528 else if (jpg->bytes == 4)
529 inBufSize = 6 * inBufSize / 8;
530 }
531 else {
532 /* just YCrCb it */
533 RGBtoYCrCb(
534 (unsigned char *) inbuf,
535 (unsigned char *) jpg->scratch,
536 jpg->xPixels,
537 jpg->bytes);
538 }
539 }
540 else { /* don't YCrCb rotate */
541
542 if(!jpg->ssDisabled && (jpg->subsampling == 0x22)){
543 /* just subsample it */
544 SubSample411(
545 (unsigned char *) inbuf,
546 (unsigned char *) jpg->scratch,
547 jpg->xPixels,
548 jpg->bytes);
549 if (jpg->bytes == 3)
550 inBufSize = inBufSize >> 1;
551 else if (jpg->bytes == 4)
552 inBufSize = 10 * inBufSize / 16;
553 }
554 else if (!jpg->ssDisabled && (jpg->subsampling == 0x21)) {
555 SubSample422(
556 (unsigned char *)inbuf,
557 (unsigned char *) jpg->scratch,
558 jpg->xPixels,
559 jpg->bytes);
560 if (jpg->bytes == 3)
561 inBufSize = 4 * inBufSize / 6;
562 else if (jpg->bytes == 4)
563 inBufSize = 6 * inBufSize / 8;
564 }
565 }
566 jpg->tile_data.data = jpg->scratch;
567 offset = (jpg->headerBytes != 0) ? -2 : 0;
568
569 /* jpg->headerBytes != 0 means that header & entropy data are
570 in the same jfif bitstream, so the EOI-SOI markers at the
571 end of the header and the beginning of the entropy bitstreams
572 need to be striped off.
573 */
574 check = JPEGEncodeTile(
575 &jpg->tile_data,
576 &jpg->jpegStruct,
577 jpg->CompDCHuffIdent,
578 jpg->CompACHuffIdent,
579 jpg->CompQuantIdent,
580 outbuf + jpg->headerBytes + offset,
581 jpg->xPixels * jpg->yPixels * jpg->bytes,
582 &finalSize);
583 switch(check) {
584 case 0:
585 break;
586 /* Actual two error-returns from JPEGEncodeTile() */
587 case EJPEG_ERROR_MEM:
588 fprintf(stderr, "libfpx: JPEGEncodeTile %s\n",
589 "complained of lack of memory");
590 return -1;
591 case EJPEG_ERROR_EOF:
592 fprintf(stderr, "libfpx: JPEGEncodeTile %s\n",
593 "complained of corrupt file");
594 return -1;
595 default:
596 fprintf(stderr, "libfpx: JPEGEncodeTile %s\n",
597 "failed unexpectedly");
598 return -1;
599 }
600
601 /* Are supposed to include the header in the tile */
602 if(jpg->headerBytes){
603 memcpy(outbuf, jpg->header, (size_t)jpg->headerBytes);
604 finalSize += (jpg->headerBytes - 2);
605
606 /* adjusted by the size of the EOI-SOI markers which
607 have been striped off */
608 }
609 /* notice that the SOI in the entropy bitstream will be overwritten by
610 the last two bytes of the header bitstream */
611
612 }
613 return(finalSize);
614 }
615
616 /* Once you are finished with the encoder, you have to call this. */
eJPEG_Shutdown(void * encoder)617 int eJPEG_Shutdown(void* encoder)
618 {
619 ENCODER_STRUCT *jpg = (ENCODER_STRUCT *)encoder;
620
621 if( jpg )
622 {
623 if(jpg->header) {
624 FPX_free(jpg->header);
625 jpg->header = NULL; /* CHG_JPEG_MEM_FIX - clear ptr */
626 }
627 if(jpg->scratch) {
628 FPX_free(jpg->scratch);
629 jpg->scratch = NULL; /* CHG_JPEG_MEM_FIX - clear ptr */
630 }
631 FPX_free(jpg);
632 jpg = 0; /* CHG_JPEG_MEM_FIX - clear ptr */
633
634 return(TRUE);
635 }
636
637 return(FALSE);
638
639 } /* eJPEG_Shutdown() */
640