aboutsummaryrefslogtreecommitdiffstats
path: root/rd/read-jpeg.c
diff options
context:
space:
mode:
Diffstat (limited to 'rd/read-jpeg.c')
-rw-r--r--rd/read-jpeg.c187
1 files changed, 187 insertions, 0 deletions
diff --git a/rd/read-jpeg.c b/rd/read-jpeg.c
new file mode 100644
index 0000000..d12fb40
--- /dev/null
+++ b/rd/read-jpeg.c
@@ -0,0 +1,187 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <jpeglib.h>
+
+#include <libexif/exif-data.h>
+
+#include "readers.h"
+#include "misc.h"
+
+/* ---------------------------------------------------------------------- */
+/* load */
+
+struct jpeg_state {
+ FILE * infile; /* source file */
+
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ JSAMPARRAY buffer; /* Output row buffer */
+ int row_stride,linelength; /* physical row width in output buffer */
+ unsigned char *image,*ptr;
+
+ /* thumbnail */
+ unsigned char *thumbnail;
+ unsigned int tpos, tsize;
+};
+
+/* ---------------------------------------------------------------------- */
+/* data source manager for thumbnail images */
+
+static void thumbnail_src_init(struct jpeg_decompress_struct *cinfo)
+{
+ struct jpeg_state *h = container_of(cinfo, struct jpeg_state, cinfo);
+ cinfo->src->next_input_byte = h->thumbnail;
+ cinfo->src->bytes_in_buffer = h->tsize;
+}
+
+static int thumbnail_src_fill(struct jpeg_decompress_struct *cinfo)
+{
+ fprintf(stderr,"jpeg: panic: no more thumbnail input data\n");
+ exit(1);
+}
+
+static void thumbnail_src_skip(struct jpeg_decompress_struct *cinfo,
+ long num_bytes)
+{
+ cinfo->src->next_input_byte += num_bytes;
+}
+
+static void thumbnail_src_term(struct jpeg_decompress_struct *cinfo)
+{
+ /* nothing */
+}
+
+static struct jpeg_source_mgr thumbnail_mgr = {
+ .init_source = thumbnail_src_init,
+ .fill_input_buffer = thumbnail_src_fill,
+ .skip_input_data = thumbnail_src_skip,
+ .resync_to_restart = jpeg_resync_to_restart,
+ .term_source = thumbnail_src_term,
+};
+
+/* ---------------------------------------------------------------------- */
+/* jpeg loader */
+
+static void*
+jpeg_init(FILE *fp, char *filename, unsigned int page,
+ struct ida_image_info *i, int thumbnail)
+{
+ struct jpeg_state *h;
+ jpeg_saved_marker_ptr mark;
+
+ h = malloc(sizeof(*h));
+ memset(h,0,sizeof(*h));
+ h->infile = fp;
+
+ h->cinfo.err = jpeg_std_error(&h->jerr);
+ jpeg_create_decompress(&h->cinfo);
+ jpeg_save_markers(&h->cinfo, JPEG_COM, 0xffff); /* comment */
+ jpeg_save_markers(&h->cinfo, JPEG_APP0+1, 0xffff); /* EXIF */
+ jpeg_stdio_src(&h->cinfo, h->infile);
+ jpeg_read_header(&h->cinfo, TRUE);
+
+ for (mark = h->cinfo.marker_list; NULL != mark; mark = mark->next) {
+ switch (mark->marker) {
+ case JPEG_COM:
+ if (debug)
+ fprintf(stderr,"jpeg: comment found (COM marker) [%.*s]\n",
+ (int)mark->data_length, mark->data);
+ load_add_extra(i,EXTRA_COMMENT,mark->data,mark->data_length);
+ break;
+ case JPEG_APP0 +1:
+ if (debug)
+ fprintf(stderr,"jpeg: exif data found (APP1 marker)\n");
+ load_add_extra(i,EXTRA_COMMENT,mark->data,mark->data_length);
+
+ if (thumbnail) {
+ ExifData *ed;
+
+ ed = exif_data_new_from_data(mark->data,mark->data_length);
+ if (ed->data &&
+ ed->data[0] == 0xff &&
+ ed->data[1] == 0xd8) {
+ if (debug)
+ fprintf(stderr,"jpeg: exif thumbnail found\n");
+
+ /* save away thumbnail data */
+ h->thumbnail = malloc(ed->size);
+ h->tsize = ed->size;
+ memcpy(h->thumbnail,ed->data,ed->size);
+ }
+ exif_data_unref(ed);
+ }
+ break;
+ }
+ }
+
+ if (h->thumbnail) {
+ /* save image size */
+ i->thumbnail = 1;
+ i->real_width = h->cinfo.image_width;
+ i->real_height = h->cinfo.image_height;
+
+ /* re-setup jpeg */
+ jpeg_destroy_decompress(&h->cinfo);
+ fclose(h->infile);
+ h->infile = NULL;
+ jpeg_create_decompress(&h->cinfo);
+ h->cinfo.src = &thumbnail_mgr;
+ jpeg_read_header(&h->cinfo, TRUE);
+ }
+
+ h->cinfo.out_color_space = JCS_RGB;
+ jpeg_start_decompress(&h->cinfo);
+ i->width = h->cinfo.image_width;
+ i->height = h->cinfo.image_height;
+ i->npages = 1;
+ switch (h->cinfo.density_unit) {
+ case 0: /* unknown */
+ break;
+ case 1: /* dot per inch */
+ i->dpi = h->cinfo.X_density;
+ break;
+ case 2: /* dot per cm */
+ i->dpi = res_cm_to_inch(h->cinfo.X_density);
+ break;
+ }
+
+ return h;
+}
+
+static void
+jpeg_read(unsigned char *dst, unsigned int line, void *data)
+{
+ struct jpeg_state *h = data;
+ JSAMPROW row = dst;
+ jpeg_read_scanlines(&h->cinfo, &row, 1);
+}
+
+static void
+jpeg_done(void *data)
+{
+ struct jpeg_state *h = data;
+ jpeg_destroy_decompress(&h->cinfo);
+ if (h->infile)
+ fclose(h->infile);
+ if (h->thumbnail)
+ free(h->thumbnail);
+ free(h);
+}
+
+struct ida_loader jpeg_loader = {
+ magic: "\xff\xd8",
+ moff: 0,
+ mlen: 2,
+ name: "libjpeg",
+ init: jpeg_init,
+ read: jpeg_read,
+ done: jpeg_done,
+};
+
+static void __init init_rd(void)
+{
+ load_register(&jpeg_loader);
+}