Fix jpeg loader for grayscale images.
[gfxprim.git] / libs / loaders / GP_JPG.c
blob5958dab15a3d1b5604751389de42dff9f6d17242
1 /*****************************************************************************
2 * This file is part of gfxprim library. *
3 * *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
8 * *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
18 * *
19 * Copyright (C) 2009-2011 Cyril Hrubis <metan@ucw.cz> *
20 * *
21 *****************************************************************************/
25 JPG image support using jpeg library.
29 #include <stdint.h>
30 #include <inttypes.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <stdio.h>
35 #include <setjmp.h>
37 #include <jpeglib.h>
39 #include <GP_Context.h>
40 #include <GP_Debug.h>
42 GP_RetCode GP_OpenJPG(const char *src_path, FILE **f)
44 *f = fopen(src_path, "rb");
46 if (*f == NULL) {
47 GP_DEBUG(1, "Failed to open '%s' : %s",
48 src_path, strerror(errno));
49 return GP_EBADFILE;
52 //TODO: check signature and rewind the stream
54 return GP_ESUCCESS;
57 struct my_jpg_err {
58 struct jpeg_error_mgr error_mgr;
60 jmp_buf setjmp_buf;
63 static void my_error_exit(j_common_ptr cinfo)
65 struct my_jpg_err *my_err = (struct my_jpg_err*) cinfo->err;
67 GP_DEBUG(1, "ERROR reading jpeg file");
69 longjmp(my_err->setjmp_buf, 1);
72 static const char *get_colorspace(J_COLOR_SPACE color_space)
74 switch (color_space) {
75 case JCS_GRAYSCALE:
76 return "Grayscale";
77 case JCS_RGB:
78 return "RGB";
79 case JCS_YCbCr:
80 return "YCbCr";
81 case JCS_CMYK:
82 return "CMYK";
83 case JCS_YCCK:
84 return "YCCK";
85 default:
86 return "Unknown";
90 GP_RetCode GP_ReadJPG(FILE *f, GP_Context **res)
92 struct jpeg_decompress_struct cinfo;
93 struct my_jpg_err my_err;
94 GP_Context *ret = NULL;
96 cinfo.err = jpeg_std_error(&my_err.error_mgr);
97 my_err.error_mgr.error_exit = my_error_exit;
99 if (setjmp(my_err.setjmp_buf)) {
100 jpeg_destroy_decompress(&cinfo);
101 GP_ContextFree(ret);
102 fclose(f);
103 return GP_EBADFILE;
106 jpeg_create_decompress(&cinfo);
107 jpeg_stdio_src(&cinfo, f);
109 jpeg_read_header(&cinfo, TRUE);
111 GP_DEBUG(1, "Have %s JPEG size %ux%u %i channels",
112 get_colorspace(cinfo.jpeg_color_space),
113 cinfo.image_width, cinfo.image_height,
114 cinfo.num_components);
116 GP_Pixel pixel_type;
118 switch (cinfo.out_color_space) {
119 case JCS_GRAYSCALE:
120 pixel_type = GP_PIXEL_G8;
121 break;
122 case JCS_RGB:
123 pixel_type = GP_PIXEL_RGB888;
124 break;
125 default:
126 pixel_type = GP_PIXEL_UNKNOWN;
129 if (pixel_type == GP_PIXEL_UNKNOWN) {
130 GP_DEBUG(1, "Can't handle %s JPEG output format",
131 get_colorspace(cinfo.out_color_space));
132 jpeg_destroy_decompress(&cinfo);
133 fclose(f);
134 return GP_EBADFILE;
137 ret = GP_ContextAlloc(cinfo.image_width, cinfo.image_height,
138 pixel_type);
140 if (ret == NULL) {
141 GP_DEBUG(1, "Malloc failed :(");
142 jpeg_destroy_decompress(&cinfo);
143 fclose(f);
144 return GP_ENOMEM;
147 jpeg_start_decompress(&cinfo);
149 while (cinfo.output_scanline < cinfo.output_height) {
150 uint32_t y = cinfo.output_scanline;
152 JSAMPROW addr = (void*)GP_PIXEL_ADDR(ret, 0, y);
153 jpeg_read_scanlines(&cinfo, &addr, 1);
155 if (pixel_type != GP_PIXEL_RGB888)
156 continue;
158 //TODO: fixme bigendian?
159 /* fix the pixel, as we want in fact BGR */
160 uint32_t i;
162 for (i = 0; i < ret->w; i++) {
163 uint8_t *pix = GP_PIXEL_ADDR(ret, i, y);
164 GP_SWAP(pix[0], pix[2]);
168 jpeg_finish_decompress(&cinfo);
169 jpeg_destroy_decompress(&cinfo);
170 fclose(f);
171 *res = ret;
173 return GP_ESUCCESS;
176 GP_RetCode GP_LoadJPG(const char *src_path, GP_Context **res)
178 FILE *f;
179 GP_RetCode ret;
181 if ((ret = GP_OpenJPG(src_path, &f)))
182 return ret;
184 return GP_ReadJPG(f, res);