]> git.sesse.net Git - qscale/blob - libqscale.c
Move JPEG loading into libqscale.
[qscale] / libqscale.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <malloc.h>
4
5 #include "libqscale.h"
6
7 qscale_img *qscale_load_jpeg(const char *filename)
8 {
9         FILE *file = fopen(filename, "rb");
10         qscale_img *img;
11         if (file == NULL) {
12                 return NULL;
13         }
14
15         img = qscale_load_jpeg_from_stdio(file);
16
17         fclose(file);
18         return img;
19 }
20
21 qscale_img *qscale_load_jpeg_from_stdio(FILE *file)
22 {
23         qscale_img *img = (qscale_img *)malloc(sizeof(qscale_img));
24         if (img == NULL) {
25                 return NULL;
26         }
27
28         img->data_y = img->data_cb = img->data_cr = NULL;
29
30         /* FIXME: Better error handling here (ie., return NULL). */
31         struct jpeg_decompress_struct dinfo;
32         struct jpeg_error_mgr jerr;
33         dinfo.err = jpeg_std_error(&jerr);
34         jpeg_create_decompress(&dinfo);
35         jpeg_stdio_src(&dinfo, stdin);
36         jpeg_read_header(&dinfo, TRUE);
37         dinfo.raw_data_out = TRUE;
38         jpeg_start_decompress(&dinfo);
39         
40         /* We do not handle anything but YCbCr images (yet?). */
41         if (dinfo.num_components != 3) {
42                 qscale_destroy(img);
43                 return NULL;
44         }
45
46         img->width = dinfo.image_width;
47         img->height = dinfo.image_height;
48
49         img->w0 = dinfo.image_width * dinfo.comp_info[0].h_samp_factor / dinfo.max_h_samp_factor;
50         img->h0 = dinfo.image_height * dinfo.comp_info[0].v_samp_factor / dinfo.max_v_samp_factor;
51
52         img->w1 = dinfo.image_width * dinfo.comp_info[1].h_samp_factor / dinfo.max_h_samp_factor;
53         img->h1 = dinfo.image_height * dinfo.comp_info[1].v_samp_factor / dinfo.max_v_samp_factor;
54
55         img->w2 = dinfo.image_width * dinfo.comp_info[2].h_samp_factor / dinfo.max_h_samp_factor;
56         img->h2 = dinfo.image_height * dinfo.comp_info[2].v_samp_factor / dinfo.max_v_samp_factor;
57
58         img->data_y  = (JSAMPLE*)memalign(16, dinfo.comp_info[0].height_in_blocks * dinfo.comp_info[0].width_in_blocks * DCTSIZE * DCTSIZE);
59         img->data_cb = (JSAMPLE*)memalign(16, dinfo.comp_info[1].height_in_blocks * dinfo.comp_info[1].width_in_blocks * DCTSIZE * DCTSIZE);
60         img->data_cr = (JSAMPLE*)memalign(16, dinfo.comp_info[2].height_in_blocks * dinfo.comp_info[2].width_in_blocks * DCTSIZE * DCTSIZE);
61
62         if (img->data_y == NULL || img->data_cb == NULL || img->data_cr == NULL) {
63                 qscale_destroy(img);
64                 return NULL;
65         }
66
67         int total_lines = 0, blocks = 0;
68         while (total_lines < dinfo.comp_info[0].height_in_blocks * DCTSIZE) {
69                 unsigned max_lines = dinfo.max_v_samp_factor * DCTSIZE;
70
71                 JSAMPROW y_row_ptrs[max_lines];
72                 JSAMPROW cb_row_ptrs[max_lines];
73                 JSAMPROW cr_row_ptrs[max_lines];
74                 JSAMPROW* ptrs[] = { y_row_ptrs, cb_row_ptrs, cr_row_ptrs };
75
76                 int i;
77                 for (i = 0; i < max_lines; ++i) {
78                         y_row_ptrs[i]  = img->data_y  + (i+blocks*DCTSIZE*dinfo.comp_info[0].v_samp_factor) * dinfo.comp_info[0].width_in_blocks * DCTSIZE;
79                         cb_row_ptrs[i] = img->data_cb + (i+blocks*DCTSIZE*dinfo.comp_info[1].v_samp_factor) * dinfo.comp_info[1].width_in_blocks * DCTSIZE;
80                         cr_row_ptrs[i] = img->data_cr + (i+blocks*DCTSIZE*dinfo.comp_info[2].v_samp_factor) * dinfo.comp_info[2].width_in_blocks * DCTSIZE;
81                 }
82
83                 total_lines += max_lines;
84                 ++blocks;
85
86                 if (jpeg_read_raw_data(&dinfo, ptrs, max_lines) == 0)
87                         break;
88         }
89
90         jpeg_destroy_decompress(&dinfo);
91         return img;
92 }
93
94 void qscale_destroy(qscale_img *img)
95 {
96         free(img->data_y);
97         free(img->data_cb);
98         free(img->data_cr);
99         free(img);
100 }