[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    extragear/graphics/gwenview
From:       Aurélien Gâteau <aurelien.gateau () free ! fr>
Date:       2006-11-01 22:32:22
Message-ID: 1162420342.943355.21279.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 601062 by gateau:

Use Exiv2 instead of libexif to handle JPEG info. Avoid crashes with some JPEG
images.
BUG: 136112


 M  +1 -0      NEWS  
 M  +19 -7     configure.in.in  
 M  +1 -1      gvcore/Makefile.am  
 M  +5 -5      imageutils/Makefile.am  
 D             imageutils/jpeg-data.c  
 D             imageutils/jpeg-data.h  
 D             imageutils/jpeg-marker.c  
 D             imageutils/jpeg-marker.h  
 M  +47 -118   imageutils/jpegcontent.cpp  
 M  +1 -1      imageutils/jpegcontent.h  


--- trunk/extragear/graphics/gwenview/NEWS #601061:601062
@@ -10,6 +10,7 @@
    shown in the title bar and it was causing the mainwindow to be enlarged if
    the name was very long (Bug 127004)
  - Show the "rotate left" button in KParts.
+ - Use Exiv2 instead of libexif to fix troubles with some JPEG (Bug 136112).
 
 2006.09.16 - v1.4.0
 - Fixes:
--- trunk/extragear/graphics/gwenview/configure.in.in #601061:601062
@@ -94,7 +94,9 @@
 GV_ASM_DEFS="$gv_asm_defs"
 AC_SUBST(GV_ASM_DEFS)
 
+#
 # libmng check (for gvmngformattype.*)
+#
 LIBMNG=
 KDE_CHECK_HEADER(libmng.h,
     [
@@ -109,14 +111,10 @@
     AC_WARN([Can't find libmng.h, Gwenview won't be compiled with MNG support])
 fi
 
-PKG_CHECK_MODULES(LIBEXIF, libexif >= 0.5.12, ,
-        AC_MSG_WARN([libexif >= 0.5.12 not found. Please install it.]) 
-	DO_NOT_COMPILE="gwenview $DO_NOT_COMPILE"
-		)
 
-AC_SUBST(LIBEXIF_LIBS)
-AC_SUBST(LIBEXIF_CFLAGS)
-
+#
+# libxcursor
+#
 KDE_CHECK_HEADERS(X11/Xcursor/Xcursor.h,
     [KDE_CHECK_LIB(Xcursor, XcursorXcFileLoadImages, [
 	GV_LIB_XCURSOR=-lXcursor
@@ -127,3 +125,17 @@
 if test -z "$GV_LIB_XCURSOR"; then
     AC_WARN([Can't find Xcursor.h, Gwenview won't be compiled with X cursor \
support])  fi
+
+
+#
+# libexiv2
+#
+KDE_CHECK_HEADERS(exiv2/image.hpp, have_exiv2=yes, have_exiv2=no)
+
+if test "$have_exiv2" = "yes"; then
+	LIB_EXIV2="-lexiv2"
+	AC_SUBST(LIB_EXIV2)
+else
+	AC_MSG_WARN([You are missing libexiv2, which is required to compile Gwenview])
+	DO_NOT_COMPILE="$DO_NOT_COMPILE gwenview"
+fi
--- trunk/extragear/graphics/gwenview/gvcore/Makefile.am #601061:601062
@@ -7,7 +7,7 @@
 libgwenviewcore_la_LIBADD   = \
 	$(LIB_KFILE) $(LIB_KDEUI) $(LIB_KDECORE) $(LIB_KDEPRINT) $(LIB_QT) \
 	$(LIBJPEG) $(LIBPNG) $(LIBMNG) $(GV_LIB_XCURSOR) \
-	$(LIBEXIF_LIBS) -lkmediaplayer ../imageutils/libgvimageutils.la \
+	-lkmediaplayer ../imageutils/libgvimageutils.la \
 	../tsthread/libtsthread.la
 
 libgwenviewcore_la_METASOURCES = AUTO
--- trunk/extragear/graphics/gwenview/imageutils/Makefile.am #601061:601062
@@ -4,6 +4,8 @@
 	-DQT_CLEAN_NAMESPACE
 AM_CCASFLAGS = -I$(srcdir) $(GV_ASM_DEFS)
 
+CXXFLAGS = -fexceptions
+
 noinst_LTLIBRARIES = libgvimageutils.la
 
 libgvimageutils_la_SOURCES = \
@@ -12,10 +14,10 @@
 	scale.cpp \
 	transupp.c \
 	asm_scale.S \
-	jpeg-data.c \
-	jpeg-marker.c \
 	croppedqimage.cpp
 
+libgvimageutils_la_LIBADD = $(LIB_KDECORE) $(LIBQT) $(LIBJPEG) $(LIB_EXIV2)
+
 noinst_HEADERS = \
 	orientation.h \
 	imageutils.h \
@@ -30,7 +32,5 @@
 
 check_PROGRAMS = testjpegcontent
 testjpegcontent_SOURCES = testjpegcontent.cpp
-testjpegcontent_LDADD = \
-	$(LIB_KFILE) $(LIB_KDEUI) $(LIB_KDECORE) $(LIB_KDEPRINT) $(LIB_QT) \
-	$(LIBJPEG) $(LIBEXIF_LIBS) libgvimageutils.la
+testjpegcontent_LDADD = $(LIB_KFILE) libgvimageutils.la
 testjpegcontent_LDFLAGS = $(all_libraries) 
--- trunk/extragear/graphics/gwenview/imageutils/jpegcontent.cpp #601061:601062
@@ -38,15 +38,13 @@
 // KDE
 #include <kdebug.h>
 
-// Exif
-#include "exif-data.h"
-#include "exif-ifd.h"
-#include "exif-utils.h"
+// Exiv2
+#include <exiv2/exif.hpp>
+#include <exiv2/image.hpp>
 
 // Local
 #include "imageutils/imageutils.h"
 #include "imageutils/jpegcontent.h"
-#include "imageutils/jpeg-data.h"
 #include "imageutils/jpegerrormanager.h"
 
 namespace ImageUtils {
@@ -145,16 +143,12 @@
 	QByteArray mRawData;
 	QSize mSize;
 	QString mComment;
-	bool mPendingChanges;
+	bool mPendingTransformation;
 	QWMatrix mTransformMatrix;
-	ExifData* mExifData;
-	ExifEntry* mOrientationEntry;
-	ExifByteOrder mByteOrder;
+	Exiv2::ExifData mExifData;
 
 	Private() {
-		mPendingChanges = false;
-		mExifData=0;
-		mOrientationEntry=0;
+		mPendingTransformation = false;
 	}
 
 	void setupInmemSource(j_decompress_ptr cinfo) {
@@ -187,7 +181,7 @@
 
 		dest->mOutput=outputData;
 	}
-	bool readJPEGInfo() {
+	bool readSize() {
 		struct jpeg_decompress_struct srcinfo;
 		jpeg_saved_marker_ptr mark;
 		
@@ -215,15 +209,6 @@
 		}
 		mSize=QSize(srcinfo.image_width, srcinfo.image_height);
 		
-		// Read the comment, if any
-		mComment=QString::null;
-		for (mark = srcinfo.marker_list; mark; mark = mark->next) {
-			if (mark->marker == JPEG_COM) {
-				mComment=QString::fromUtf8((const char*)(mark->data), mark->data_length);
-				break;
-			}
-		}
-		
 		jpeg_destroy_decompress(&srcinfo);
 		return true;
 	}
@@ -241,9 +226,6 @@
 
 
 JPEGContent::~JPEGContent() {
-	if (d->mExifData) {
-		exif_data_unref(d->mExifData);
-	}
 	delete d;
 }
 
@@ -259,12 +241,8 @@
 
 
 bool JPEGContent::loadFromData(const QByteArray& data) {
-	d->mPendingChanges = false;
+	d->mPendingTransformation = false;
 	d->mTransformMatrix.reset();
-	if (d->mExifData) {
-		exif_data_unref(d->mExifData);
-		d->mExifData=0;
-	}
 
 	d->mRawData = data;
 	if (d->mRawData.size()==0) {
@@ -272,19 +250,20 @@
 		return false;
 	}
 
-	if (!d->readJPEGInfo()) return false;
+	if (!d->readSize()) return false;
 
-	d->mExifData = exif_data_new_from_data((unsigned char*)data.data(), data.size());
-	if (!d->mExifData) {
-		kdError() << "Could not load exif data\n";
+	Exiv2::Image::AutoPtr image;
+	try {
+		image = Exiv2::ImageFactory::open((unsigned char*)data.data(), data.size());
+	} catch (Exiv2::Error&) {
+		kdError() << "Could not load image with Exiv2\n";
 		return false;
 	}
-	d->mByteOrder = exif_data_get_byte_order(d->mExifData);
-	
-	d->mOrientationEntry =
-		exif_content_get_entry(d->mExifData->ifd[EXIF_IFD_0],
-			EXIF_TAG_ORIENTATION);
+	image->readMetadata();
 
+	d->mExifData = image->exifData();
+	d->mComment = QString::fromUtf8( image->comment().c_str() );
+
 	// Adjust the size according to the orientation
 	switch (orientation()) {
 	case TRANSPOSE:
@@ -302,21 +281,23 @@
 
 
 Orientation JPEGContent::orientation() const {
-	if (!d->mOrientationEntry) {
+	Exiv2::ExifKey key("Exif.Image.Orientation");
+	Exiv2::ExifData::iterator it = d->mExifData.findKey(key);
+	if (it == d->mExifData.end()) {
 		return NOT_AVAILABLE;
 	}
-	short value=exif_get_short(d->mOrientationEntry->data, d->mByteOrder);
-	if (value<NORMAL || value>ROT_270) return NOT_AVAILABLE;
-	return Orientation(value);
+	return Orientation( it->toLong() );
 }
 
 
 void JPEGContent::resetOrientation() {
-	if (!d->mOrientationEntry) {
+	Exiv2::ExifKey key("Exif.Image.Orientation");
+	Exiv2::ExifData::iterator it = d->mExifData.findKey(key);
+	if (it == d->mExifData.end()) {
 		return;
 	}
-	exif_set_short(d->mOrientationEntry->data, d->mByteOrder,
-		short(ImageUtils::NORMAL));
+
+	*it = uint16_t(ImageUtils::NORMAL);
 }
 
 
@@ -331,43 +312,10 @@
 
 
 void JPEGContent::setComment(const QString& comment) {
-	d->mPendingChanges = true;
 	d->mComment = comment;
 }
 
 
-
-// This code is inspired by jpegtools.c from fbida
-static void doSetComment(struct jpeg_decompress_struct *src, const QString& comment) \
                {
-	jpeg_saved_marker_ptr mark;
-	int size;
-
-	/* find or create comment marker */
-	for (mark = src->marker_list;; mark = mark->next) {
-		if (mark->marker == JPEG_COM)
-			break;
-		if (NULL == mark->next) {
-			mark->next = (jpeg_marker_struct*)
-				src->mem->alloc_large((j_common_ptr)src,JPOOL_IMAGE,
-							   sizeof(*mark));
-			mark = mark->next;
-			memset(mark,0,sizeof(*mark));
-			mark->marker = JPEG_COM;
-			break;
-		}
-	}
-
-	/* update comment marker */
-	QCString utf8=comment.utf8();
-	size = utf8.length();
-	mark->data = (JOCTET*)
-		src->mem->alloc_large((j_common_ptr)src,JPOOL_IMAGE,size);
-	mark->original_length = size;
-	mark->data_length = size;
-	memcpy(mark->data, utf8, size);
-}
-
-
 static QWMatrix createRotMatrix(int angle) {
 	QWMatrix matrix;
 	matrix.rotate(angle);
@@ -419,7 +367,7 @@
 
 void JPEGContent::transform(Orientation orientation) {
 	if (orientation != NOT_AVAILABLE && orientation != NORMAL) {
-		d->mPendingChanges = true;
+		d->mPendingTransformation = true;
 		OrientationInfoList::ConstIterator it(orientationInfoList().begin()), \
end(orientationInfoList().end());  for (; it!=end; ++it) {
 			if ( (*it).orientation == orientation ) {
@@ -465,7 +413,7 @@
 }
 
 
-void JPEGContent::applyPendingChanges() {
+void JPEGContent::applyPendingTransformation() {
 	if (d->mRawData.size()==0) {
 		kdError() << "No data loaded\n";
 		return;
@@ -505,8 +453,6 @@
 
 	(void) jpeg_read_header(&srcinfo, TRUE);
 
-	doSetComment(&srcinfo, d->mComment);
-
 	// Init transformation
 	jpeg_transform_info transformoption;
 	transformoption.transform = findJxform(d->mTransformMatrix);
@@ -556,24 +502,19 @@
 
 QImage JPEGContent::thumbnail() const {
 	QImage image;
-	if( d->mExifData && d->mExifData->data ) {
-		image.loadFromData( d->mExifData->data, d->mExifData->size, "JPEG" );
+	if (!d->mExifData.empty()) {
+		Exiv2::DataBuf thumbnail = d->mExifData.copyThumbnail();
+		image.loadFromData(thumbnail.pData_, thumbnail.size_);
 	}
 	return image;
 }
 
 
 void JPEGContent::setThumbnail(const QImage& thumbnail) {
-	if( !d->mExifData) {
+	if (d->mExifData.empty()) {
 		return;
 	}
 	
-	if(d->mExifData->data) {
-		free(d->mExifData->data);
-		d->mExifData->data=0;
-	}
-	d->mExifData->size=0;
-
 	QByteArray array;
 	QBuffer buffer(array);
 	buffer.open(IO_WriteOnly);
@@ -584,13 +525,7 @@
 		return;
 	}
 	
-	d->mExifData->size=array.size();
-	d->mExifData->data=(unsigned char*)malloc(d->mExifData->size);
-	if (!d->mExifData->data) {
-		kdError() << "Could not allocate memory for thumbnail\n";
-		return;
-	}
-	memcpy(d->mExifData->data, array.data(), array.size());
+	d->mExifData.setJpegThumbnail((unsigned char*)array.data(), array.size());
 }
 
 
@@ -611,29 +546,23 @@
 		return false;
 	}
 
-	if (d->mPendingChanges) {
-		applyPendingChanges();
-		d->mPendingChanges = false;
+	if (d->mPendingTransformation) {
+		applyPendingTransformation();
+		d->mPendingTransformation = false;
 	}
 
-	if (d->mExifData) {
-		// Store Exif info
-		JPEGData* jpegData=jpeg_data_new_from_data((unsigned char*)d->mRawData.data(), \
                d->mRawData.size());
-		if (!jpegData) {
-			kdError() << "Could not create jpegData object\n";
-			return false;
-		}
-		
-		jpeg_data_set_exif_data(jpegData, d->mExifData);
-		unsigned char* dest=0L;
-		unsigned int destSize=0;
-		jpeg_data_save_data(jpegData, &dest, &destSize);
-		jpeg_data_unref(jpegData);
+	Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open((unsigned \
char*)d->mRawData.data(), d->mRawData.size());  
-		// Update mRawData
-		d->mRawData.assign((char*)dest, destSize);
-	}
+	// Store Exif info
+	image->setExifData(d->mExifData);
+	image->setComment(d->mComment.utf8().data());
+	image->writeMetadata();
 	
+	// Update mRawData
+	Exiv2::BasicIo& io = image->io();
+	d->mRawData.resize(io.size());
+	io.read((unsigned char*)d->mRawData.data(), io.size());
+	
 	QDataStream stream(file);
 	stream.writeRawBytes(d->mRawData.data(), d->mRawData.size());
 
--- trunk/extragear/graphics/gwenview/imageutils/jpegcontent.h #601061:601062
@@ -65,7 +65,7 @@
 
 	JPEGContent(const JPEGContent&);
 	void operator=(const JPEGContent&);
-    void applyPendingChanges();
+    void applyPendingTransformation();
 };
 
 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic