Version: svn (using KDE KDE 3.5.5) Installed from: Gentoo Packages Compiler: gcc 4.1.1 Configured with: /var/tmp/portage/gcc-4.1.1/work/gcc-4.1.1/configure --prefix=/usr --bindir=/usr/i686-pc-linux-gnu/gcc-bin/4.1.1 --includedir=/usr/lib/gcc/i686-pc-linux-gnu/4.1.1/include --datadir=/usr/share/gcc-data/i686-pc-linux-gnu/4.1.1 --mandir=/usr/share/gcc-data/i686-pc-linux-gnu/4.1.1/man --infodir=/usr/share/gcc-data/i686-pc-linux-gnu/4.1.1/info --with-gxx-include-dir=/usr/lib/gcc/i686-pc-linux-gnu/4.1.1/include/g++-v4 --host=i686-pc-linux-gnu --build=i686-pc-linux-gnu --disable-altivec --enable-nls --without-included-gettext --with-system-zlib --disable-checking --disable-werror --disable-libunwind-exceptions --disable-multilib --disable-libmudflap --disable-libssp --disable-libgcj --enable-languages=c,c++ --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu OS: Linux When I open this image: http://perso.wanadoo.es/galiasilka/cam_0990.jpg and try to save as, gwenview (1.4.0 SVN) crashes (only with images from my camera). The standard version that is included with kde 3.5.5 crashes too. If I open the image, rotate x degrees and try to save as, then don't crash. When I click to "save as" gwenview says (at console): QComboBox::text: (KFileDialog::filterwidget) Index 0 out of range QComboBox::text: (KFileDialog::filterwidget) Index 0 out of range but it says this with all images. I configured gwenview with --enable-debug=full but I think this will not help: Using host libthread_db library "/lib/libthread_db.so.1". `system-supplied DSO at 0xffffe000' has disappeared; keeping its symbols. [Thread debugging using libthread_db enabled] [New Thread -1233746256 (LWP 13877)] 0xffffe410 in __kernel_vsyscall () #0 0xffffe410 in __kernel_vsyscall () #1 0xb67f4816 in nanosleep () from /lib/libc.so.6 #2 0xb67f463f in sleep () from /lib/libc.so.6 #3 0xb74b12df in KCrash::startDrKonqi () from /usr/kde/3.5/lib/libkdecore.so.4 #4 0x00000000 in ?? () PD: Sorry for my bad english
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(); };