diff options
Diffstat (limited to 'kfile-plugins/jpeg')
-rw-r--r-- | kfile-plugins/jpeg/CMakeLists.txt | 35 | ||||
-rw-r--r-- | kfile-plugins/jpeg/Makefile.am | 24 | ||||
-rw-r--r-- | kfile-plugins/jpeg/README | 35 | ||||
-rw-r--r-- | kfile-plugins/jpeg/exif.cpp | 961 | ||||
-rw-r--r-- | kfile-plugins/jpeg/exif.h | 127 | ||||
-rw-r--r-- | kfile-plugins/jpeg/kfile_jpeg.cpp | 531 | ||||
-rw-r--r-- | kfile-plugins/jpeg/kfile_jpeg.desktop | 64 | ||||
-rw-r--r-- | kfile-plugins/jpeg/kfile_jpeg.h | 44 | ||||
-rw-r--r-- | kfile-plugins/jpeg/kfile_setcomment.cpp | 536 |
9 files changed, 0 insertions, 2357 deletions
diff --git a/kfile-plugins/jpeg/CMakeLists.txt b/kfile-plugins/jpeg/CMakeLists.txt deleted file mode 100644 index a35543d7..00000000 --- a/kfile-plugins/jpeg/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -################################################# -# -# (C) 2010-2011 Calvin Morrison -# -# Improvements and feedback are welcome -# -# This file is released under GPL >= 2 -# -################################################# - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_BINARY_DIR} - ${TDE_INCLUDE_DIR} - ${TQT_INCLUDE_DIRS} -) - -link_directories( - ${TQT_LIBRARY_DIRS} -) - - -#### other data ################################# - -install( FILES kfile_jpeg.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) - - -#### kfile_jpeg (module) ######################## - -tde_add_kpart( kfile_jpeg AUTOMOC - SOURCES kfile_jpeg.cpp exif.cpp kfile_setcomment.cpp - LINK kio-shared - DESTINATION ${PLUGIN_INSTALL_DIR} -) diff --git a/kfile-plugins/jpeg/Makefile.am b/kfile-plugins/jpeg/Makefile.am deleted file mode 100644 index fac3b392..00000000 --- a/kfile-plugins/jpeg/Makefile.am +++ /dev/null @@ -1,24 +0,0 @@ -## Makefile.am for jpeg file meta info plugin - -KDE_CXXFLAGS = $(USE_EXCEPTIONS) - -# set the include path for X, qt and KDE -INCLUDES = $(all_includes) - -# these are the headers for your project -noinst_HEADERS = kfile_jpeg.h exif.h - -kde_module_LTLIBRARIES = kfile_jpeg.la - -kfile_jpeg_la_SOURCES = kfile_jpeg.cpp exif.cpp kfile_setcomment.cpp -kfile_jpeg_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) -kfile_jpeg_la_LIBADD = $(LIB_KIO) - -# let automoc handle all of the meta source files (moc) -METASOURCES = AUTO - -messages: - $(XGETTEXT) *.cpp -o $(podir)/kfile_jpeg.pot - -services_DATA = kfile_jpeg.desktop -servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/jpeg/README b/kfile-plugins/jpeg/README deleted file mode 100644 index 6b714426..00000000 --- a/kfile-plugins/jpeg/README +++ /dev/null @@ -1,35 +0,0 @@ -------------------------------------------------------------------------------- -Thanks to: -Matthias Wandel <[email protected]> -jhead (http://www.sentex.net/~mwandel/jhead/) - -Groult Richard <[email protected]> -showimg (http://ric.jalix.org/) - -Bryce Nesbitt for setcomment -based on wrjpgcom.c, Copyright (C) 1994-1997, Thomas G. Lane. - -Frank Pieczynski <[email protected]> - -EXIF spec: -http://www.pima.net/standards/it10/PIMA15740/exif.htm -http://www.ba.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html - -------------------------------------------------------------------------------- -Bugs: - 0) Just showing the meta info can cause the file to be rewritten!!! - 1) utf-8 paths must be tested and supported. - 2) Display of EXIF comments need to be tested. - Both Unicode & ASCII need testing. - -New features needed: - 1) Should switch to a multi-line editor for comments. Support "\n". - 2) Should autodetect if the jpeg COM is in utf-8 format. - 3) Allow editing the EXIF "Orientation" flag (without rewriting the exif header). - 4) Extract and return the EXIF thumbnail, oriented properly, as an alternative - to the much slower process of generating a new thumbnail. - -Future features: - 1) Allow the user to erase or move comment in either the EXIF or jpeg COM. - 2) Play or return audio files associated with the exif. - diff --git a/kfile-plugins/jpeg/exif.cpp b/kfile-plugins/jpeg/exif.cpp deleted file mode 100644 index 60c689bd..00000000 --- a/kfile-plugins/jpeg/exif.cpp +++ /dev/null @@ -1,961 +0,0 @@ -//-------------------------------------------------------------------------- -// Program to pull the information out of various types of EFIF digital -// camera files and show it in a reasonably consistent way -// -// This module parses the very complicated exif structures. -// -// Matthias Wandel, Dec 1999 - August 2000 -//-------------------------------------------------------------------------- - - -#include "exif.h" -#include <tqwmatrix.h> -#include <kglobal.h> - - -static unsigned char * LastExifRefd; -static int ExifSettingsLength; -static double FocalplaneXRes; -static double FocalplaneUnits; -static int MotorolaOrder = 0; -static int SectionsRead; -//static int HaveAll; - -//-------------------------------------------------------------------------- -// Table of Jpeg encoding process names - -#define M_SOF0 0xC0 // Start Of Frame N -#define M_SOF1 0xC1 // N indicates which compression process -#define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use -#define M_SOF3 0xC3 -#define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers -#define M_SOF6 0xC6 -#define M_SOF7 0xC7 -#define M_SOF9 0xC9 -#define M_SOF10 0xCA -#define M_SOF11 0xCB -#define M_SOF13 0xCD -#define M_SOF14 0xCE -#define M_SOF15 0xCF -#define M_SOI 0xD8 // Start Of Image (beginning of datastream) -#define M_EOI 0xD9 // End Of Image (end of datastream) -#define M_SOS 0xDA // Start Of Scan (begins compressed data) -#define M_JFIF 0xE0 // Jfif marker -#define M_EXIF 0xE1 // Exif marker -#define M_COM 0xFE // COMment - - -TagTable_t ProcessTable[] = { - { M_SOF0, "Baseline"}, - { M_SOF1, "Extended sequential"}, - { M_SOF2, "Progressive"}, - { M_SOF3, "Lossless"}, - { M_SOF5, "Differential sequential"}, - { M_SOF6, "Differential progressive"}, - { M_SOF7, "Differential lossless"}, - { M_SOF9, "Extended sequential, arithmetic coding"}, - { M_SOF10, "Progressive, arithmetic coding"}, - { M_SOF11, "Lossless, arithmetic coding"}, - { M_SOF13, "Differential sequential, arithmetic coding"}, - { M_SOF14, "Differential progressive, arithmetic coding"}, - { M_SOF15, "Differential lossless, arithmetic coding"}, - { 0, "Unknown"} -}; - - - -//-------------------------------------------------------------------------- -// Describes format descriptor -static int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8}; -#define NUM_FORMATS 12 - -#define FMT_BYTE 1 -#define FMT_STRING 2 -#define FMT_USHORT 3 -#define FMT_ULONG 4 -#define FMT_URATIONAL 5 -#define FMT_SBYTE 6 -#define FMT_UNDEFINED 7 -#define FMT_SSHORT 8 -#define FMT_SLONG 9 -#define FMT_SRATIONAL 10 -#define FMT_SINGLE 11 -#define FMT_DOUBLE 12 - -//-------------------------------------------------------------------------- -// Describes tag values - -#define TAG_EXIF_OFFSET 0x8769 -#define TAG_INTEROP_OFFSET 0xa005 - -#define TAG_MAKE 0x010F -#define TAG_MODEL 0x0110 -#define TAG_ORIENTATION 0x0112 - -#define TAG_EXPOSURETIME 0x829A -#define TAG_FNUMBER 0x829D - -#define TAG_SHUTTERSPEED 0x9201 -#define TAG_APERTURE 0x9202 -#define TAG_MAXAPERTURE 0x9205 -#define TAG_FOCALLENGTH 0x920A - -#define TAG_DATETIME_ORIGINAL 0x9003 -#define TAG_USERCOMMENT 0x9286 - -#define TAG_SUBJECT_DISTANCE 0x9206 -#define TAG_FLASH 0x9209 - -#define TAG_FOCALPLANEXRES 0xa20E -#define TAG_FOCALPLANEUNITS 0xa210 -#define TAG_EXIF_IMAGEWIDTH 0xA002 -#define TAG_EXIF_IMAGELENGTH 0xA003 - -// the following is added 05-jan-2001 vcs -#define TAG_EXPOSURE_BIAS 0x9204 -#define TAG_WHITEBALANCE 0x9208 -#define TAG_METERING_MODE 0x9207 -#define TAG_EXPOSURE_PROGRAM 0x8822 -#define TAG_ISO_EQUIVALENT 0x8827 -#define TAG_COMPRESSION_LEVEL 0x9102 - -#define TAG_THUMBNAIL_OFFSET 0x0201 -#define TAG_THUMBNAIL_LENGTH 0x0202 - - -/*static TagTable_t TagTable[] = { - { 0x100, "ImageWidth"}, - { 0x101, "ImageLength"}, - { 0x102, "BitsPerSample"}, - { 0x103, "Compression"}, - { 0x106, "PhotometricInterpretation"}, - { 0x10A, "FillOrder"}, - { 0x10D, "DocumentName"}, - { 0x10E, "ImageDescription"}, - { 0x10F, "Make"}, - { 0x110, "Model"}, - { 0x111, "StripOffsets"}, - { 0x112, "Orientation"}, - { 0x115, "SamplesPerPixel"}, - { 0x116, "RowsPerStrip"}, - { 0x117, "StripByteCounts"}, - { 0x11A, "XResolution"}, - { 0x11B, "YResolution"}, - { 0x11C, "PlanarConfiguration"}, - { 0x128, "ResolutionUnit"}, - { 0x12D, "TransferFunction"}, - { 0x131, "Software"}, - { 0x132, "DateTime"}, - { 0x13B, "Artist"}, - { 0x13E, "WhitePoint"}, - { 0x13F, "PrimaryChromaticities"}, - { 0x156, "TransferRange"}, - { 0x200, "JPEGProc"}, - { 0x201, "ThumbnailOffset"}, - { 0x202, "ThumbnailLength"}, - { 0x211, "YCbCrCoefficients"}, - { 0x212, "YCbCrSubSampling"}, - { 0x213, "YCbCrPositioning"}, - { 0x214, "ReferenceBlackWhite"}, - { 0x828D, "CFARepeatPatternDim"}, - { 0x828E, "CFAPattern"}, - { 0x828F, "BatteryLevel"}, - { 0x8298, "Copyright"}, - { 0x829A, "ExposureTime"}, - { 0x829D, "FNumber"}, - { 0x83BB, "IPTC/NAA"}, - { 0x8769, "ExifOffset"}, - { 0x8773, "InterColorProfile"}, - { 0x8822, "ExposureProgram"}, - { 0x8824, "SpectralSensitivity"}, - { 0x8825, "GPSInfo"}, - { 0x8827, "ISOSpeedRatings"}, - { 0x8828, "OECF"}, - { 0x9000, "ExifVersion"}, - { 0x9003, "DateTimeOriginal"}, - { 0x9004, "DateTimeDigitized"}, - { 0x9101, "ComponentsConfiguration"}, - { 0x9102, "CompressedBitsPerPixel"}, - { 0x9201, "ShutterSpeedValue"}, - { 0x9202, "ApertureValue"}, - { 0x9203, "BrightnessValue"}, - { 0x9204, "ExposureBiasValue"}, - { 0x9205, "MaxApertureValue"}, - { 0x9206, "SubjectDistance"}, - { 0x9207, "MeteringMode"}, - { 0x9208, "LightSource"}, - { 0x9209, "Flash"}, - { 0x920A, "FocalLength"}, - { 0x927C, "MakerNote"}, - { 0x9286, "UserComment"}, - { 0x9290, "SubSecTime"}, - { 0x9291, "SubSecTimeOriginal"}, - { 0x9292, "SubSecTimeDigitized"}, - { 0xA000, "FlashPixVersion"}, - { 0xA001, "ColorSpace"}, - { 0xA002, "ExifImageWidth"}, - { 0xA003, "ExifImageLength"}, - { 0xA005, "InteroperabilityOffset"}, - { 0xA20B, "FlashEnergy"}, // 0x920B in TIFF/EP - { 0xA20C, "SpatialFrequencyResponse"}, // 0x920C - - - { 0xA20E, "FocalPlaneXResolution"}, // 0x920E - - - { 0xA20F, "FocalPlaneYResolution"}, // 0x920F - - - { 0xA210, "FocalPlaneResolutionUnit"}, // 0x9210 - - - { 0xA214, "SubjectLocation"}, // 0x9214 - - - { 0xA215, "ExposureIndex"}, // 0x9215 - - - { 0xA217, "SensingMethod"}, // 0x9217 - - - { 0xA300, "FileSource"}, - { 0xA301, "SceneType"}, - { 0, NULL} -} ; -*/ - - -//-------------------------------------------------------------------------- -// Parse the marker stream until SOS or EOI is seen; -//-------------------------------------------------------------------------- -int ExifData::ReadJpegSections (TQFile & infile, ReadMode_t ReadMode) -{ - int a; - - a = infile.getch(); - - if (a != 0xff || infile.getch() != M_SOI) { - SectionsRead = 0; - return false; - } - for(SectionsRead = 0; SectionsRead < MAX_SECTIONS-1; ){ - int marker = 0; - int got; - unsigned int ll,lh; - unsigned int itemlen; - uchar * Data; - - for (a=0;a<7;a++){ - marker = infile.getch(); - if (marker != 0xff) break; - - if (a >= 6){ - - kdDebug(7034) << "too many padding bytes\n"; - return false; - - } - } - - if (marker == 0xff){ - // 0xff is legal padding, but if we get that many, something's wrong. - throw FatalError("too many padding bytes!"); - } - - Sections[SectionsRead].Type = marker; - - // Read the length of the section. - lh = (uchar) infile.getch(); - ll = (uchar) infile.getch(); - - itemlen = (lh << 8) | ll; - - if (itemlen < 2) { - throw FatalError("invalid marker"); - } - - Sections[SectionsRead].Size = itemlen; - - Data = (uchar *)malloc(itemlen+1); // Add 1 to allow sticking a 0 at the end. - Sections[SectionsRead].Data = Data; - - // Store first two pre-read bytes. - Data[0] = (uchar)lh; - Data[1] = (uchar)ll; - - got = infile.readBlock((char*)Data+2, itemlen-2); // Read the whole section. - if (( unsigned ) got != itemlen-2){ - throw FatalError("reading from file"); - } - SectionsRead++; - - switch(marker){ - - case M_SOS: // stop before hitting compressed data - // If reading entire image is requested, read the rest of the data. - if (ReadMode & READ_IMAGE){ - unsigned long size; - - size = kMax( 0ul, (unsigned long)(infile.size()-infile.at()) ); - Data = (uchar *)malloc(size); - if (Data == NULL){ - throw FatalError("could not allocate data for entire image"); - } - - got = infile.readBlock((char*)Data, size); - if (( unsigned ) got != size){ - throw FatalError("could not read the rest of the image"); - } - - Sections[SectionsRead].Data = Data; - Sections[SectionsRead].Size = size; - Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER; - SectionsRead ++; - //HaveAll = 1; - } - return true; - - case M_EOI: // in case it's a tables-only JPEG stream - kdDebug(7034) << "No image in jpeg!\n"; - return false; - - case M_COM: // Comment section - // pieczy 2002-02-12 - // now the User comment goes to UserComment - // so we can store a Comment section also in READ_EXIF mode - process_COM(Data, itemlen); - break; - - case M_JFIF: - // Regular jpegs always have this tag, exif images have the exif - // marker instead, althogh ACDsee will write images with both markers. - // this program will re-create this marker on absence of exif marker. - // hence no need to keep the copy from the file. - free(Sections[--SectionsRead].Data); - break; - - case M_EXIF: - // Seen files from some 'U-lead' software with Vivitar scanner - // that uses marker 31 for non exif stuff. Thus make sure - // it says 'Exif' in the section before treating it as exif. - if ((ReadMode & READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){ - process_EXIF((uchar *)Data, itemlen); // FIXME: This call - // requires Data to be array of at least 8 bytes. Code - // above only checks for itemlen < 2. - }else{ - // Discard this section. - free(Sections[--SectionsRead].Data); - } - break; - - case M_SOF0: - case M_SOF1: - case M_SOF2: - case M_SOF3: - case M_SOF5: - case M_SOF6: - case M_SOF7: - case M_SOF9: - case M_SOF10: - case M_SOF11: - case M_SOF13: - case M_SOF14: - case M_SOF15: - process_SOFn(Data, marker); //FIXME: This call requires Data to - // be array of at least 8 bytes. Code above only checks for - // itemlen < 2. - break; - default: - break; - } - } - return true; -} - - -//-------------------------------------------------------------------------- -// Discard read data. -//-------------------------------------------------------------------------- -void ExifData::DiscardData(void) -{ - for (int a=0; a < SectionsRead; a++) - free(Sections[a].Data); - SectionsRead = 0; -} - -//-------------------------------------------------------------------------- -// Convert a 16 bit unsigned value from file's native byte order -//-------------------------------------------------------------------------- -int ExifData::Get16u(void * Short) -{ - if (MotorolaOrder){ - return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1]; - }else{ - return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0]; - } -} - -//-------------------------------------------------------------------------- -// Convert a 32 bit signed value from file's native byte order -//-------------------------------------------------------------------------- -int ExifData::Get32s(void * Long) -{ - if (MotorolaOrder){ - return ((( char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16) - | (((uchar *)Long)[2] << 8 ) | (((uchar *)Long)[3] << 0 ); - }else{ - return ((( char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16) - | (((uchar *)Long)[1] << 8 ) | (((uchar *)Long)[0] << 0 ); - } -} - -//-------------------------------------------------------------------------- -// Convert a 32 bit unsigned value from file's native byte order -//-------------------------------------------------------------------------- -unsigned ExifData::Get32u(void * Long) -{ - return (unsigned)Get32s(Long) & 0xffffffff; -} - -//-------------------------------------------------------------------------- -// Evaluate number, be it int, rational, or float from directory. -//-------------------------------------------------------------------------- -double ExifData::ConvertAnyFormat(void * ValuePtr, int Format) -{ - double Value; - Value = 0; - - switch(Format){ - case FMT_SBYTE: Value = *(signed char *)ValuePtr; break; - case FMT_BYTE: Value = *(uchar *)ValuePtr; break; - - case FMT_USHORT: Value = Get16u(ValuePtr); break; - - case FMT_ULONG: Value = Get32u(ValuePtr); break; - - case FMT_URATIONAL: - case FMT_SRATIONAL: - { - int Num,Den; - Num = Get32s(ValuePtr); - Den = Get32s(4+(char *)ValuePtr); - if (Den == 0){ - Value = 0; - }else{ - Value = (double)Num/Den; - } - break; - } - - case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break; - case FMT_SLONG: Value = Get32s(ValuePtr); break; - - // Not sure if this is correct (never seen float used in Exif format) - case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break; - case FMT_DOUBLE: Value = *(double *)ValuePtr; break; - } - return Value; -} - -//-------------------------------------------------------------------------- -// Process one of the nested EXIF directories. -//-------------------------------------------------------------------------- -void ExifData::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength, unsigned NestingLevel) -{ - int de; - int a; - int NumDirEntries; - unsigned ThumbnailOffset = 0; - unsigned ThumbnailSize = 0; - - if ( NestingLevel > 4) - throw FatalError("Maximum directory nesting exceeded (corrupt exif header)"); - - NumDirEntries = Get16u(DirStart); - #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry)) - - { - unsigned char * DirEnd; - DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries); - if (DirEnd+4 > (OffsetBase+ExifLength)){ - if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength){ - // Version 1.3 of jhead would truncate a bit too much. - // This also caught later on as well. - }else{ - // Note: Files that had thumbnails trimmed with jhead 1.3 or earlier - // might trigger this. - throw FatalError("Illegally sized directory"); - } - } - if (DirEnd < LastExifRefd) LastExifRefd = DirEnd; - } - - for (de=0;de<NumDirEntries;de++){ - int Tag, Format, Components; - unsigned char * ValuePtr; - unsigned ByteCount; - char * DirEntry; - DirEntry = (char *)DIR_ENTRY_ADDR(DirStart, de); - - Tag = Get16u(DirEntry); - Format = Get16u(DirEntry+2); - Components = Get32u(DirEntry+4); - - if ((Format-1) >= NUM_FORMATS) { - // (-1) catches illegal zero case as unsigned underflows to positive large. - throw FatalError("Illegal format code in EXIF dir"); - } - - if ((unsigned)Components > 0x10000) { - throw FatalError("Illegal number of components for tag"); - continue; - } - - ByteCount = Components * BytesPerFormat[Format]; - - if (ByteCount > 4){ - unsigned OffsetVal; - OffsetVal = Get32u(DirEntry+8); - // If its bigger than 4 bytes, the dir entry contains an offset. - if (OffsetVal+ByteCount > ExifLength){ - // Bogus pointer offset and / or bytecount value - //printf("Offset %d bytes %d ExifLen %d\n",OffsetVal, ByteCount, ExifLength); - - throw FatalError("Illegal pointer offset value in EXIF"); - } - ValuePtr = OffsetBase+OffsetVal; - }else{ - // 4 bytes or less and value is in the dir entry itself - ValuePtr = (unsigned char *)DirEntry+8; - } - - if (LastExifRefd < ValuePtr+ByteCount){ - // Keep track of last byte in the exif header that was actually referenced. - // That way, we know where the discardable thumbnail data begins. - LastExifRefd = ValuePtr+ByteCount; - } - - // Extract useful components of tag - switch(Tag){ - - case TAG_MAKE: - ExifData::CameraMake = TQString::fromLatin1((const char*)ValuePtr, 31); - break; - - case TAG_MODEL: - ExifData::CameraModel = TQString::fromLatin1((const char*)ValuePtr, 39); - break; - - case TAG_ORIENTATION: - Orientation = (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_DATETIME_ORIGINAL: - DateTime = TQString::fromLatin1((const char*)ValuePtr, 19); - break; - - case TAG_USERCOMMENT: - // Olympus has this padded with trailing spaces. Remove these first. - for (a=ByteCount;;){ - a--; - if ((ValuePtr)[a] == ' '){ - (ValuePtr)[a] = '\0'; - }else{ - break; - } - if (a == 0) break; - } - - // Copy the comment - if (memcmp(ValuePtr, "ASCII",5) == 0){ - for (a=5;a<10;a++){ - int c; - c = (ValuePtr)[a]; - if (c != '\0' && c != ' '){ - UserComment = TQString::fromLatin1((const char*)(a+ValuePtr), 199); - break; - } - } - }else{ - UserComment = TQString::fromLatin1((const char*)ValuePtr, 199); - } - break; - - case TAG_FNUMBER: - // Simplest way of expressing aperture, so I trust it the most. - // (overwrite previously computd value if there is one) - ExifData::ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_APERTURE: - case TAG_MAXAPERTURE: - // More relevant info always comes earlier, so only use this field if we don't - // have appropriate aperture information yet. - if (ExifData::ApertureFNumber == 0){ - ExifData::ApertureFNumber - = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0)*0.5); - } - break; - - case TAG_FOCALLENGTH: - // Nice digital cameras actually save the focal length as a function - // of how far they are zoomed in. - ExifData::FocalLength = (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_SUBJECT_DISTANCE: - // Inidcates the distacne the autofocus camera is focused to. - // Tends to be less accurate as distance increases. - ExifData::Distance = (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_EXPOSURETIME: - // Simplest way of expressing exposure time, so I trust it most. - // (overwrite previously computd value if there is one) - ExifData::ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_SHUTTERSPEED: - // More complicated way of expressing exposure time, so only use - // this value if we don't already have it from somewhere else. - if (ExifData::ExposureTime == 0){ - ExifData::ExposureTime - = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0))); - } - break; - - case TAG_FLASH: - ExifData::FlashUsed = (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_EXIF_IMAGELENGTH: - ExifImageLength = (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_EXIF_IMAGEWIDTH: - ExifImageWidth = (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_FOCALPLANEXRES: - FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_FOCALPLANEUNITS: - switch((int)ConvertAnyFormat(ValuePtr, Format)){ - case 1: FocalplaneUnits = 25.4; break; // inch - case 2: - // According to the information I was using, 2 means meters. - // But looking at the Cannon powershot's files, inches is the only - // sensible value. - FocalplaneUnits = 25.4; - break; - - case 3: FocalplaneUnits = 10; break; // centimeter - case 4: FocalplaneUnits = 1; break; // milimeter - case 5: FocalplaneUnits = .001; break; // micrometer - } - break; - - // Remaining cases contributed by: Volker C. Schoech ([email protected]) - - case TAG_EXPOSURE_BIAS: - ExifData::ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_WHITEBALANCE: - ExifData::Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_METERING_MODE: - ExifData::MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_EXPOSURE_PROGRAM: - ExifData::ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_ISO_EQUIVALENT: - ExifData::ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format); - if ( ExifData::ISOequivalent < 50 ) ExifData::ISOequivalent *= 200; - break; - - case TAG_COMPRESSION_LEVEL: - ExifData::CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_THUMBNAIL_OFFSET: - ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_THUMBNAIL_LENGTH: - ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format); - break; - - } - - if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET){ - unsigned char * SubdirStart; - SubdirStart = OffsetBase + Get32u(ValuePtr); - if (SubdirStart <= OffsetBase || SubdirStart >= OffsetBase+ExifLength){ - throw FatalError("Illegal subdirectory link"); - } - ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1); - continue; - } - } - - { - // In addition to linking to subdirectories via exif tags, - // there's also a potential link to another directory at the end of each - // directory. this has got to be the result of a comitee! - unsigned char * SubdirStart; - unsigned Offset; - - if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){ - Offset = Get32u(DIR_ENTRY_ADDR(DirStart, NumDirEntries)); - // There is at least one jpeg from an HP camera having an Offset of almost MAXUINT. - // Adding OffsetBase to it produces an overflow, so compare with ExifLength here. - // See http://bugs.kde.org/show_bug.cgi?id=54542 - if (Offset && Offset < ExifLength){ - SubdirStart = OffsetBase + Offset; - if (SubdirStart > OffsetBase+ExifLength){ - if (SubdirStart < OffsetBase+ExifLength+20){ - // Jhead 1.3 or earlier would crop the whole directory! - // As Jhead produces this form of format incorrectness, - // I'll just let it pass silently - kdDebug(7034) << "Thumbnail removed with Jhead 1.3 or earlier\n"; - }else{ - throw FatalError("Illegal subdirectory link 2"); - } - }else{ - if (SubdirStart <= OffsetBase+ExifLength){ - ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1); - } - } - } - }else{ - // The exif header ends before the last next directory pointer. - } - } - - if (ThumbnailSize && ThumbnailOffset){ - if (ThumbnailSize + ThumbnailOffset < ExifLength){ - // The thumbnail pointer appears to be valid. Store it. - Thumbnail.loadFromData(OffsetBase + ThumbnailOffset, ThumbnailSize, "JPEG"); - } - } -} - -//-------------------------------------------------------------------------- -// Process a COM marker. We want to leave the bytes unchanged. The -// progam that displays this text may decide to remove blanks, convert -// newlines, or otherwise modify the text. In particular we want to be -// safe for passing utf-8 text. -//-------------------------------------------------------------------------- -void ExifData::process_COM (const uchar * Data, int length) -{ - Comment = TQString::fromUtf8((char *)Data+2, (length-2)); -} - - -//-------------------------------------------------------------------------- -// Process a SOFn marker. This is useful for the image dimensions -//-------------------------------------------------------------------------- -void ExifData::process_SOFn (const uchar * Data, int marker) -{ - int data_precision, num_components; - - data_precision = Data[2]; - ExifData::Height = Get16m(Data+3); - ExifData::Width = Get16m(Data+5); - num_components = Data[7]; - - if (num_components == 3){ - ExifData::IsColor = 1; - }else{ - ExifData::IsColor = 0; - } - - ExifData::Process = marker; - -} - -//-------------------------------------------------------------------------- -// Get 16 bits motorola order (always) for jpeg header stuff. -//-------------------------------------------------------------------------- -int ExifData::Get16m(const void * Short) -{ - return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1]; -} - - -//-------------------------------------------------------------------------- -// Process a EXIF marker -// Describes all the drivel that most digital cameras include... -//-------------------------------------------------------------------------- -void ExifData::process_EXIF(unsigned char * CharBuf, unsigned int length) -{ - ExifData::FlashUsed = 0; // If it s from a digicam, and it used flash, it says so. - - FocalplaneXRes = 0; - FocalplaneUnits = 0; - ExifImageWidth = 0; - ExifImageLength = 0; - - { // Check the EXIF header component - static const uchar ExifHeader[] = "Exif\0\0"; - if (memcmp(CharBuf+2, ExifHeader,6)){ - throw FatalError("Incorrect Exif header"); - } - } - - if (memcmp(CharBuf+8,"II",2) == 0){ - // printf("Exif section in Intel order\n"); - MotorolaOrder = 0; - }else{ - if (memcmp(CharBuf+8,"MM",2) == 0){ - // printf("Exif section in Motorola order\n"); - MotorolaOrder = 1; - }else{ - throw FatalError("Invalid Exif alignment marker."); - } - } - - // Check the next two values for correctness. - if (Get16u(CharBuf+10) != 0x2a){ - throw FatalError("Invalid Exif start (1)"); - } - - long IFDoffset = Get32u(CharBuf+12); - - LastExifRefd = CharBuf; - - // First directory starts 16 bytes in. Offsets start at 8 bytes in. - ProcessExifDir(&CharBuf[8+IFDoffset], CharBuf+8, length-6, 0); - - // This is how far the interesting (non thumbnail) part of the exif went. - ExifSettingsLength = LastExifRefd - CharBuf; - - // Compute the CCD width, in milimeters. - if (FocalplaneXRes != 0){ - kdDebug(7034) << "ExifImageWidth " << ExifImageWidth << " FocalplaneUnits " << FocalplaneUnits << " FocalplaneXRes " << FocalplaneXRes << endl; - ExifData::CCDWidth = (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes); - } -} - -//-------------------------------------------------------------------------- -// Convert exif time to Unix time structure -//-------------------------------------------------------------------------- -int ExifData::Exif2tm(struct tm * timeptr, char * ExifTime) -{ - int a; - - timeptr->tm_wday = -1; - - // Check for format: YYYY:MM:DD HH:MM:SS format. - a = sscanf(ExifTime, "%d:%d:%d %d:%d:%d", - &timeptr->tm_year, &timeptr->tm_mon, &timeptr->tm_mday, - &timeptr->tm_hour, &timeptr->tm_min, &timeptr->tm_sec); - - if (a == 6){ - timeptr->tm_isdst = -1; - timeptr->tm_mon -= 1; // Adjust for unix zero-based months - timeptr->tm_year -= 1900; // Adjust for year starting at 1900 - return true; // worked. - } - - return false; // Wasn't in Exif date format. -} - -//-------------------------------------------------------------------------- -// Contructor for initialising -//-------------------------------------------------------------------------- -ExifData::ExifData() -{ - ExifData::Whitebalance = -1; - ExifData::MeteringMode = -1; - ExifData::FlashUsed = 0; - Orientation = 0; - Height = 0; - Width = 0; - IsColor = 0; - Process = 0; - FocalLength = 0; - ExposureTime = 0; - ApertureFNumber = 0; - Distance = 0; - CCDWidth = 0; - ExposureBias = 0; - ExposureProgram = 0; - ISOequivalent = 0; - CompressionLevel = 0; -} - -//-------------------------------------------------------------------------- -// process a EXIF jpeg file -//-------------------------------------------------------------------------- -bool ExifData::scan(const TQString & path) -{ - int ret; - - TQFile f(path); - if ( !f.open(IO_ReadOnly) ) - return false; - - try { - // Scan the JPEG headers. - ret = ReadJpegSections(f, READ_EXIF); - } - catch (FatalError& e) { - e.debug_print(); - f.close(); - return false; - } - - if (ret == false){ - kdDebug(7034) << "Not JPEG file!\n"; - DiscardData(); - f.close(); - return false; - } - f.close(); - DiscardData(); - - //now make the strings clean, - // for exmaple my Casio is a "QV-4000 " - CameraMake = CameraMake.stripWhiteSpace(); - CameraModel = CameraModel.stripWhiteSpace(); - UserComment = UserComment.stripWhiteSpace(); - Comment = Comment.stripWhiteSpace(); - return true; -} - -//-------------------------------------------------------------------------- -// Does the embedded thumbnail match the jpeg image? -//-------------------------------------------------------------------------- -#ifndef JPEG_TOL -#define JPEG_TOL 0.02 -#endif -bool ExifData::isThumbnailSane() { - if (Thumbnail.isNull()) return false; - - // check whether thumbnail dimensions match the image - // not foolproof, but catches some altered images (jpegtran -rotate) - if (ExifImageLength != 0 && ExifImageLength != Height) return false; - if (ExifImageWidth != 0 && ExifImageWidth != Width) return false; - if (Thumbnail.width() == 0 || Thumbnail.height() == 0) return false; - if (Height == 0 || Width == 0) return false; - double d = (double)Height/Width*Thumbnail.width()/Thumbnail.height(); - return (1-JPEG_TOL < d) && (d < 1+JPEG_TOL); -} - - -//-------------------------------------------------------------------------- -// return a thumbnail that respects the orientation flag -// only if it seems sane -//-------------------------------------------------------------------------- -TQImage ExifData::getThumbnail() { - if (!isThumbnailSane()) return NULL; - if (!Orientation || Orientation == 1) return Thumbnail; - - // now fix orientation - TQWMatrix M; - TQWMatrix flip= TQWMatrix(-1,0,0,1,0,0); - switch (Orientation) { // notice intentional fallthroughs - case 2: M = flip; break; - case 4: M = flip; - case 3: M.rotate(180); break; - case 5: M = flip; - case 6: M.rotate(90); break; - case 7: M = flip; - case 8: M.rotate(270); break; - default: break; // should never happen - } - return Thumbnail.xForm(M); -} diff --git a/kfile-plugins/jpeg/exif.h b/kfile-plugins/jpeg/exif.h deleted file mode 100644 index f8eb13ef..00000000 --- a/kfile-plugins/jpeg/exif.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef __EXIF_H__ -#define __EXIF_H__ - -/** - exif.h -*/ - -#include <stdio.h> -#include <stdlib.h> -#include <math.h> -#include <time.h> - -#include "tqstring.h" -#include "tqfile.h" -#include "tqimage.h" -#include <kdebug.h> - -typedef enum { - READ_EXIF = 1, - READ_IMAGE = 2, - READ_ALL = 3 -}ReadMode_t; - -//-------------------------------------------------------------------------- -// This structure is used to store jpeg file sections in memory. -typedef struct { - uchar * Data; - int Type; - unsigned Size; -}Section_t; - -typedef unsigned char uchar; - -typedef struct { - unsigned short Tag; - const char*const Desc; -}TagTable_t; - -#define MAX_SECTIONS 20 -#define PSEUDO_IMAGE_MARKER 0x123; // Extra value. - -class ExifData { - Section_t Sections[MAX_SECTIONS]; - - TQString CameraMake; - TQString CameraModel; - TQString DateTime; - int Orientation; - int Height, Width; - int ExifImageLength, ExifImageWidth; - int IsColor; - int Process; - int FlashUsed; - float FocalLength; - float ExposureTime; - float ApertureFNumber; - float Distance; - int Whitebalance; - int MeteringMode; - float CCDWidth; - float ExposureBias; - int ExposureProgram; - int ISOequivalent; - int CompressionLevel; - TQString UserComment; - TQString Comment; - TQImage Thumbnail; - - int ReadJpegSections (TQFile & infile, ReadMode_t ReadMode); - void DiscardData(void); - int Get16u(void * Short); - int Get32s(void * Long); - unsigned Get32u(void * Long); - double ConvertAnyFormat(void * ValuePtr, int Format); - void ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength, - unsigned NestingLevel); - void process_COM (const uchar * Data, int length); - void process_SOFn (const uchar * Data, int marker); - int Get16m(const void * Short); - void process_EXIF(unsigned char * CharBuf, unsigned int length); - int Exif2tm(struct tm * timeptr, char * ExifTime); - -public: - ExifData(); - bool scan(const TQString &); - TQString getCameraMake() { return CameraMake; } - TQString getCameraModel() { return CameraModel; } - TQString getDateTime() { return DateTime; } - int getOrientation() { return Orientation; } - int getHeight() { return Height; } - int getWidth() { return Width; } - int getIsColor() { return IsColor; } - int getProcess() { return Process; } - int getFlashUsed() { return FlashUsed; } - float getFocalLength() { return FocalLength; } - float getExposureTime() { return ExposureTime; } - float getApertureFNumber() { return ApertureFNumber; } - float getDistance() { return Distance; } - int getWhitebalance() { return Whitebalance; } - int getMeteringMode() { return MeteringMode; } - float getCCDWidth() { return CCDWidth; } - float getExposureBias() { return ExposureBias; } - int getExposureProgram() { return ExposureProgram; } - int getISOequivalent() { return ISOequivalent; } - int getCompressionLevel() { return CompressionLevel; } - TQString getUserComment() { return UserComment; } - TQString getComment() { return Comment; } - TQImage getThumbnail(); - bool isThumbnailSane(); - bool isNullThumbnail() { return !isThumbnailSane(); } -}; - -class FatalError { - const char* ex; -public: - FatalError(const char* s) { ex = s; } - void debug_print() const { kdDebug(7034) << "exception: " << ex << endl; } -}; - -extern TagTable_t ProcessTable[]; - -//-------------------------------------------------------------------------- -// Define comment writing code, impelemented in setcomment.c -extern int safe_copy_and_modify( const char * original_filename, const char * comment ); - -#endif - diff --git a/kfile-plugins/jpeg/kfile_jpeg.cpp b/kfile-plugins/jpeg/kfile_jpeg.cpp deleted file mode 100644 index 6f187c8e..00000000 --- a/kfile-plugins/jpeg/kfile_jpeg.cpp +++ /dev/null @@ -1,531 +0,0 @@ -/* This file is part of the KDE project - * Copyright (C) 2002 Frank Pieczynski <[email protected]>, - * 2002 Carsten Pfeiffer <[email protected]> - * based on the jhead tool of Matthias Wandel (see below) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - - -#include <stdlib.h> -#include "kfile_jpeg.h" - -#include <kurl.h> -#include <kprocess.h> -#include <klocale.h> -#include <kgenericfactory.h> -#include <kdebug.h> - -#include <tqcstring.h> -#include <tqfile.h> -#include <tqdatetime.h> -#include <tqdict.h> -#include <tqvalidator.h> -#include <tqimage.h> - -#include "exif.h" - -#define EXIFGROUP "Jpeg EXIF Data" - -typedef KGenericFactory<KJpegPlugin> JpegFactory; - -K_EXPORT_COMPONENT_FACTORY(kfile_jpeg, JpegFactory("kfile_jpeg")) - -KJpegPlugin::KJpegPlugin(TQObject *parent, const char *name, - const TQStringList &args ) - : KFilePlugin(parent, name, args) -{ - kdDebug(7034) << "jpeg plugin\n"; - - // - // define all possible meta info items - // - KFileMimeTypeInfo *info = addMimeTypeInfo("image/jpeg"); - KFileMimeTypeInfo::GroupInfo *exifGroup = addGroupInfo( info, EXIFGROUP, - i18n("JPEG Exif") ); - KFileMimeTypeInfo::ItemInfo* item; - - item = addItemInfo( exifGroup, "Comment", i18n("Comment"), TQVariant::String); - setAttributes( item, - KFileMimeTypeInfo::Modifiable | - KFileMimeTypeInfo::Addable | - KFileMimeTypeInfo::MultiLine ); - - item = addItemInfo( exifGroup, "Manufacturer", i18n("Camera Manufacturer"), - TQVariant::String ); - - item = addItemInfo( exifGroup, "Model", i18n("Camera Model"), - TQVariant::String ); - - item = addItemInfo( exifGroup, "Date/time", i18n("Date/Time"), - TQVariant::DateTime ); - - item = addItemInfo( exifGroup, "CreationDate", i18n("Creation Date"), - TQVariant::Date ); - - item = addItemInfo( exifGroup, "CreationTime", i18n("Creation Time"), - TQVariant::Time ); - - item = addItemInfo( exifGroup, "Dimensions", i18n("Dimensions"), - TQVariant::Size ); - setHint( item, KFileMimeTypeInfo::Size ); - setUnit( item, KFileMimeTypeInfo::Pixels ); - - item = addItemInfo( exifGroup, "Orientation", i18n("Orientation"), - TQVariant::Int ); - - item = addItemInfo( exifGroup, "ColorMode", i18n("Color Mode"), - TQVariant::String ); - - item = addItemInfo( exifGroup, "Flash used", i18n("Flash Used"), - TQVariant::String ); - item = addItemInfo( exifGroup, "Focal length", i18n("Focal Length"), - TQVariant::String ); - setUnit( item, KFileMimeTypeInfo::Millimeters ); - - item = addItemInfo( exifGroup, "35mm equivalent", i18n("35mm Equivalent"), - TQVariant::Int ); - setUnit( item, KFileMimeTypeInfo::Millimeters ); - - item = addItemInfo( exifGroup, "CCD width", i18n("CCD Width"), - TQVariant::String ); - setUnit( item, KFileMimeTypeInfo::Millimeters ); - - item = addItemInfo( exifGroup, "Exposure time", i18n("Exposure Time"), - TQVariant::String ); - setHint( item, KFileMimeTypeInfo::Seconds ); - - item = addItemInfo( exifGroup, "Aperture", i18n("Aperture"), - TQVariant::String ); - - item = addItemInfo( exifGroup, "Focus dist.", i18n("Focus Dist."), - TQVariant::String ); - - item = addItemInfo( exifGroup, "Exposure bias", i18n("Exposure Bias"), - TQVariant::String ); - - item = addItemInfo( exifGroup, "Whitebalance", i18n("Whitebalance"), - TQVariant::String ); - - item = addItemInfo( exifGroup, "Metering mode", i18n("Metering Mode"), - TQVariant::String ); - - item = addItemInfo( exifGroup, "Exposure", i18n("Exposure"), - TQVariant::String ); - - item = addItemInfo( exifGroup, "ISO equiv.", i18n("ISO Equiv."), - TQVariant::String ); - - item = addItemInfo( exifGroup, "JPEG quality", i18n("JPEG Quality"), - TQVariant::String ); - - item = addItemInfo( exifGroup, "User comment", i18n("User Comment"), - TQVariant::String ); - setHint(item, KFileMimeTypeInfo::Description); - - item = addItemInfo( exifGroup, "JPEG process", i18n("JPEG Process"), - TQVariant::String ); - - item = addItemInfo( exifGroup, "Thumbnail", i18n("Thumbnail"), - TQVariant::Image ); - setHint( item, KFileMimeTypeInfo::Thumbnail ); - -// ### -// exifGroup.setSupportsVariableKeys(true); -} - -TQValidator* KJpegPlugin::createValidator(const KFileMetaInfoItem& /*item*/, - TQObject */*parent*/, - const char */*name*/ ) const -{ - // no need to return a validator that validates everything as OK :) -// if (item.isEditable()) -// return new TQRegExpValidator(TQRegExp(".*"), parent, name); -// else - return 0L; -} - -bool KJpegPlugin::writeInfo( const KFileMetaInfo& info ) const -{ - TQString comment = info[EXIFGROUP].value("Comment").toString(); - TQString path = info.path(); - - kdDebug(7034) << "exif writeInfo: " << info.path() << " \"" << comment << "\"\n"; - - /* - Do a strictly safe insertion of the comment: - - Scan original to verify it's a proper jpeg - Open a unique temporary file in this directory - Write temporary, replacing all COM blocks with this one. - Scan temporary, to verify it's a proper jpeg - Rename original to another unique name - Rename temporary to original - Unlink original - */ - /* - The jpeg standard does not regulate the contents of the COM block. - I'm assuming the best thing to do here is write as unicode utf-8, - which is fully backwards compatible with readers expecting ascii. - Readers expecting a national character set are out of luck... - */ - if( safe_copy_and_modify( TQFile::encodeName( path ), comment.utf8() ) ) { - return false; - } - return true; -} - -bool KJpegPlugin::readInfo( KFileMetaInfo& info, uint what ) -{ - const TQString path( info.path() ); - if ( path.isEmpty() ) // remote file - return false; - - TQString tag; - ExifData ImageInfo; - - // parse the jpeg file now - try { - if ( !ImageInfo.scan(info.path()) ) { - kdDebug(7034) << "Not a JPEG file!\n"; - return false; - } - } - catch (FatalError& e) { // malformed exif data? - kdDebug(7034) << "Exception caught while parsing Exif data of: " << info.path() << endl; - e.debug_print(); - return false; - } - - KFileMetaInfoGroup exifGroup = appendGroup( info, EXIFGROUP ); - - tag = ImageInfo.getComment(); - if ( tag.length() ) { - kdDebug(7034) << "exif inserting Comment: " << tag << "\n"; - appendItem( exifGroup, "Comment", tag ); - } else { - appendItem( exifGroup, "Comment", tag ); // So user can add new comment - } - - tag = ImageInfo.getCameraMake(); - if (tag.length()) - appendItem( exifGroup, "Manufacturer", tag ); - - tag = ImageInfo.getCameraModel(); - if (tag.length()) - appendItem( exifGroup, "Model", tag ); - - tag = ImageInfo.getDateTime(); - if (tag.length()){ - TQDateTime dt = parseDateTime( tag.stripWhiteSpace() ); - if ( dt.isValid() ) { - appendItem( exifGroup, "Date/time", dt ); - appendItem( exifGroup, "CreationDate", dt.date() ); - appendItem( exifGroup, "CreationTime", dt.time() ); - } - } - - appendItem( exifGroup,"Dimensions", TQSize( ImageInfo.getWidth(), - ImageInfo.getHeight() ) ); - - if ( ImageInfo.getOrientation() ) - appendItem( exifGroup, "Orientation", ImageInfo.getOrientation() ); - - appendItem( exifGroup, "ColorMode", ImageInfo.getIsColor() ? - i18n("Color") : i18n("Black and white") ); - - int flashUsed = ImageInfo.getFlashUsed(); // -1, <set> - if ( flashUsed >= 0 ) { - TQString flash = i18n("Flash", "(unknown)"); - switch ( flashUsed ) { - case 0: flash = i18n("Flash", "No"); - break; - case 1: - case 5: - case 7: - flash = i18n("Flash", "Fired"); - break; - case 9: - case 13: - case 15: - flash = i18n( "Flash", "Fill Fired" ); - break; - case 16: - flash = i18n( "Flash", "Off" ); - break; - case 24: - flash = i18n( "Flash", "Auto Off" ); - break; - case 25: - case 29: - case 31: - flash = i18n( "Flash", "Auto Fired" ); - break; - case 32: - flash = i18n( "Flash", "Not Available" ); - break; - default: - break; - } - appendItem( exifGroup, "Flash used", - flash ); - } - - if (ImageInfo.getFocalLength()){ - appendItem( exifGroup, "Focal length", - TQString(TQString().sprintf("%4.1f", ImageInfo.getFocalLength()) )); - - if (ImageInfo.getCCDWidth()){ - appendItem( exifGroup, "35mm equivalent", - (int)(ImageInfo.getFocalLength()/ImageInfo.getCCDWidth()*35 + 0.5) ); - } - } - - if (ImageInfo.getCCDWidth()){ - appendItem( exifGroup, "CCD width", - TQString(TQString().sprintf("%4.2f", ImageInfo.getCCDWidth()) )); - } - - if (ImageInfo.getExposureTime()){ - tag=TQString().sprintf("%6.3f", ImageInfo.getExposureTime()); - float exposureTime = ImageInfo.getExposureTime(); - if (exposureTime > 0 && exposureTime <= 0.5){ - tag+=TQString().sprintf(" (1/%d)", (int)(0.5 + 1/exposureTime) ); - } - appendItem( exifGroup, "Exposure time", tag ); - } - - if (ImageInfo.getApertureFNumber()){ - appendItem( exifGroup, "Aperture", - TQString(TQString().sprintf("f/%3.1f", - (double)ImageInfo.getApertureFNumber()))); - } - - if (ImageInfo.getDistance()){ - if (ImageInfo.getDistance() < 0){ - tag=i18n("Infinite"); - }else{ - tag=TQString().sprintf("%5.2fm",(double)ImageInfo.getDistance()); - } - appendItem( exifGroup, "Focus dist.", tag ); - } - - if (ImageInfo.getExposureBias()){ - appendItem( exifGroup, "Exposure bias", - TQString(TQString().sprintf("%4.2f", - (double)ImageInfo.getExposureBias()) )); - } - - if (ImageInfo.getWhitebalance() != -1){ - switch(ImageInfo.getWhitebalance()) { - case 0: - tag=i18n("Unknown"); - break; - case 1: - tag=i18n("Daylight"); - break; - case 2: - tag=i18n("Fluorescent"); - break; - case 3: - //tag=i18n("incandescent"); - tag=i18n("Tungsten"); - break; - case 17: - tag=i18n("Standard light A"); - break; - case 18: - tag=i18n("Standard light B"); - break; - case 19: - tag=i18n("Standard light C"); - break; - case 20: - tag=i18n("D55"); - break; - case 21: - tag=i18n("D65"); - break; - case 22: - tag=i18n("D75"); - break; - case 255: - tag=i18n("Other"); - break; - default: - //23 to 254 = reserved - tag=i18n("Unknown"); - } - appendItem( exifGroup, "Whitebalance", tag ); - } - - if (ImageInfo.getMeteringMode() != -1){ - switch(ImageInfo.getMeteringMode()) { - case 0: - tag=i18n("Unknown"); - break; - case 1: - tag=i18n("Average"); - break; - case 2: - tag=i18n("Center weighted average"); - break; - case 3: - tag=i18n("Spot"); - break; - case 4: - tag=i18n("MultiSpot"); - break; - case 5: - tag=i18n("Pattern"); - break; - case 6: - tag=i18n("Partial"); - break; - case 255: - tag=i18n("Other"); - break; - default: - // 7 to 254 = reserved - tag=i18n("Unknown"); - } - appendItem( exifGroup, "Metering mode", tag ); - } - - if (ImageInfo.getExposureProgram()){ - switch(ImageInfo.getExposureProgram()) { - case 0: - tag=i18n("Not defined"); - break; - case 1: - tag=i18n("Manual"); - break; - case 2: - tag=i18n("Normal program"); - break; - case 3: - tag=i18n("Aperture priority"); - break; - case 4: - tag=i18n("Shutter priority"); - break; - case 5: - tag=i18n("Creative program\n(biased toward fast shutter speed)"); - break; - case 6: - tag=i18n("Action program\n(biased toward fast shutter speed)"); - break; - case 7: - tag=i18n("Portrait mode\n(for closeup photos with the background out of focus)"); - break; - case 8: - tag=i18n("Landscape mode\n(for landscape photos with the background in focus)"); - break; - default: - // 9 to 255 = reserved - tag=i18n("Unknown"); - } - appendItem( exifGroup, "Exposure", tag ); - } - - if (ImageInfo.getISOequivalent()){ - appendItem( exifGroup, "ISO equiv.", - TQString(TQString().sprintf("%2d", - (int)ImageInfo.getISOequivalent()) )); - } - - if (ImageInfo.getCompressionLevel()){ - switch(ImageInfo.getCompressionLevel()) { - case 1: - tag=i18n("Basic"); - break; - case 2: - tag=i18n("Normal"); - break; - case 4: - tag=i18n("Fine"); - break; - default: - tag=i18n("Unknown"); - } - appendItem( exifGroup, "JPEG quality", tag ); - } - - tag = ImageInfo.getUserComment(); - if (tag.length()){ - appendItem( exifGroup, "EXIF comment", tag ); - } - - int a; - for (a=0;;a++){ - if (ProcessTable[a].Tag == ImageInfo.getProcess() || ProcessTable[a].Tag == 0){ - appendItem( exifGroup, "JPEG process", - TQString::fromUtf8( ProcessTable[a].Desc) ); - break; - } - } - - if ( what & KFileMetaInfo::Thumbnail && !ImageInfo.isNullThumbnail() ){ - appendItem( exifGroup, "Thumbnail", ImageInfo.getThumbnail() ); - } - - return true; -} - -// format of the string is: -// YYYY:MM:DD HH:MM:SS -TQDateTime KJpegPlugin::parseDateTime( const TQString& string ) -{ - TQDateTime dt; - if ( string.length() != 19 ) - return dt; - - TQString year = string.left( 4 ); - TQString month = string.mid( 5, 2 ); - TQString day = string.mid( 8, 2 ); - TQString hour = string.mid( 11, 2 ); - TQString minute = string.mid( 14, 2 ); - TQString seconds = string.mid( 17, 2 ); - - bool ok; - bool allOk = true; - int y = year.toInt( &ok ); - allOk &= ok; - - int mo = month.toInt( &ok ); - allOk &= ok; - - int d = day.toInt( &ok ); - allOk &= ok; - - int h = hour.toInt( &ok ); - allOk &= ok; - - int mi = minute.toInt( &ok ); - allOk &= ok; - - int s = seconds.toInt( &ok ); - allOk &= ok; - - if ( allOk ) { - dt.setDate( TQDate( y, mo, d ) ); - dt.setTime( TQTime( h, mi, s ) ); - } - - return dt; -} - -#include "kfile_jpeg.moc" diff --git a/kfile-plugins/jpeg/kfile_jpeg.desktop b/kfile-plugins/jpeg/kfile_jpeg.desktop deleted file mode 100644 index fccaaeff..00000000 --- a/kfile-plugins/jpeg/kfile_jpeg.desktop +++ /dev/null @@ -1,64 +0,0 @@ -[Desktop Entry] -Type=Service -Name=JPEG EXIF Info -Name[ar]=معلومات JPEG EXIF -Name[br]=Titouroù EXIF JPEG -Name[ca]=Informació de JPEG EXIF -Name[cs]=JPEG EXIF info -Name[cy]=Gwybodaeth JPEG EXIF -Name[da]=JPEG EXIF-info -Name[de]=JPEG EXIF-Info -Name[el]=Πληροφορίες JPEG EXIF -Name[eo]=JPEG-EXIF-informo -Name[es]=Info JPEG EXIF -Name[et]=JPEG EXIF info -Name[fa]=اطلاعات JPEG EXIF -Name[fi]=JPEG EXIF -tiedot -Name[fr]=Informations JPEG EXIF -Name[gl]=Inf. JPEG EXIF -Name[he]=מידע JPEG EXIF -Name[hi]=JPEG EXIF जानकारी -Name[hr]=JPEG EXIF Informacije -Name[hu]=JPEG EXIF-jellemzők -Name[is]=JPEG EXIF upplýsingar -Name[it]=Informazioni JPEG EXIF -Name[ja]=JPEG EXIF 情報 -Name[kk]=JPEG EXIF мәліметі -Name[km]=ព័ត៌មាន JPEG EXIF -Name[lt]=JPEG EXIF informacija -Name[ms]=Maklumat JPEG EXIF -Name[nds]=JPEG-EXIF-Info -Name[ne]=JPEG EXIF सूचना -Name[nl]=JPEG EXIF-info -Name[nn]=JPEG EXIF-info -Name[nso]=TshedimoJPEG EXIF Info -Name[pa]=JPEG EXIF ਜਾਣਕਾਰੀ -Name[pl]=Informacja o pliku JPEG EXIF -Name[pt]=Informação do JPEG EXIF -Name[pt_BR]=Informação sobre JPEG EXIF -Name[ro]=Informaţii EXIF JPEG -Name[ru]=Информация о JPEG EXIF -Name[se]=JPEG EXIF-dieđut -Name[sl]=Podatki o JPEG EXIF -Name[sr]=JPEG EXIF информације -Name[sr@Latn]=JPEG EXIF informacije -Name[sv]=JPEG EXIF-information -Name[ta]=JPEG EXIF தகவல் -Name[tg]=Иттилоот оиди JPEG EXIF -Name[th]=ข้อมูลแฟ้ม JPEG EXIF -Name[tr]=JPEG EXIF Bilgisi -Name[uk]=Інформація про JPEG EXIF -Name[uz]=JPEG EXIF haqida maʼlumot -Name[uz@cyrillic]=JPEG EXIF ҳақида маълумот -Name[ven]=Mafhungo a JPEG EXIF -Name[wa]=Informåcion sol imådje JPEG EXIF -Name[xh]=Ulwazi lwe JPEG EXIF -Name[zh_CN]=JPEG EXIF 信息 -Name[zh_HK]=JPEG EXIF 資訊 -Name[zh_TW]=JPEG EXIF 資訊 -Name[zu]=Ulwazi lwe-JPEG EXIF -ServiceTypes=KFilePlugin -X-TDE-Library=kfile_jpeg -MimeType=image/jpeg -PreferredItems=User comment,CreationDate,CreationTime,Dimensions,Exposure time,JPEG quality,Comment -SupportsThumbnail=true diff --git a/kfile-plugins/jpeg/kfile_jpeg.h b/kfile-plugins/jpeg/kfile_jpeg.h deleted file mode 100644 index e7c821a6..00000000 --- a/kfile-plugins/jpeg/kfile_jpeg.h +++ /dev/null @@ -1,44 +0,0 @@ -/* This file is part of the KDE project - * Copyright (C) 2002 Frank Pieczynski - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef __KFILE_JPEG_H__ -#define __KFILE_JPEG_H__ - -#include <tqdatetime.h> -#include <kfilemetainfo.h> - -class KJpegPlugin: public KFilePlugin -{ - Q_OBJECT - - -public: - KJpegPlugin( TQObject *parent, const char *name, - const TQStringList& args ); - - virtual bool readInfo ( KFileMetaInfo& info, uint what ); - virtual bool writeInfo( const KFileMetaInfo& info ) const; - virtual TQValidator* createValidator( const KFileMetaInfoItem& item, - TQObject* parent, const char* name) const; - -private: - TQDateTime parseDateTime( const TQString& string ); -}; - -#endif diff --git a/kfile-plugins/jpeg/kfile_setcomment.cpp b/kfile-plugins/jpeg/kfile_setcomment.cpp deleted file mode 100644 index 07dca273..00000000 --- a/kfile-plugins/jpeg/kfile_setcomment.cpp +++ /dev/null @@ -1,536 +0,0 @@ -/* - * setcomment.cpp - * - * Copyright 2002 Bryce Nesbitt - * - * Based on wrjpgcom.c, Copyright (C) 1994-1997, Thomas G. Lane. - * Part of the Independent JPEG Group's software release 6b of 27-Mar-1998 - * - * This file contains a very simple stand-alone application that inserts - * user-supplied text as a COM (comment) marker in a JPEG/JFIF file. - * This may be useful as an example of the minimum logic needed to parse - * JPEG markers. - * - * There can be an arbitrary number of COM blocks in each jpeg file, with - * up to 64K of data each. We, however, write just one COM and blow away - * the rest. - * - ***************** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#undef STANDALONE_COMPILE - -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <string.h> -#include "config.h" - -extern int safe_copy_and_modify( const char * original_filename, const char * comment ); - -#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ -#define READ_BINARY "r" -#define WRITE_BINARY "w" -#else -#ifdef VMS /* VMS is very nonstandard */ -#define READ_BINARY "rb", "ctx=stm" -#define WRITE_BINARY "wb", "ctx=stm" -#else /* standard ANSI-compliant case */ -#define READ_BINARY "rb" -#define WRITE_BINARY "wb" -#endif -#endif - -#define WARNING_GARBAGE 1 /* Original file had some unspecified content */ -#define ERROR_NOT_A_JPEG 5 /* Original file not a proper jpeg (must be 1st) */ -#define ERROR_TEMP_FILE 6 /* Problem writing temporay file */ -#define ERROR_SCREWUP 7 /* Original file is now damaged. Ooops. */ -#define ERROR_PREMATURE_EOF 8 /* Unexpected end of file */ -#define ERROR_BAD_MARKER 9 /* Marker with illegal length */ -#define ERROR_MARKER_ORDER 10 /* File seems to be mixed up */ - -static int global_error; /* global error flag. Once set, we're dead. */ - -/****************************************************************************/ -/* - * These macros are used to read the input file and write the output file. - * To reuse this code in another application, you might need to change these. - */ -static FILE * infile; /* input JPEG file */ - -/* Return next input byte, or EOF if no more */ -#define NEXTBYTE() getc(infile) - -static FILE * outfile; /* output JPEG file */ - -/* Emit an output byte */ -#define PUTBYTE(x) putc((x), outfile) - - -/****************************************************************************/ -/* Read one byte, testing for EOF */ -static int -read_1_byte (void) -{ - int c; - - c = NEXTBYTE(); - if (c == EOF) { - global_error = ERROR_PREMATURE_EOF; - } - return c; -} - -/* Read 2 bytes, convert to unsigned int */ -/* All 2-byte quantities in JPEG markers are MSB first */ -static unsigned int -read_2_bytes (void) -{ - int c1, c2; - - c1 = NEXTBYTE(); - if (c1 == EOF) - global_error = ERROR_PREMATURE_EOF; - c2 = NEXTBYTE(); - if (c2 == EOF) - global_error = ERROR_PREMATURE_EOF; - return (((unsigned int) c1) << 8) + ((unsigned int) c2); -} - - -/****************************************************************************/ -/* Routines to write data to output file */ -static void -write_1_byte (int c) -{ - PUTBYTE(c); -} - -static void -write_2_bytes (unsigned int val) -{ - PUTBYTE((val >> 8) & 0xFF); - PUTBYTE(val & 0xFF); -} - -static void -write_marker (int marker) -{ - PUTBYTE(0xFF); - PUTBYTE(marker); -} - -static void -copy_rest_of_file (void) -{ - int c; - - while ((c = NEXTBYTE()) != EOF) - PUTBYTE(c); -} - - -/****************************************************************************/ -/* - * JPEG markers consist of one or more 0xFF bytes, followed by a marker - * code byte (which is not an FF). Here are the marker codes of interest - * in this program. (See jdmarker.c for a more complete list.) - */ - -#define M_SOF0 0xC0 /* Start Of Frame N */ -#define M_SOF1 0xC1 /* N indicates which compression process */ -#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */ -#define M_SOF3 0xC3 -#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */ -#define M_SOF6 0xC6 -#define M_SOF7 0xC7 -#define M_SOF9 0xC9 -#define M_SOF10 0xCA -#define M_SOF11 0xCB -#define M_SOF13 0xCD -#define M_SOF14 0xCE -#define M_SOF15 0xCF -#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */ -#define M_EOI 0xD9 /* End Of Image (end of datastream) */ -#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */ -#define M_COM 0xFE /* COMment */ - - -/* - * Find the next JPEG marker and return its marker code. - * We expect at least one FF byte, possibly more if the compressor used FFs - * to pad the file. (Padding FFs will NOT be replicated in the output file.) - * There could also be non-FF garbage between markers. The treatment of such - * garbage is unspecified; we choose to skip over it but emit a warning msg. - * NB: this routine must not be used after seeing SOS marker, since it will - * not deal correctly with FF/00 sequences in the compressed image data... - */ -static int -next_marker (void) -{ - int c; - int discarded_bytes = 0; - - /* Find 0xFF byte; count and skip any non-FFs. */ - c = read_1_byte(); - while (c != 0xFF) { - discarded_bytes++; - c = read_1_byte(); - } - /* Get marker code byte, swallowing any duplicate FF bytes. Extra FFs - * are legal as pad bytes, so don't count them in discarded_bytes. - */ - do { - c = read_1_byte(); - } while (c == 0xFF); - - if (discarded_bytes != 0) { - global_error = WARNING_GARBAGE; - } - - return c; -} - - -/* - * Most types of marker are followed by a variable-length parameter segment. - * This routine skips over the parameters for any marker we don't otherwise - * want to process. - * Note that we MUST skip the parameter segment explicitly in order not to - * be fooled by 0xFF bytes that might appear within the parameter segment; - * such bytes do NOT introduce new markers. - */ -static void -copy_variable (void) -/* Copy an unknown or uninteresting variable-length marker */ -{ - unsigned int length; - - /* Get the marker parameter length count */ - length = read_2_bytes(); - write_2_bytes(length); - /* Length includes itself, so must be at least 2 */ - if (length < 2) { - global_error = ERROR_BAD_MARKER; - length = 2; - } - length -= 2; - /* Skip over the remaining bytes */ - while (length > 0) { - write_1_byte(read_1_byte()); - length--; - } -} - -static void -skip_variable (void) -/* Skip over an unknown or uninteresting variable-length marker */ -{ - unsigned int length; - - /* Get the marker parameter length count */ - length = read_2_bytes(); - /* Length includes itself, so must be at least 2 */ - if (length < 2) { - global_error = ERROR_BAD_MARKER; - length = 2; - } - length -= 2; - /* Skip over the remaining bytes */ - while (length > 0) { - (void) read_1_byte(); - length--; - } -} - - -static int -scan_JPEG_header (int keep_COM) -/* - * Parse & copy the marker stream until SOFn or EOI is seen; - * copy data to output, but discard COM markers unless keep_COM is true. - */ -{ - int c1, c2; - int marker; - - /* - * Read the initial marker, which should be SOI. - * For a JFIF file, the first two bytes of the file should be literally - * 0xFF M_SOI. To be more general, we could use next_marker, but if the - * input file weren't actually JPEG at all, next_marker might read the whole - * file and then return a misleading error message... - */ - c1 = NEXTBYTE(); - c2 = NEXTBYTE(); - if (c1 != 0xFF || c2 != M_SOI) { - global_error = ERROR_NOT_A_JPEG; - return EOF; - } - - write_marker(M_SOI); - - /* Scan miscellaneous markers until we reach SOFn. */ - for (;;) { - marker = next_marker(); - switch (marker) { - /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be, - * treated as SOFn. C4 in particular is actually DHT. - */ - case M_SOF0: /* Baseline */ - case M_SOF1: /* Extended sequential, Huffman */ - case M_SOF2: /* Progressive, Huffman */ - case M_SOF3: /* Lossless, Huffman */ - case M_SOF5: /* Differential sequential, Huffman */ - case M_SOF6: /* Differential progressive, Huffman */ - case M_SOF7: /* Differential lossless, Huffman */ - case M_SOF9: /* Extended sequential, arithmetic */ - case M_SOF10: /* Progressive, arithmetic */ - case M_SOF11: /* Lossless, arithmetic */ - case M_SOF13: /* Differential sequential, arithmetic */ - case M_SOF14: /* Differential progressive, arithmetic */ - case M_SOF15: /* Differential lossless, arithmetic */ - return marker; - - case M_SOS: /* should not see compressed data before SOF */ - global_error = ERROR_MARKER_ORDER; - break; - - case M_EOI: /* in case it's a tables-only JPEG stream */ - return marker; - - case M_COM: /* Existing COM: conditionally discard */ - if (keep_COM) { - write_marker(marker); - copy_variable(); - } else { - skip_variable(); - } - break; - - default: /* Anything else just gets copied */ - write_marker(marker); - copy_variable(); /* we assume it has a parameter count... */ - break; - } - } /* end loop */ -} - - -/****************************************************************************/ -/* - Verify we know how to set the comment on this type of file. - - TODO: The actual check! This should verify - the image size promised in the headers matches the file, - and that all markers are properly formatted. -*/ -static int validate_image_file( const char * filename ) -{ -int status = 1; -int c1, c2; - - if ( (infile = fopen(filename, READ_BINARY)) ) { - c1 = NEXTBYTE(); - c2 = NEXTBYTE(); - if (c1 != 0xFF || c2 != M_SOI) - status = ERROR_NOT_A_JPEG; - else - status = 0; - fclose( infile ); - } - return( status ); -} - - -/****************************************************************************/ -/* - Modify the file in place, but be paranoid and safe about it. - It's worth a few extra CPU cycles to make sure we never - destory an original image: - 1) Validate the input file. - 2) Open a temporary file. - 3) Copy the data, writing a new comment block. - 4) Validate the temporary file. - 5) Move the temporary file over the original. - - To be even more paranoid & safe we could: - 5) Rename the original to a different temporary name. - 6) Rename the temporary to the original. - 7) Delete the original. -*/ -extern int safe_copy_and_modify( const char * original_filename, const char * comment ) -{ -char * temp_filename; -int temp_filename_length; -int comment_length = 0; -int marker; -int i; -struct stat statbuf; - - global_error = 0; - - /* - * Make sure we're dealing with a proper input file. Safety first! - */ - if( validate_image_file( original_filename ) ) { - fprintf(stderr, "error validating original file %s\n", original_filename); - return(ERROR_NOT_A_JPEG); - } - - /* Get a unique temporary file in the same directory. Hopefully - * if things go wrong, this file will still be left for recovery purposes. - * - * NB: I hate these stupid string functions in C... the buffer length is too - * hard to manage... - */ - outfile = NULL; - temp_filename_length = strlen( original_filename) + 4; - temp_filename = (char *)calloc( temp_filename_length, 1 ); - for( i=0; i<10; i++ ) { - snprintf( temp_filename, temp_filename_length, "%s%d", original_filename, i ); - if( stat( temp_filename, &statbuf ) ) { - outfile = fopen(temp_filename, WRITE_BINARY); - break; - } - } - if( !outfile ) { - fprintf(stderr, "failed opening temporary file %s\n", temp_filename); - free(temp_filename); - return(ERROR_TEMP_FILE); - } - - - /* - * Let's rock and roll! - */ - if ((infile = fopen(original_filename, READ_BINARY)) == NULL) { - fprintf(stderr, "can't open input file %s\n", original_filename); - free(temp_filename); - return(ERROR_NOT_A_JPEG); - } - /* Copy JPEG headers until SOFn marker; - * we will insert the new comment marker just before SOFn. - * This (a) causes the new comment to appear after, rather than before, - * existing comments; and (b) ensures that comments come after any JFIF - * or JFXX markers, as required by the JFIF specification. - */ - marker = scan_JPEG_header(0); - /* Insert the new COM marker, but only if nonempty text has been supplied */ - if (comment) { - comment_length = strlen( comment ); - } - if (comment_length > 0) { - write_marker(M_COM); - write_2_bytes(comment_length + 2); - while (comment_length > 0) { - write_1_byte(*comment++); - comment_length--; - } - } - /* Duplicate the remainder of the source file. - * Note that any COM markers occurring after SOF will not be touched. - * - * :TODO: Discard COM markers occurring after SOF - */ - write_marker(marker); - copy_rest_of_file(); - fclose( infile ); - fsync( fileno( outfile) ); /* Make sure its really on disk first. !!!VERY IMPORTANT!!! */ - if ( fclose( outfile ) ) { - fprintf(stderr, "error in temporary file %s\n", temp_filename); - free(temp_filename); - return(ERROR_TEMP_FILE); - } - - - /* - * Make sure we did it right. We've already fsync()'ed the file. Safety first! - */ - if( validate_image_file( temp_filename ) ) { - fprintf(stderr, "error in temporary file %s\n", temp_filename); - free(temp_filename); - return(ERROR_TEMP_FILE); - } - - if( global_error >= ERROR_NOT_A_JPEG ) { - fprintf(stderr, "error %d processing %s\n", global_error, original_filename); - free(temp_filename); - return(ERROR_NOT_A_JPEG); - } - - if( rename( temp_filename, original_filename ) ) { - fprintf(stderr, "error renaming %s to %s\n", temp_filename, original_filename); - free(temp_filename); - return(ERROR_TEMP_FILE); - } - free(temp_filename); - - return(0); -} - - -#ifdef STANDALONE_COMPILE -int -main (int argc, char **argv) -{ - char * progname; /* program name for error messages */ - char * filename; - char * comment; - FILE * fp; - int error; - - /* Process command line arguments... */ - progname = argv[0]; - if (progname == NULL || progname[0] == 0) - progname = "writejpgcomment"; /* in case C library doesn't provide it */ - if( argc != 3) { - fprintf(stderr, "Usage: %s <filename> \"<comment>\"\nOverwrites the comment in a image file with the given comment.\n", progname); - return(5); - } - filename = argv[1]; - comment = argv[2]; - - - /* Check if file is readable... */ - if ((fp = fopen(filename, READ_BINARY)) == NULL) { - fprintf(stderr, "Error: Can't open file %s\n", filename); - fclose(fp); - return(5); - } - fclose(fp); - - /* Check if we really have a commentable image file here... */ - if( validate_image_file( filename ) ) { - fprintf(stderr, "Error: file %s is not of a supported type\n", filename); - return(5); - } - - /* Lets do it... modify the comment in place */ - if ((error = safe_copy_and_modify( filename, comment ) )) { - fprintf(stderr, "Error: %d setting jpg comment\n", error); - return(10); - } - - - /* TODO: Read comment back out of jpg and display it */ - return( 0 ); -} -#endif |