changeset 1904:fec3a31bc978

load mpo files as SBS
author Vladimir Nadvornik <nadvornik@suse.cz>
date Sun, 27 Mar 2011 11:58:29 +0200
parents 16b0afb2347c
children 25f23890dabe
files src/image_load_jpeg.c
diffstat 1 files changed, 101 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/src/image_load_jpeg.c	Sun Mar 27 10:57:08 2011 +0200
+++ b/src/image_load_jpeg.c	Sun Mar 27 11:58:29 2011 +0200
@@ -148,19 +148,54 @@
   /* do nothing */
 }
 
+
+void image_loader_jpeg_read_scanline(struct jpeg_decompress_struct *cinfo, guchar **dptr, guint rowstride)
+{
+	guchar *lines[4];
+	guchar **lptr;
+	gint i;
+
+	lptr = lines;
+	for (i = 0; i < cinfo->rec_outbuf_height; i++) 
+		{
+		*lptr++ = *dptr;
+		*dptr += rowstride;
+		}
+
+	jpeg_read_scanlines (cinfo, lines, cinfo->rec_outbuf_height);
+
+	switch (cinfo->out_color_space) 
+		{
+		    case JCS_GRAYSCALE:
+		      explode_gray_into_buf (cinfo, lines);
+		      break;
+		    case JCS_RGB:
+		      /* do nothing */
+		      break;
+		    case JCS_CMYK:
+		      convert_cmyk_to_rgb (cinfo, lines);
+		      break;
+		    default:
+		      break;
+		}
+}
+
 static gboolean image_loader_jpeg_load (gpointer loader, const guchar *buf, gsize count, GError **error)
 {
 	ImageLoaderJpeg *lj = (ImageLoaderJpeg *) loader;
 	struct jpeg_decompress_struct cinfo;
-	guchar *dptr;
+	struct jpeg_decompress_struct cinfo2;
+	guchar *dptr, *dptr2;
 	guint rowstride;
 
 	struct error_handler_data jerr;
 //	stdio_src_ptr src;
 	MPOData *mpo = jpeg_get_mpo_data(buf, count);
+	gboolean stereo = (mpo && mpo->num_images > 1);
 
 	/* setup error handler */
 	cinfo.err = jpeg_std_error (&jerr.pub);
+	if (stereo) cinfo2.err = jpeg_std_error (&jerr.pub);
 	jerr.pub.error_exit = fatal_error_handler;
         jerr.pub.output_message = output_message_handler;
 
@@ -173,6 +208,7 @@
 		 * We need to clean up the JPEG object, close the input file, and return.
 		*/
 		jpeg_destroy_decompress(&cinfo);
+		if (stereo) jpeg_destroy_decompress(&cinfo2);
 		return FALSE;
 		}
 	
@@ -182,72 +218,102 @@
 
 
 	jpeg_read_header(&cinfo, TRUE);
+	
+	if (stereo)
+		{
+		printf("decoding stereo");
+		jpeg_create_decompress(&cinfo2);
+		jpeg_mem_src(&cinfo2, (unsigned char *)buf + mpo->images[1].offset, mpo->images[1].length);
+		jpeg_read_header(&cinfo2, TRUE);
+		
+		if (cinfo.image_width != cinfo2.image_width ||
+		    cinfo.image_height != cinfo2.image_height) 
+			{
+			DEBUG_1("stereo data with different size");
+			jpeg_destroy_decompress(&cinfo2);
+			stereo = FALSE;
+			}
+		}
 
-	lj->requested_width = cinfo.image_width;
+		    
+
+	lj->requested_width = stereo ? cinfo.image_width * 2: cinfo.image_width;
 	lj->requested_height = cinfo.image_height;
-	lj->size_cb(loader, cinfo.image_width, cinfo.image_height, lj->data);
+	lj->size_cb(loader, lj->requested_width, lj->requested_height, lj->data);
 			
 	cinfo.scale_num = 1;
 	for (cinfo.scale_denom = 2; cinfo.scale_denom <= 8; cinfo.scale_denom *= 2) {
 		jpeg_calc_output_dimensions(&cinfo);
-		if (cinfo.output_width < lj->requested_width || cinfo.output_height < lj->requested_height) {
+		if (cinfo.output_width < (stereo ? lj->requested_width / 2 : lj->requested_width) || cinfo.output_height < lj->requested_height) {
 			cinfo.scale_denom /= 2;
 			break;
 		}
 	}
 	jpeg_calc_output_dimensions(&cinfo);
+	if (stereo)
+		{
+		cinfo2.scale_num = cinfo.scale_num;
+		cinfo2.scale_denom = cinfo.scale_denom;
+		jpeg_calc_output_dimensions(&cinfo2);
+		jpeg_start_decompress(&cinfo2);
+		}
+		
 
 	jpeg_start_decompress(&cinfo);
 	
+
+	if (stereo)
+		{
+		if (cinfo.output_width != cinfo2.output_width ||
+		    cinfo.output_height != cinfo2.output_height ||
+		    cinfo.out_color_components != cinfo2.out_color_components) 
+			{
+			DEBUG_1("stereo data with different output size");
+			jpeg_destroy_decompress(&cinfo2);
+			stereo = FALSE;
+			}
+		}
+	
+	
 	lj->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 
 				     cinfo.out_color_components == 4 ? TRUE : FALSE, 
-				     8, cinfo.output_width, cinfo.output_height);
+				     8, stereo ? cinfo.output_width * 2: cinfo.output_width, cinfo.output_height);
 
-	lj->area_prepared_cb(loader, lj->data);
-	rowstride = gdk_pixbuf_get_rowstride(lj->pixbuf);
-	dptr = gdk_pixbuf_get_pixels(lj->pixbuf);
-	      
 	if (!lj->pixbuf) 
 		{
 		jpeg_destroy_decompress (&cinfo);
+		if (stereo) jpeg_destroy_decompress (&cinfo2);
 		return 0;
 		}
+	if (stereo) g_object_set_data(G_OBJECT(lj->pixbuf), "stereo_data", GINT_TO_POINTER(STEREO_PIXBUF_CROSS));
+	lj->area_prepared_cb(loader, lj->data);
+
+	rowstride = gdk_pixbuf_get_rowstride(lj->pixbuf);
+	dptr = gdk_pixbuf_get_pixels(lj->pixbuf);
+	dptr2 = gdk_pixbuf_get_pixels(lj->pixbuf) + ((cinfo.out_color_components == 4) ? 4 * cinfo.output_width : 3 * cinfo.output_width);
+	
 
 	while (cinfo.output_scanline < cinfo.output_height && !lj->abort) 
 		{
-		guchar *lines[4];
-		guchar **lptr;
-		gint i;
 		guint scanline = cinfo.output_scanline;
-
-		lptr = lines;
-		for (i = 0; i < cinfo.rec_outbuf_height; i++) 
+		image_loader_jpeg_read_scanline(&cinfo, &dptr, rowstride);
+		lj->area_updated_cb(loader, 0, scanline, cinfo.output_width, cinfo.rec_outbuf_height, lj->data);
+		if (stereo)
 			{
-			*lptr++ = dptr;
-			dptr += rowstride;
+			guint scanline = cinfo2.output_scanline;
+			image_loader_jpeg_read_scanline(&cinfo2, &dptr2, rowstride);
+			lj->area_updated_cb(loader, cinfo.output_width, scanline, cinfo2.output_width, cinfo2.rec_outbuf_height, lj->data);
 			}
-
-		jpeg_read_scanlines (&cinfo, lines, cinfo.rec_outbuf_height);
-
-		switch (cinfo.out_color_space) 
-			{
-			    case JCS_GRAYSCALE:
-			      explode_gray_into_buf (&cinfo, lines);
-			      break;
-			    case JCS_RGB:
-			      /* do nothing */
-			      break;
-			    case JCS_CMYK:
-			      convert_cmyk_to_rgb (&cinfo, lines);
-			      break;
-			    default:
-			      break;
-			}
-		lj->area_updated_cb(loader, 0, scanline, cinfo.output_width, cinfo.rec_outbuf_height, lj->data);
 		}
 
 	jpeg_finish_decompress(&cinfo);
 	jpeg_destroy_decompress(&cinfo);
+	if (stereo)
+		{
+		jpeg_finish_decompress(&cinfo);
+		jpeg_destroy_decompress(&cinfo);
+		}
+
 	return TRUE;
 }