X-Git-Url: https://git.sesse.net/?p=qscale;a=blobdiff_plain;f=libqscale.c;fp=libqscale.c;h=b744a9b5f3b98e1a1da8182e15f9eaefc991f694;hp=0000000000000000000000000000000000000000;hb=cce321fe623a347fd2bda4e442bed42dfc9299c7;hpb=9d3e18175a68b3ffe71bb1a68c7fba0f9624d5f1 diff --git a/libqscale.c b/libqscale.c new file mode 100644 index 0000000..b744a9b --- /dev/null +++ b/libqscale.c @@ -0,0 +1,100 @@ +#include +#include +#include + +#include "libqscale.h" + +qscale_img *qscale_load_jpeg(const char *filename) +{ + FILE *file = fopen(filename, "rb"); + qscale_img *img; + if (file == NULL) { + return NULL; + } + + img = qscale_load_jpeg_from_stdio(file); + + fclose(file); + return img; +} + +qscale_img *qscale_load_jpeg_from_stdio(FILE *file) +{ + qscale_img *img = (qscale_img *)malloc(sizeof(qscale_img)); + if (img == NULL) { + return NULL; + } + + img->data_y = img->data_cb = img->data_cr = NULL; + + /* FIXME: Better error handling here (ie., return NULL). */ + struct jpeg_decompress_struct dinfo; + struct jpeg_error_mgr jerr; + dinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&dinfo); + jpeg_stdio_src(&dinfo, stdin); + jpeg_read_header(&dinfo, TRUE); + dinfo.raw_data_out = TRUE; + jpeg_start_decompress(&dinfo); + + /* We do not handle anything but YCbCr images (yet?). */ + if (dinfo.num_components != 3) { + qscale_destroy(img); + return NULL; + } + + img->width = dinfo.image_width; + img->height = dinfo.image_height; + + img->w0 = dinfo.image_width * dinfo.comp_info[0].h_samp_factor / dinfo.max_h_samp_factor; + img->h0 = dinfo.image_height * dinfo.comp_info[0].v_samp_factor / dinfo.max_v_samp_factor; + + img->w1 = dinfo.image_width * dinfo.comp_info[1].h_samp_factor / dinfo.max_h_samp_factor; + img->h1 = dinfo.image_height * dinfo.comp_info[1].v_samp_factor / dinfo.max_v_samp_factor; + + img->w2 = dinfo.image_width * dinfo.comp_info[2].h_samp_factor / dinfo.max_h_samp_factor; + img->h2 = dinfo.image_height * dinfo.comp_info[2].v_samp_factor / dinfo.max_v_samp_factor; + + img->data_y = (JSAMPLE*)memalign(16, dinfo.comp_info[0].height_in_blocks * dinfo.comp_info[0].width_in_blocks * DCTSIZE * DCTSIZE); + img->data_cb = (JSAMPLE*)memalign(16, dinfo.comp_info[1].height_in_blocks * dinfo.comp_info[1].width_in_blocks * DCTSIZE * DCTSIZE); + img->data_cr = (JSAMPLE*)memalign(16, dinfo.comp_info[2].height_in_blocks * dinfo.comp_info[2].width_in_blocks * DCTSIZE * DCTSIZE); + + if (img->data_y == NULL || img->data_cb == NULL || img->data_cr == NULL) { + qscale_destroy(img); + return NULL; + } + + int total_lines = 0, blocks = 0; + while (total_lines < dinfo.comp_info[0].height_in_blocks * DCTSIZE) { + unsigned max_lines = dinfo.max_v_samp_factor * DCTSIZE; + + JSAMPROW y_row_ptrs[max_lines]; + JSAMPROW cb_row_ptrs[max_lines]; + JSAMPROW cr_row_ptrs[max_lines]; + JSAMPROW* ptrs[] = { y_row_ptrs, cb_row_ptrs, cr_row_ptrs }; + + int i; + for (i = 0; i < max_lines; ++i) { + 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; + 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; + 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; + } + + total_lines += max_lines; + ++blocks; + + if (jpeg_read_raw_data(&dinfo, ptrs, max_lines) == 0) + break; + } + + jpeg_destroy_decompress(&dinfo); + return img; +} + +void qscale_destroy(qscale_img *img) +{ + free(img->data_y); + free(img->data_cb); + free(img->data_cr); + free(img); +}