fix bug in jpeg saver.
[profile/ivi/evas.git] / src / modules / savers / jpeg / evas_image_save_jpeg.c
1 #include "evas_common.h"
2 #include "evas_private.h"
3
4 #include <stdio.h>
5 #include <jpeglib.h>
6 #include <setjmp.h>
7
8 static int evas_image_save_file_jpeg(RGBA_Image *im, const char *file, const char *key, int quality, int compress);
9
10 static Evas_Image_Save_Func evas_image_save_jpeg_func =
11 {
12    evas_image_save_file_jpeg
13 };
14
15 struct _JPEG_error_mgr
16 {
17    struct     jpeg_error_mgr pub;
18    jmp_buf    setjmp_buffer;
19 };
20 typedef struct _JPEG_error_mgr *emptr;
21
22 static void _JPEGFatalErrorHandler(j_common_ptr cinfo);
23 static void
24 _JPEGFatalErrorHandler(j_common_ptr cinfo)
25 {
26    emptr errmgr;
27
28    errmgr = (emptr) cinfo->err;
29    longjmp(errmgr->setjmp_buffer, 1);
30    return;
31 }
32
33 static void
34 _JPEGErrorHandler(j_common_ptr cinfo __UNUSED__)
35 {
36 /*    emptr errmgr; */
37
38 /*    errmgr = (emptr) cinfo->err; */
39    return;
40 }
41
42 static void
43 _JPEGErrorHandler2(j_common_ptr cinfo __UNUSED__, int msg_level __UNUSED__)
44 {
45 /*    emptr errmgr; */
46
47 /*    errmgr = (emptr) cinfo->err; */
48    return;
49 }
50
51 static int
52 save_image_jpeg(RGBA_Image *im, const char *file, int quality)
53 {
54    struct jpeg_compress_struct cinfo;
55    struct _JPEG_error_mgr jerr;
56    FILE               *f;
57    DATA8              *buf;
58    DATA32             *ptr;
59    JSAMPROW           *jbuf;
60    int                 y = 0;
61
62    if (!im || !im->image.data || !file)
63       return 0;
64
65    buf = alloca(im->cache_entry.w * 3 * sizeof(DATA8));
66    f = fopen(file, "wb");
67    if (!f)
68      {
69         return 0;
70      }
71    memset(&cinfo, 0, sizeof(cinfo));
72    cinfo.err = jpeg_std_error(&(jerr.pub));
73    jerr.pub.error_exit = _JPEGFatalErrorHandler;
74    jerr.pub.emit_message = _JPEGErrorHandler2;
75    jerr.pub.output_message = _JPEGErrorHandler;
76    if (sigsetjmp(jerr.setjmp_buffer, 1))
77      {
78         jpeg_destroy_compress(&cinfo);
79         fclose(f);
80         return 0;
81      }
82    jpeg_create_compress(&cinfo);
83    jpeg_stdio_dest(&cinfo, f);
84    cinfo.image_width = im->cache_entry.w;
85    cinfo.image_height = im->cache_entry.h;
86    cinfo.input_components = 3;
87    cinfo.in_color_space = JCS_RGB;
88    cinfo.optimize_coding = FALSE;
89    cinfo.dct_method = JDCT_ISLOW; // JDCT_FLOAT JDCT_IFAST(quality loss)
90    if (quality < 60) cinfo.dct_method = JDCT_IFAST;
91    jpeg_set_defaults(&cinfo);
92    jpeg_set_quality(&cinfo, quality, TRUE);
93    if (quality >= 90)
94      {
95         cinfo.comp_info[0].h_samp_factor = 1;
96         cinfo.comp_info[0].v_samp_factor = 1;
97         cinfo.comp_info[1].h_samp_factor = 1;
98         cinfo.comp_info[1].v_samp_factor = 1;
99         cinfo.comp_info[2].h_samp_factor = 1;
100         cinfo.comp_info[2].v_samp_factor = 1;
101      }
102    jpeg_start_compress(&cinfo, TRUE);
103    ptr = im->image.data;
104    while (cinfo.next_scanline < cinfo.image_height)
105      {
106         unsigned int i, j;
107         for (j = 0, i = 0; i < im->cache_entry.w; i++)
108           {
109              buf[j++] = ((*ptr) >> 16) & 0xff;
110              buf[j++] = ((*ptr) >> 8) & 0xff;
111              buf[j++] = ((*ptr)) & 0xff;
112              ptr++;
113           }
114         jbuf = (JSAMPROW *) (&buf);
115         jpeg_write_scanlines(&cinfo, jbuf, 1);
116         y++;
117      }
118    jpeg_finish_compress(&cinfo);
119    jpeg_destroy_compress(&cinfo);
120    fclose(f);
121    return 1;
122 }
123
124 static int evas_image_save_file_jpeg(RGBA_Image *im, const char *file, const char *key __UNUSED__, int quality, int compress __UNUSED__)
125 {
126    return save_image_jpeg(im, file, quality);
127 }
128
129 static int
130 module_open(Evas_Module *em)
131 {
132    if (!em) return 0;
133    em->functions = (void *)(&evas_image_save_jpeg_func);
134    return 1;
135 }
136
137 static void
138 module_close(Evas_Module *em __UNUSED__)
139 {
140 }
141
142 static Evas_Module_Api evas_modapi =
143 {
144    EVAS_MODULE_API_VERSION,
145    "jpeg",
146    "none",
147    {
148      module_open,
149      module_close
150    }
151 };
152
153 EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_SAVER, image_saver, jpeg);
154
155 #ifndef EVAS_STATIC_BUILD_JPEG
156 EVAS_EINA_MODULE_DEFINE(image_saver, jpeg);
157 #endif