1 /****************************************************************************
2     jpeg.c - read and write jpeg images using libjpeg routines
3     Copyright (C) 2002 Hari Nair <hari@alumni.caltech.edu>
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 ****************************************************************************/
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include <jpeglib.h>
25 
26 #define MAX_DIMENSION 21600
27 
28 int
read_jpeg(const char * filename,int * width,int * height,unsigned char ** rgb)29 read_jpeg(const char *filename, int *width, int *height, unsigned char **rgb)
30 {
31     struct jpeg_decompress_struct cinfo;
32     struct jpeg_error_mgr jerr;
33     unsigned char *ptr = NULL;
34     unsigned int i, ipos;
35 
36     FILE *infile = fopen(filename, "rb");
37 
38     cinfo.err = jpeg_std_error(&jerr);
39     jpeg_create_decompress(&cinfo);
40     jpeg_stdio_src(&cinfo, infile);
41     jpeg_read_header(&cinfo, TRUE);
42     jpeg_start_decompress(&cinfo);
43 
44     *width = cinfo.output_width;
45     *height = cinfo.output_height;
46 
47     /* Prevent against integer overflow - thanks to Niels Heinen */
48     if (cinfo.output_width > MAX_DIMENSION
49         || cinfo.output_height > MAX_DIMENSION)
50     {
51        fprintf(stderr, "Width, height in JPEG header is %d, %d\n",
52                cinfo.output_width, cinfo.output_height);
53        return(0);
54     }
55 
56     rgb[0] = malloc(3 * cinfo.output_width * cinfo.output_height);
57     if (rgb[0] == NULL)
58     {
59         fprintf(stderr, "Can't allocate memory for JPEG file.\n");
60         fclose(infile);
61         return(0);
62     }
63 
64     if (cinfo.output_components == 3)
65     {
66         ptr = rgb[0];
67         while (cinfo.output_scanline < cinfo.output_height)
68         {
69             jpeg_read_scanlines(&cinfo, &ptr, 1);
70             ptr += 3 * cinfo.output_width;
71         }
72     }
73     else if (cinfo.output_components == 1)
74     {
75         ptr = malloc(cinfo.output_width);
76         if (ptr == NULL)
77         {
78             fprintf(stderr, "Can't allocate memory for JPEG file.\n");
79             fclose(infile);
80             return(0);
81         }
82 
83         ipos = 0;
84         while (cinfo.output_scanline < cinfo.output_height)
85         {
86             jpeg_read_scanlines(&cinfo, &ptr, 1);
87 
88             for (i = 0; i < cinfo.output_width; i++)
89             {
90                 memset(rgb[0] + ipos, ptr[i], 3);
91                 ipos += 3;
92             }
93         }
94 
95         free(ptr);
96     }
97 
98     jpeg_finish_decompress(&cinfo);
99     jpeg_destroy_decompress(&cinfo);
100 
101     fclose(infile);
102 
103     return(1);
104 }
105 
106 int
write_jpeg(FILE * outfile,int width,int height,unsigned char * rgb,int quality)107 write_jpeg(FILE *outfile, int width, int height, unsigned char *rgb,
108            int quality)
109 {
110     struct jpeg_compress_struct cinfo;
111     struct jpeg_error_mgr jerr;
112 
113     JSAMPROW scanline[1];
114 
115     cinfo.err = jpeg_std_error(&jerr);
116     jpeg_create_compress(&cinfo);
117     jpeg_stdio_dest(&cinfo, outfile);
118 
119     cinfo.image_width = width;
120     cinfo.image_height = height;
121     cinfo.input_components = 3;
122     cinfo.in_color_space = JCS_RGB;
123 
124     jpeg_set_defaults(&cinfo);
125 
126     jpeg_set_quality(&cinfo, quality, TRUE);
127 
128     jpeg_start_compress(&cinfo, TRUE);
129 
130     while (cinfo.next_scanline < (unsigned int) height)
131     {
132         scanline[0] = rgb + 3 * width * cinfo.next_scanline;
133         jpeg_write_scanlines(&cinfo, scanline, 1);
134     }
135 
136     jpeg_finish_compress(&cinfo);
137     jpeg_destroy_compress(&cinfo);
138 
139     return(1);
140 }
141