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