Line data Source code
1 : /* Copyright (C) 2000-2012 by George Williams */
2 : /*
3 : * Redistribution and use in source and binary forms, with or without
4 : * modification, are permitted provided that the following conditions are met:
5 :
6 : * Redistributions of source code must retain the above copyright notice, this
7 : * list of conditions and the following disclaimer.
8 :
9 : * Redistributions in binary form must reproduce the above copyright notice,
10 : * this list of conditions and the following disclaimer in the documentation
11 : * and/or other materials provided with the distribution.
12 :
13 : * The name of the author may not be used to endorse or promote products
14 : * derived from this software without specific prior written permission.
15 :
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 : * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : */
27 :
28 : #include <fontforge-config.h>
29 :
30 : #ifdef _NO_LIBJPEG
31 :
32 : static int a_file_must_define_something=0; /* ANSI says so */
33 :
34 : #else
35 :
36 : #include <sys/types.h>
37 : #include <stdio.h>
38 : #include <jpeglib.h>
39 : #include <jerror.h>
40 :
41 : #include <setjmp.h>
42 :
43 : #include "gimage.h"
44 :
45 : /******************************************************************************/
46 :
47 : struct my_error_mgr {
48 : struct jpeg_error_mgr pub; /* "public" fields */
49 :
50 : jmp_buf setjmp_buffer; /* for return to caller */
51 : int padding[8]; /* On my solaris box jmp_buf is the wrong size */
52 : };
53 :
54 : typedef struct my_error_mgr * my_error_ptr;
55 :
56 : METHODDEF(void)
57 0 : my_error_exit (j_common_ptr cinfo)
58 : {
59 : /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
60 0 : my_error_ptr myerr = (my_error_ptr) cinfo->err;
61 :
62 : /* Always display the message. */
63 : /* We could postpone this until after returning, if we chose. */
64 0 : (*cinfo->err->output_message) (cinfo);
65 :
66 : /* Return control to the setjmp point */
67 0 : longjmp(myerr->setjmp_buffer, 1);
68 : }
69 :
70 0 : static void transferImageToBuffer(struct _GImage *base,JSAMPLE *buffer,int w,int ypos) {
71 : JSAMPLE *pt, *end;
72 : uint32 *ppt;
73 :
74 0 : ppt = (uint32 *) (base->data + ypos*base->bytes_per_line);
75 0 : if ( base->image_type==it_index && base->clut==NULL ) {
76 0 : unsigned char *px = (unsigned char *) ppt; int col;
77 0 : register int bit=0x80;
78 0 : for ( pt = buffer, end = pt+3*w; pt<end; ) {
79 0 : if ( *px&bit ) col = 0xffffff;
80 0 : else col = 0;
81 0 : if (( bit >>= 1 )== 0 ) { ++px; bit = 0x80; }
82 0 : *pt++ = COLOR_RED(col);
83 0 : *pt++ = COLOR_GREEN(col);
84 0 : *pt++ = COLOR_BLUE(col);
85 : }
86 0 : } else if ( base->image_type==it_index ) {
87 0 : unsigned char *px = (unsigned char *) ppt; int col;
88 0 : register int bit=0x80;
89 0 : for ( pt = buffer, end = pt+3*w; pt<end; ) {
90 0 : if ( *px&bit ) col = base->clut->clut[1];
91 0 : else col = base->clut->clut[0];
92 0 : if (( bit >>= 1 )== 0 ) { ++px; bit = 0x80; }
93 0 : *pt++ = COLOR_RED(col);
94 0 : *pt++ = COLOR_GREEN(col);
95 0 : *pt++ = COLOR_BLUE(col);
96 : }
97 0 : } else if ( base->image_type==it_index ) {
98 0 : unsigned char *px = (unsigned char *) ppt; int col;
99 0 : for ( pt = buffer, end = pt+3*w; pt<end; ) {
100 0 : col = base->clut->clut[ *px++ ];
101 0 : *pt++ = COLOR_RED(col);
102 0 : *pt++ = COLOR_GREEN(col);
103 0 : *pt++ = COLOR_BLUE(col);
104 : }
105 : } else {
106 0 : for ( pt = buffer, end = pt+3*w; pt<end; ++ppt) {
107 0 : *pt++ = COLOR_RED(*ppt);
108 0 : *pt++ = COLOR_GREEN(*ppt);
109 0 : *pt++ = COLOR_BLUE(*ppt);
110 : }
111 : }
112 0 : }
113 :
114 0 : static void setColorSpace(struct jpeg_compress_struct *cinfo, struct _GImage *base) {
115 : int i;
116 :
117 0 : cinfo->input_components = 3; /* # of color components per pixel */
118 0 : cinfo->in_color_space = JCS_RGB; /* colorspace of input image */
119 :
120 0 : if ( base->image_type==it_index ) {
121 0 : if ( base->clut->clut_len!=256 )
122 0 : return;
123 0 : for ( i=0; i<256; ++i )
124 0 : if ( base->clut->clut[i]!=COLOR_CREATE(i,i,i))
125 0 : break;
126 0 : if ( i==256 ) {
127 0 : cinfo->input_components = 1;
128 0 : cinfo->in_color_space = JCS_GRAYSCALE;
129 : }
130 : }
131 : }
132 :
133 : /* quality is a number between 0 and 100 */
134 0 : int GImageWrite_Jpeg(GImage *gi, FILE *outfile, int quality, int progressive) {
135 0 : struct _GImage *base = gi->list_len==0?gi->u.image:gi->u.images[0];
136 : struct jpeg_compress_struct cinfo;
137 : struct my_error_mgr jerr;
138 : JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
139 :
140 0 : cinfo.err = jpeg_std_error(&jerr.pub);
141 0 : jerr.pub.error_exit = my_error_exit;
142 0 : if (setjmp(jerr.setjmp_buffer)) {
143 0 : jpeg_destroy_compress(&cinfo);
144 0 : return 0;
145 : }
146 0 : jpeg_CreateCompress(&cinfo,JPEG_LIB_VERSION,(size_t) sizeof(struct jpeg_compress_struct));
147 0 : jpeg_stdio_dest(&cinfo, outfile);
148 :
149 0 : cinfo.image_width = base->width;
150 0 : cinfo.image_height = base->height;
151 0 : setColorSpace(&cinfo,base);
152 0 : jpeg_set_defaults(&cinfo);
153 0 : jpeg_set_quality(&cinfo, quality, TRUE );
154 0 : if ( progressive )
155 0 : jpeg_simple_progression(&cinfo);
156 0 : jpeg_start_compress(&cinfo, TRUE);
157 :
158 0 : if ( cinfo.in_color_space != JCS_GRAYSCALE )
159 0 : row_pointer[0] = (JSAMPROW) malloc(3*base->width);
160 0 : while (cinfo.next_scanline < cinfo.image_height) {
161 0 : if ( cinfo.in_color_space == JCS_GRAYSCALE )
162 0 : row_pointer[0] = (unsigned char *) (base->data + cinfo.next_scanline*base->bytes_per_line);
163 : else
164 0 : transferImageToBuffer(base,row_pointer[0],base->width,cinfo.next_scanline);
165 0 : (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
166 : }
167 0 : jpeg_finish_compress(&cinfo);
168 0 : jpeg_destroy_compress(&cinfo);
169 0 : if ( cinfo.in_color_space != JCS_GRAYSCALE )
170 0 : free(row_pointer[0]);
171 0 : return( 1 );
172 : }
173 :
174 0 : int GImageWriteJpeg(GImage *gi, char *filename, int quality, int progressive) {
175 : FILE * outfile; /* target file */
176 : int ret;
177 :
178 0 : if ((outfile = fopen(filename, "wb")) == NULL) {
179 0 : fprintf(stderr, "can't open %s\n", filename);
180 0 : return(0);
181 : }
182 0 : ret = GImageWrite_Jpeg(gi,outfile,quality,progressive);
183 0 : fclose(outfile);
184 0 : return( ret );
185 : }
186 :
187 : #endif
|