xref: /plan9-contrib/sys/src/cmd/gs/src/sjpegc.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1994, 1997, 1999 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: sjpegc.c,v 1.7 2002/03/30 23:55:15 giles Exp $ */
187dd7cddfSDavid du Colombier /* Interface routines for IJG code, common to encode/decode. */
197dd7cddfSDavid du Colombier #include "stdio_.h"
207dd7cddfSDavid du Colombier #include "string_.h"
217dd7cddfSDavid du Colombier #include "jpeglib_.h"
227dd7cddfSDavid du Colombier #include "jerror_.h"
237dd7cddfSDavid du Colombier #include "gx.h"
247dd7cddfSDavid du Colombier #include "gserrors.h"
257dd7cddfSDavid du Colombier #include "strimpl.h"
267dd7cddfSDavid du Colombier #include "sdct.h"
277dd7cddfSDavid du Colombier #include "sjpeg.h"
287dd7cddfSDavid du Colombier 
29*593dc095SDavid du Colombier /*
30*593dc095SDavid du Colombier   Ghostscript uses a non-public interface to libjpeg in order to
31*593dc095SDavid du Colombier   override the library's default memory manager implementation.
32*593dc095SDavid du Colombier   Since many users will want to compile Ghostscript using the
33*593dc095SDavid du Colombier   shared jpeg library, we provide these prototypes so that a copy
34*593dc095SDavid du Colombier   of the libjpeg source distribution is not needed.
35*593dc095SDavid du Colombier 
36*593dc095SDavid du Colombier   The presence of the jmemsys.h header file is detected in
37*593dc095SDavid du Colombier   unix-aux.mak, and written to gconfig_.h
38*593dc095SDavid du Colombier  */
39*593dc095SDavid du Colombier 
40*593dc095SDavid du Colombier #include "gconfig_.h"
41*593dc095SDavid du Colombier #ifdef DONT_HAVE_JMEMSYS_H
42*593dc095SDavid du Colombier 
43*593dc095SDavid du Colombier void *
44*593dc095SDavid du Colombier jpeg_get_small(j_common_ptr cinfo, size_t size);
45*593dc095SDavid du Colombier 
46*593dc095SDavid du Colombier void
47*593dc095SDavid du Colombier jpeg_free_small(j_common_ptr cinfo, void *object, size_t size);
48*593dc095SDavid du Colombier 
49*593dc095SDavid du Colombier void FAR *
50*593dc095SDavid du Colombier jpeg_get_large(j_common_ptr cinfo, size_t size);
51*593dc095SDavid du Colombier 
52*593dc095SDavid du Colombier void
53*593dc095SDavid du Colombier jpeg_free_large(j_common_ptr cinfo, void FAR * object, size_t size);
54*593dc095SDavid du Colombier typedef void *backing_store_ptr;
55*593dc095SDavid du Colombier 
56*593dc095SDavid du Colombier long
57*593dc095SDavid du Colombier jpeg_mem_available(j_common_ptr cinfo, long min_bytes_needed,
58*593dc095SDavid du Colombier 		   long max_bytes_needed, long already_allocated);
59*593dc095SDavid du Colombier 
60*593dc095SDavid du Colombier void
61*593dc095SDavid du Colombier jpeg_open_backing_store(j_common_ptr cinfo, backing_store_ptr info,
62*593dc095SDavid du Colombier 			long total_bytes_needed);
63*593dc095SDavid du Colombier 
64*593dc095SDavid du Colombier long
65*593dc095SDavid du Colombier jpeg_mem_init(j_common_ptr cinfo);
66*593dc095SDavid du Colombier 
67*593dc095SDavid du Colombier void
68*593dc095SDavid du Colombier jpeg_mem_term(j_common_ptr cinfo);
69*593dc095SDavid du Colombier 
70*593dc095SDavid du Colombier #else
71*593dc095SDavid du Colombier #include "jmemsys.h"		/* for prototypes */
72*593dc095SDavid du Colombier #endif
73*593dc095SDavid du Colombier 
743ff48bf5SDavid du Colombier private_st_jpeg_block();
753ff48bf5SDavid du Colombier 
767dd7cddfSDavid du Colombier /*
777dd7cddfSDavid du Colombier  * Error handling routines (these replace corresponding IJG routines from
787dd7cddfSDavid du Colombier  * jpeg/jerror.c).  These are used for both compression and decompression.
797dd7cddfSDavid du Colombier  * We assume
807dd7cddfSDavid du Colombier  * offset_of(jpeg_compress_data, cinfo)==offset_of(jpeg_decompress_data, dinfo)
817dd7cddfSDavid du Colombier  */
827dd7cddfSDavid du Colombier 
837dd7cddfSDavid du Colombier private void
gs_jpeg_error_exit(j_common_ptr cinfo)847dd7cddfSDavid du Colombier gs_jpeg_error_exit(j_common_ptr cinfo)
857dd7cddfSDavid du Colombier {
867dd7cddfSDavid du Colombier     jpeg_stream_data *jcomdp =
877dd7cddfSDavid du Colombier     (jpeg_stream_data *) ((char *)cinfo -
887dd7cddfSDavid du Colombier 			  offset_of(jpeg_compress_data, cinfo));
897dd7cddfSDavid du Colombier 
907dd7cddfSDavid du Colombier     longjmp(jcomdp->exit_jmpbuf, 1);
917dd7cddfSDavid du Colombier }
927dd7cddfSDavid du Colombier 
937dd7cddfSDavid du Colombier private void
gs_jpeg_emit_message(j_common_ptr cinfo,int msg_level)947dd7cddfSDavid du Colombier gs_jpeg_emit_message(j_common_ptr cinfo, int msg_level)
957dd7cddfSDavid du Colombier {
967dd7cddfSDavid du Colombier     if (msg_level < 0) {	/* GS policy is to ignore IJG warnings when Picky=0,
977dd7cddfSDavid du Colombier 				 * treat them as errors when Picky=1.
987dd7cddfSDavid du Colombier 				 */
997dd7cddfSDavid du Colombier 	jpeg_stream_data *jcomdp =
1007dd7cddfSDavid du Colombier 	(jpeg_stream_data *) ((char *)cinfo -
1017dd7cddfSDavid du Colombier 			      offset_of(jpeg_compress_data, cinfo));
1027dd7cddfSDavid du Colombier 
1037dd7cddfSDavid du Colombier 	if (jcomdp->Picky)
1047dd7cddfSDavid du Colombier 	    gs_jpeg_error_exit(cinfo);
1057dd7cddfSDavid du Colombier     }
1067dd7cddfSDavid du Colombier     /* Trace messages are always ignored. */
1077dd7cddfSDavid du Colombier }
1087dd7cddfSDavid du Colombier 
1097dd7cddfSDavid du Colombier /*
1107dd7cddfSDavid du Colombier  * This routine initializes the error manager fields in the JPEG object.
1117dd7cddfSDavid du Colombier  * It is based on jpeg_std_error from jpeg/jerror.c.
1127dd7cddfSDavid du Colombier  */
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier void
gs_jpeg_error_setup(stream_DCT_state * st)1157dd7cddfSDavid du Colombier gs_jpeg_error_setup(stream_DCT_state * st)
1167dd7cddfSDavid du Colombier {
1177dd7cddfSDavid du Colombier     struct jpeg_error_mgr *err = &st->data.common->err;
1187dd7cddfSDavid du Colombier 
1197dd7cddfSDavid du Colombier     /* Initialize the JPEG compression object with default error handling */
1207dd7cddfSDavid du Colombier     jpeg_std_error(err);
1217dd7cddfSDavid du Colombier 
1227dd7cddfSDavid du Colombier     /* Replace some methods with our own versions */
1237dd7cddfSDavid du Colombier     err->error_exit = gs_jpeg_error_exit;
1247dd7cddfSDavid du Colombier     err->emit_message = gs_jpeg_emit_message;
1257dd7cddfSDavid du Colombier 
1267dd7cddfSDavid du Colombier     st->data.compress->cinfo.err = err;		/* works for decompress case too */
1277dd7cddfSDavid du Colombier }
1287dd7cddfSDavid du Colombier 
1297dd7cddfSDavid du Colombier /* Stuff the IJG error message into errorinfo after an error exit. */
1307dd7cddfSDavid du Colombier 
1317dd7cddfSDavid du Colombier int
gs_jpeg_log_error(stream_DCT_state * st)1327dd7cddfSDavid du Colombier gs_jpeg_log_error(stream_DCT_state * st)
1337dd7cddfSDavid du Colombier {
1347dd7cddfSDavid du Colombier     j_common_ptr cinfo = (j_common_ptr) & st->data.compress->cinfo;
1357dd7cddfSDavid du Colombier     char buffer[JMSG_LENGTH_MAX];
1367dd7cddfSDavid du Colombier 
1377dd7cddfSDavid du Colombier     /* Format the error message */
1387dd7cddfSDavid du Colombier     (*cinfo->err->format_message) (cinfo, buffer);
1397dd7cddfSDavid du Colombier     (*st->report_error) ((stream_state *) st, buffer);
1407dd7cddfSDavid du Colombier     return gs_error_ioerror;	/* caller will do return_error() */
1417dd7cddfSDavid du Colombier }
1427dd7cddfSDavid du Colombier 
1437dd7cddfSDavid du Colombier 
1447dd7cddfSDavid du Colombier /*
1457dd7cddfSDavid du Colombier  * Interface routines.  This layer of routines exists solely to limit
1467dd7cddfSDavid du Colombier  * side-effects from using setjmp.
1477dd7cddfSDavid du Colombier  */
1487dd7cddfSDavid du Colombier 
1497dd7cddfSDavid du Colombier 
1507dd7cddfSDavid du Colombier JQUANT_TBL *
gs_jpeg_alloc_quant_table(stream_DCT_state * st)1517dd7cddfSDavid du Colombier gs_jpeg_alloc_quant_table(stream_DCT_state * st)
1527dd7cddfSDavid du Colombier {
1537dd7cddfSDavid du Colombier     if (setjmp(st->data.common->exit_jmpbuf)) {
1547dd7cddfSDavid du Colombier 	gs_jpeg_log_error(st);
1557dd7cddfSDavid du Colombier 	return NULL;
1567dd7cddfSDavid du Colombier     }
1577dd7cddfSDavid du Colombier     return jpeg_alloc_quant_table((j_common_ptr)
1587dd7cddfSDavid du Colombier 				  & st->data.compress->cinfo);
1597dd7cddfSDavid du Colombier }
1607dd7cddfSDavid du Colombier 
1617dd7cddfSDavid du Colombier JHUFF_TBL *
gs_jpeg_alloc_huff_table(stream_DCT_state * st)1627dd7cddfSDavid du Colombier gs_jpeg_alloc_huff_table(stream_DCT_state * st)
1637dd7cddfSDavid du Colombier {
1647dd7cddfSDavid du Colombier     if (setjmp(st->data.common->exit_jmpbuf)) {
1657dd7cddfSDavid du Colombier 	gs_jpeg_log_error(st);
1667dd7cddfSDavid du Colombier 	return NULL;
1677dd7cddfSDavid du Colombier     }
1687dd7cddfSDavid du Colombier     return jpeg_alloc_huff_table((j_common_ptr)
1697dd7cddfSDavid du Colombier 				 & st->data.compress->cinfo);
1707dd7cddfSDavid du Colombier }
1717dd7cddfSDavid du Colombier 
1727dd7cddfSDavid du Colombier int
gs_jpeg_destroy(stream_DCT_state * st)1737dd7cddfSDavid du Colombier gs_jpeg_destroy(stream_DCT_state * st)
1747dd7cddfSDavid du Colombier {
1757dd7cddfSDavid du Colombier     if (setjmp(st->data.common->exit_jmpbuf))
1767dd7cddfSDavid du Colombier 	return_error(gs_jpeg_log_error(st));
1777dd7cddfSDavid du Colombier     jpeg_destroy((j_common_ptr) & st->data.compress->cinfo);
1787dd7cddfSDavid du Colombier     return 0;
1797dd7cddfSDavid du Colombier }
1807dd7cddfSDavid du Colombier 
1817dd7cddfSDavid du Colombier 
1827dd7cddfSDavid du Colombier /*
1837dd7cddfSDavid du Colombier  * These routines replace the low-level memory manager of the IJG library.
1847dd7cddfSDavid du Colombier  * They pass malloc/free calls to the Ghostscript memory manager.
1857dd7cddfSDavid du Colombier  * Note we do not need these to be declared in any GS header file.
1867dd7cddfSDavid du Colombier  */
1877dd7cddfSDavid du Colombier 
1883ff48bf5SDavid du Colombier private inline jpeg_compress_data *
cinfo2jcd(j_common_ptr cinfo)1893ff48bf5SDavid du Colombier cinfo2jcd(j_common_ptr cinfo)
1903ff48bf5SDavid du Colombier {   /* We use the offset of cinfo in jpeg_compress data here, but we */
1913ff48bf5SDavid du Colombier     /* could equally well have used jpeg_decompress_data.            */
1923ff48bf5SDavid du Colombier     return (jpeg_compress_data *)
1933ff48bf5SDavid du Colombier       ((byte *)cinfo - offset_of(jpeg_compress_data, cinfo));
1943ff48bf5SDavid du Colombier }
1957dd7cddfSDavid du Colombier 
1963ff48bf5SDavid du Colombier private void *
jpeg_alloc(j_common_ptr cinfo,size_t size,const char * info)1973ff48bf5SDavid du Colombier jpeg_alloc(j_common_ptr cinfo, size_t size, const char *info)
1983ff48bf5SDavid du Colombier {
1993ff48bf5SDavid du Colombier     jpeg_compress_data *jcd = cinfo2jcd(cinfo);
2003ff48bf5SDavid du Colombier     gs_memory_t *mem = jcd->memory;
2013ff48bf5SDavid du Colombier 
2023ff48bf5SDavid du Colombier     jpeg_block_t *p = gs_alloc_struct_immovable(mem, jpeg_block_t,
2033ff48bf5SDavid du Colombier     			&st_jpeg_block, "jpeg_alloc(block)");
2043ff48bf5SDavid du Colombier     void *data = gs_alloc_bytes_immovable(mem, size, info);
2053ff48bf5SDavid du Colombier 
2063ff48bf5SDavid du Colombier     if (p == 0 || data == 0) {
2073ff48bf5SDavid du Colombier 	gs_free_object(mem, data, info);
2083ff48bf5SDavid du Colombier 	gs_free_object(mem, p, "jpeg_alloc(block)");
2093ff48bf5SDavid du Colombier 	return 0;
2103ff48bf5SDavid du Colombier     }
2113ff48bf5SDavid du Colombier     p->data = data;
2123ff48bf5SDavid du Colombier     p->next = jcd->blocks;
2133ff48bf5SDavid du Colombier     jcd->blocks = p;
2143ff48bf5SDavid du Colombier     return data;
2153ff48bf5SDavid du Colombier }
2163ff48bf5SDavid du Colombier 
2173ff48bf5SDavid du Colombier private void
jpeg_free(j_common_ptr cinfo,void * data,const char * info)2183ff48bf5SDavid du Colombier jpeg_free(j_common_ptr cinfo, void *data, const char *info)
2193ff48bf5SDavid du Colombier {
2203ff48bf5SDavid du Colombier     jpeg_compress_data *jcd = cinfo2jcd(cinfo);
2213ff48bf5SDavid du Colombier     gs_memory_t *mem = jcd->memory;
2223ff48bf5SDavid du Colombier     jpeg_block_t  *p  =  jcd->blocks;
2233ff48bf5SDavid du Colombier     jpeg_block_t **pp = &jcd->blocks;
2243ff48bf5SDavid du Colombier 
2253ff48bf5SDavid du Colombier     gs_free_object(mem, data, info);
2263ff48bf5SDavid du Colombier     while(p && p->data != data)
2273ff48bf5SDavid du Colombier       { pp = &p->next;
2283ff48bf5SDavid du Colombier         p = p->next;
2293ff48bf5SDavid du Colombier       }
2303ff48bf5SDavid du Colombier     if(p == 0)
2313ff48bf5SDavid du Colombier       lprintf1("Freeing unrecorded JPEG data 0x%lx!\n", (ulong)data);
2323ff48bf5SDavid du Colombier     else
2333ff48bf5SDavid du Colombier       *pp = p->next;
2343ff48bf5SDavid du Colombier     gs_free_object(mem, p, "jpeg_free(block)");
2357dd7cddfSDavid du Colombier }
2367dd7cddfSDavid du Colombier 
2377dd7cddfSDavid du Colombier void *
jpeg_get_small(j_common_ptr cinfo,size_t size)2383ff48bf5SDavid du Colombier jpeg_get_small(j_common_ptr cinfo, size_t size)
2397dd7cddfSDavid du Colombier {
2403ff48bf5SDavid du Colombier     return jpeg_alloc(cinfo, size, "JPEG small internal data allocation");
2417dd7cddfSDavid du Colombier }
2427dd7cddfSDavid du Colombier 
2437dd7cddfSDavid du Colombier void
jpeg_free_small(j_common_ptr cinfo,void * object,size_t size)2443ff48bf5SDavid du Colombier jpeg_free_small(j_common_ptr cinfo, void *object, size_t size)
2457dd7cddfSDavid du Colombier {
2463ff48bf5SDavid du Colombier     jpeg_free(cinfo, object, "Freeing JPEG small internal data");
2477dd7cddfSDavid du Colombier }
2487dd7cddfSDavid du Colombier 
2497dd7cddfSDavid du Colombier void FAR *
jpeg_get_large(j_common_ptr cinfo,size_t size)2503ff48bf5SDavid du Colombier jpeg_get_large(j_common_ptr cinfo, size_t size)
2517dd7cddfSDavid du Colombier {
2523ff48bf5SDavid du Colombier     return jpeg_alloc(cinfo, size, "JPEG large internal data allocation");
2537dd7cddfSDavid du Colombier }
2547dd7cddfSDavid du Colombier 
2557dd7cddfSDavid du Colombier void
jpeg_free_large(j_common_ptr cinfo,void FAR * object,size_t size)2563ff48bf5SDavid du Colombier jpeg_free_large(j_common_ptr cinfo, void FAR * object, size_t size)
2577dd7cddfSDavid du Colombier {
2583ff48bf5SDavid du Colombier     jpeg_free(cinfo, object, "Freeing JPEG large internal data");
2597dd7cddfSDavid du Colombier }
2607dd7cddfSDavid du Colombier 
2617dd7cddfSDavid du Colombier long
jpeg_mem_available(j_common_ptr cinfo,long min_bytes_needed,long max_bytes_needed,long already_allocated)2627dd7cddfSDavid du Colombier jpeg_mem_available(j_common_ptr cinfo, long min_bytes_needed,
2637dd7cddfSDavid du Colombier 		   long max_bytes_needed, long already_allocated)
2647dd7cddfSDavid du Colombier {
2657dd7cddfSDavid du Colombier     return max_bytes_needed;
2667dd7cddfSDavid du Colombier }
2677dd7cddfSDavid du Colombier 
2687dd7cddfSDavid du Colombier void
jpeg_open_backing_store(j_common_ptr cinfo,backing_store_ptr info,long total_bytes_needed)2697dd7cddfSDavid du Colombier jpeg_open_backing_store(j_common_ptr cinfo, backing_store_ptr info,
2707dd7cddfSDavid du Colombier 			long total_bytes_needed)
2717dd7cddfSDavid du Colombier {
2727dd7cddfSDavid du Colombier     ERREXIT(cinfo, JERR_NO_BACKING_STORE);
2737dd7cddfSDavid du Colombier }
2747dd7cddfSDavid du Colombier 
2757dd7cddfSDavid du Colombier long
jpeg_mem_init(j_common_ptr cinfo)2767dd7cddfSDavid du Colombier jpeg_mem_init(j_common_ptr cinfo)
2777dd7cddfSDavid du Colombier {
2787dd7cddfSDavid du Colombier     return 0;			/* just set max_memory_to_use to 0 */
2797dd7cddfSDavid du Colombier }
2807dd7cddfSDavid du Colombier 
2817dd7cddfSDavid du Colombier void
jpeg_mem_term(j_common_ptr cinfo)2827dd7cddfSDavid du Colombier jpeg_mem_term(j_common_ptr cinfo)
2837dd7cddfSDavid du Colombier {
2847dd7cddfSDavid du Colombier     /* no work */
2857dd7cddfSDavid du Colombier }
286