diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 47d455dd55be855e4cc691c32f687f723d9247ee (patch) | |
tree | 52e236aaa2576bdb3840ebede26619692fed6d7d /kfile-plugins | |
download | tdegraphics-47d455dd55be855e4cc691c32f687f723d9247ee.tar.gz tdegraphics-47d455dd55be855e4cc691c32f687f723d9247ee.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdegraphics@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kfile-plugins')
89 files changed, 10305 insertions, 0 deletions
diff --git a/kfile-plugins/Makefile.am b/kfile-plugins/Makefile.am new file mode 100644 index 00000000..92a6e911 --- /dev/null +++ b/kfile-plugins/Makefile.am @@ -0,0 +1,14 @@ +if include_EXR_MODULES +KFILE_EXR_SUBDIR=exr +endif + +if include_TIFF +KFILE_TIFF_SUBDIR=tiff +endif + +if include_PDF +KFILE_PDF_SUBDIR=pdf +endif + +SUBDIRS=dvi png ps jpeg xbm xpm bmp tga rgb ico pcx $(KFILE_TIFF_SUBDIR) pnm \ + $(KFILE_EXR_SUBDIR) $(KFILE_PDF_SUBDIR) dds gif raw diff --git a/kfile-plugins/RETURNED_ITEMS b/kfile-plugins/RETURNED_ITEMS new file mode 100644 index 00000000..593d466a --- /dev/null +++ b/kfile-plugins/RETURNED_ITEMS @@ -0,0 +1,245 @@ +If you make a new plugin, please add the list of returned items to this list. + + +pdf plugin: +=========== + +Date Created +Date Modiified +Int Pages +Bool Encrypted +and everything else pdfinfo returns as string + + +png plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +Size Dimensions -/- +Int BitDepth -/- +String ColorMode -/- +String Compression -/- Compression type. Right now always "deflate" + +Other keys corresponding to the png comment keys are returned as non-editable +String. + +Common keys that are recommended in the png spec: +Title, Author, Description, Copyright, Creation Time, Software, Disclaimer, +Warning, Source, Comment + + +PostScript plugin: +================== + +String Title +String Creator +String CreationDate +String For +Int Pages + + + +Jpeg plugin: +============ +Note: number.number means precision of converted number + +type key Comment +----------------------------------------------------------------------------- +String Camera make +String Camera model +String Date/time +Size Dimensions Width x Height in pixels +int Orientation 1 - "The 0th row is at the visual top of the image, + and the 0th column is the visual left-hand side." + 2 - "The 0th row is at the visual top of the image, + and the 0th column is the visual right-hand side." + 3 - "The 0th row is at the visual bottom of the image, + and the 0th column is the visual right-hand side." + 4 - "The 0th row is at the visual bottom of the image, + and the 0th column is the visual left-hand side." + 5 - "The 0th row is the visual left-hand side of of the image, + and the 0th column is the visual top." + 6 - "The 0th row is the visual right-hand side of of the image, + and the 0th column is the visual top." + 7 - "The 0th row is the visual right-hand side of of the image, + and the 0th column is the visual bottom." + 8 - "The 0th row is the visual left-hand side of of the image, + and the 0th column is the visual bottom." +String ColorMode "Grayscale" "Color" +String Flash used "Yes" "No" +String Focal length 4.1 mm, 35mm equivalent +String Exposure time 6.3 (if < 0.5 also in 1/xx) sec +String Aperture "f/3.1" +String Focus dist. "Infinite" or 5.2 m +String CCD width 4.2 Postfix mm +String Exposure bias 4.2 +String Whitebalance 0 = unknown + 1 = Daylight + 2 = Fluorescent + 3 = Tungsten + 17 = Standard light A + 18 = Standard light B + 19 = Standard light C + 20 = D55 + 21 = D65 + 22 = D75 + 23 to 254 = reserved + 255 = other +String Metering mode 0 = unknown + 1 = Average + 2 = CenterWeightedAverage + 3 = Spot + 4 = MultiSpot + 5 = Pattern + 6 = Partial + 7 to 254 = reserved + 255 = other +String Exposure 0 = Not defined + 1 = Manual + 2 = Normal program + 3 = Aperture priority + 4 = Shutter priority + 5 = Creative program (biased toward depth of field) + 6 = Action program + (biased toward fast shutter speed) + 7 = Portrait mode + (for closeup photos with the background out of focus) + 8 = Landscape mode + (for landscape photos with the background in focus) + 9 to 255 = reserved +String ISO equiv. 2digits ??? +String JPG quality 1 - "basic" + 2 - "normal" + 4 - "fine" + default: unknown +String User comment +String Comment +QImage Thumbnail + + +gif plugin: +=========== + +type key Comment +----------------------------------------------------------------------------- +Size Dimensions Width x Height in pixels. +String Comment gif comment blocks, which we permit to be utf-8 encoded + in clear violation/extension of the specification which + calls for 7 bit ASCII. See: + http://www.geocities.co.jp/SiliconValley/3453/gif_info/index_en.html + + +TIFF plugin: +=========== + +:: Group: General :: + +type key Comment +------ -------------- ----------------------------------------------------- +String ColorMode Color Mode (Monochrome, RGB, RGBA etc) +Size Dimensions Width & height as a QSize object +Size Resolution x & y resolution in dpi as a QSize object +Int BitDepth No. of bits per pixel (e.g. 24 for 8-bit RGB) +String Compression Compression used (None, Deflate, LZW, JPEG etc.) +Int FaxPages No. of pages if this is fax +String Software Software used to produce this image +String Description Image description +String Copyright Copyright information +String DateTime Date and time of image creation +String Artist Name of the person who created this image + +:: Group: Scanner :: + +type key Comment +------ -------------- ----------------------------------------------------- +String Make Make of the scanner used +String Model Model of the scanner used + + + + + +xbm plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +QSize Dimensions -/- Dimensions in pixels + +xpm plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +QSize Dimensions -/- Dimensions in pixels +Int BitDepth -/- Bits per pixel + + +bmp plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +String Type -/- Bitmap type (Windows / OS/2) +QSize Dimensions -/- Dimensions in pixels +Int BitDepth -/- Bits per pixel +String Compression -/- Compression type + + +tga plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +QSize Dimensions -/- Dimensions in pixels +Int BitDepth -/- Bits per pixel +String ColorMode -/- Color mode (e.g. RGB) +String Compression -/- Compression type, if any + + +ico plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +Int Number -/- Number of icons in file +QSize Dimensions -/- Dimensions +QSize DimensionsM -/- Dimensions [of 1st icon] +Int Colors -/- Number of colors [in 1st icon] + +pcx plugin: +=========== + +type key W/A details +------------------------------------------------------------------------ +QSize Dimensions -/- Dimensions in pixels +Int BitDepth -/- Bits per pixel +QSize Resolution -/- Resolution in DPI +String Compression -/- Compression type, if any + + +rgb plugin: +=========== + +type key details +------------------------------------------------------------------------ +String ImageName Image name (or comment) +QSize Dimensions Dimensions in pixels +Int BitDepth Bits per pixel +String ColorMode Color Mode (Monochrome, RGB, RGBA etc) +String Compression Compression type +String SharedRows Percentage of shared rows + (amount of "aggression" -> see GIMP) +dds plugin: +=========== + +type key details +------------------------------------------------------------------------ +QSize Dimensions Dimensions in pixels +Int Depth Depth in pixels +Int BitDepth Bits per pixel +String ColorMode Color Mode (RGB, RGBA) +String Type 2D, volume or cube map +String Compression Compression type + diff --git a/kfile-plugins/bmp/Makefile.am b/kfile-plugins/bmp/Makefile.am new file mode 100644 index 00000000..dbaa8ff2 --- /dev/null +++ b/kfile-plugins/bmp/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for bmp file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_bmp.h + +kde_module_LTLIBRARIES = kfile_bmp.la + +kfile_bmp_la_SOURCES = kfile_bmp.cpp +kfile_bmp_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_bmp_la_LIBADD = $(LIB_KSYCOCA) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_bmp.cpp -o $(podir)/kfile_bmp.pot + +services_DATA = kfile_bmp.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/bmp/kfile_bmp.cpp b/kfile-plugins/bmp/kfile_bmp.cpp new file mode 100644 index 00000000..b9d6a7ad --- /dev/null +++ b/kfile-plugins/bmp/kfile_bmp.cpp @@ -0,0 +1,174 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk> + * + * 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 <config.h> +#include "kfile_bmp.h" + +#include <kprocess.h> +#include <klocale.h> +#include <kgenericfactory.h> +#include <kstringvalidator.h> +#include <kdebug.h> + +#include <qdict.h> +#include <qvalidator.h> +#include <qcstring.h> +#include <qfile.h> +#include <qdatetime.h> + +#if !defined(__osf__) +#include <inttypes.h> +#else +typedef unsigned long uint32_t; +typedef unsigned short uint16_t; +#endif + +typedef KGenericFactory<KBmpPlugin> BmpFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_bmp, BmpFactory( "kfile_bmp" )) + +KBmpPlugin::KBmpPlugin(QObject *parent, const char *name, + const QStringList &args) + + : KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-bmp" ); + + KFileMimeTypeInfo::GroupInfo* group = 0L; + + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo(group, "Type", i18n("Type"), QVariant::String); + + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit(item, KFileMimeTypeInfo::Pixels); + + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); + + item = addItemInfo(group, "Compression", i18n("Compression"), QVariant::String); + +} + + +bool KBmpPlugin::readInfo( KFileMetaInfo& info, uint what) +{ + const char * bmptype_bm = "BM"; + const char * bmptype_ba = "BA"; + const char * bmptype_ci = "CI"; + const char * bmptype_cp = "CP"; + const char * bmptype_ic = "IC"; + const char * bmptype_pt = "PT"; + + QFile file(info.path()); + + if (!file.open(IO_ReadOnly)) + { + kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + QDataStream dstream(&file); + + // BMP files are little-endian + dstream.setByteOrder(QDataStream::LittleEndian); + + // create this now because we output image type early on + KFileMetaInfoGroup group = appendGroup(info, "Technical"); + + + // read the beginning of the file and make sure it looks ok + unsigned char * bmp_id = (unsigned char *) malloc(2); + file.readBlock((char *) bmp_id, 2); + + if (memcmp(bmp_id, bmptype_bm, 2) == 0) { + appendItem(group, "Type", i18n("Windows Bitmap")); + } else if (memcmp(bmp_id, bmptype_ba, 2) == 0) { + appendItem(group, "Type", i18n("OS/2 Bitmap Array")); + } else if (memcmp(bmp_id, bmptype_ci, 2) == 0) { + appendItem(group, "Type", i18n("OS/2 Color Icon")); + } else if (memcmp(bmp_id, bmptype_cp, 2) == 0) { + appendItem(group, "Type", i18n("OS/2 Color Pointer")); + } else if (memcmp(bmp_id, bmptype_ic, 2) == 0) { + appendItem(group, "Type", i18n("OS/2 Icon")); + } else if (memcmp(bmp_id, bmptype_pt, 2) == 0) { + appendItem(group, "Type", i18n("OS/2 Pointer")); + } else { + return false; + } + + free(bmp_id); + + + // read the next bits, we ignore them, but anyways... + uint32_t bmp_size; + uint16_t bmp_reserved1; + uint16_t bmp_reserved2; + uint32_t bmp_offbits; + + dstream >> bmp_size; + dstream >> bmp_reserved1; + dstream >> bmp_reserved2; + dstream >> bmp_offbits; + + + // we should now be at the file info structure + uint32_t bmpi_size; + uint32_t bmpi_width; + uint32_t bmpi_height; + uint16_t bmpi_planes; + uint16_t bmpi_bitcount; + uint32_t bmpi_compression; + + dstream >> bmpi_size; + dstream >> bmpi_width; + dstream >> bmpi_height; + dstream >> bmpi_planes; + dstream >> bmpi_bitcount; + dstream >> bmpi_compression; + + + // output the useful bits + appendItem(group, "Dimensions", QSize(bmpi_width, bmpi_height)); + appendItem(group, "BitDepth", bmpi_bitcount); + + switch (bmpi_compression) { + case 0 : + appendItem(group, "Compression", i18n("None")); + break; + case 1 : + appendItem(group, "Compression", i18n("RLE 8bit/pixel")); + break; + case 2 : + appendItem(group, "Compression", i18n("RLE 4bit/pixel")); + break; + case 3 : + appendItem(group, "Compression", i18n("Bitfields")); + break; + default : + appendItem(group, "Compression", i18n("Unknown")); + } + + return true; +} + +#include "kfile_bmp.moc" diff --git a/kfile-plugins/bmp/kfile_bmp.desktop b/kfile-plugins/bmp/kfile_bmp.desktop new file mode 100644 index 00000000..37b44b42 --- /dev/null +++ b/kfile-plugins/bmp/kfile_bmp.desktop @@ -0,0 +1,66 @@ +[Desktop Entry] +Type=Service +Name=BMP Info +Name[af]=Bmp Inligting +Name[ar]=معلومات BMP +Name[br]=Titouroù BMP +Name[ca]=Informació de BMP +Name[cs]=BMP info +Name[cy]=Gwybodaeth BMP +Name[da]=BMP-info +Name[de]=BMP-Info +Name[el]=Πληροφορίες BMP +Name[eo]=BMP-informo +Name[es]=Info BMP +Name[et]=BMP info +Name[fa]=اطلاعات BMP +Name[fi]=BMP-tiedot +Name[fr]=Informations BMP +Name[ga]=Eolas faoi BMP +Name[gl]=Inf. BMP +Name[he]=מידע BMP +Name[hi]=BMP जानकारी +Name[hr]=BMP informacije +Name[hu]=BMP-jellemzők +Name[is]=BMP upplýsingar +Name[it]=Informazioni BMP +Name[ja]=BMP 情報 +Name[kk]=BMP мәліметі +Name[km]=ព័ត៌មាន BMP +Name[lt]=BMP informacija +Name[ms]=Maklumat BMP +Name[nds]=BMP-Info +Name[ne]=BMP सूचना +Name[nl]=BMP-info +Name[nn]=BMP-info +Name[nso]=Tshedimoso ya BMP +Name[pa]=BMP ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku BMP +Name[pt]=Informação do BMP +Name[pt_BR]=Informação sobre BMP +Name[ro]=Informaţii BMP +Name[ru]=Информация о BMP +Name[se]=BMP-dieđut +Name[sl]=Podatki o BMP +Name[sr]=BMP информације +Name[sr@Latn]=BMP informacije +Name[sv]=BMP-information +Name[ta]=BMP தகவல் +Name[tg]=Иттилоот оиди BMP +Name[th]=ข้อมูลแฟ้ม BMP +Name[tr]=BMP Bilgisi +Name[uk]=Інформація по BMP +Name[uz]=BMP haqida maʼlumot +Name[uz@cyrillic]=BMP ҳақида маълумот +Name[ven]=Mafhungo BMP +Name[wa]=Informåcion sol imådje BMP +Name[xh]=Ulwazi lwe BMP +Name[zh_CN]=BMP 信息 +Name[zh_HK]=BMP 資訊 +Name[zh_TW]=BMP 資訊 +Name[zu]=Ulwazi lwe-BMP +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_bmp +MimeType=image/x-bmp +PreferredGroups=Technical +PreferredItems=Type,Resolution,Bitdepth,Compression diff --git a/kfile-plugins/bmp/kfile_bmp.h b/kfile-plugins/bmp/kfile_bmp.h new file mode 100644 index 00000000..b72ee16d --- /dev/null +++ b/kfile-plugins/bmp/kfile_bmp.h @@ -0,0 +1,37 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk> + * + * 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_BMP_H__ +#define __KFILE_BMP_H__ + +#include <kfilemetainfo.h> + +class QStringList; + +class KBmpPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KBmpPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); +}; + +#endif diff --git a/kfile-plugins/configure.in.bot b/kfile-plugins/configure.in.bot new file mode 100644 index 00000000..47308e8b --- /dev/null +++ b/kfile-plugins/configure.in.bot @@ -0,0 +1,32 @@ +if test -z "$LIBTIFF"; then + echo "" + echo "You're missing libtiff. The additional info plugin for TIFF images" + echo "files won't be compiled without libtiff." + echo "You can download it from http://www.libtiff.org" + echo "" + all_tests=bad +fi + +if test -z "$POPPLER_LIBS"; then + echo "" + echo "You're missing poppler. The additional info plugin for PDF files" + echo "files won't be compiled without poppler >= 0.3.1." + echo "You can download poppler from http://poppler.freedesktop.org/" + echo "" +fi + +if test "$EXRSTATUS" = "no"; then + echo "" + echo "No OpenEXR Libraries were found" + echo "Install the OpenEXR package (from http://www.openexr.org)" + echo "if you want EXR image format support" + echo "" +fi + +if test "$EXRSTATUS" = "old"; then + echo "" + echo "OpenEXR libraries were found, but at least version 1.1.0 is required" + echo "Install a newer OpenEXR package (from http://www.openexr.org)" + echo "if you want EXR image format support" + echo "" +fi diff --git a/kfile-plugins/dds/Makefile.am b/kfile-plugins/dds/Makefile.am new file mode 100644 index 00000000..c3e0382a --- /dev/null +++ b/kfile-plugins/dds/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for dds file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_dds.h + +kde_module_LTLIBRARIES = kfile_dds.la + +kfile_dds_la_SOURCES = kfile_dds.cpp +kfile_dds_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_dds_la_LIBADD = $(LIB_KSYCOCA) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_dds.cpp -o $(podir)/kfile_dds.pot + +services_DATA = kfile_dds.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/dds/kfile_dds.cpp b/kfile-plugins/dds/kfile_dds.cpp new file mode 100644 index 00000000..dd7f8f1e --- /dev/null +++ b/kfile-plugins/dds/kfile_dds.cpp @@ -0,0 +1,317 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Ignacio Castao <castano@ludicon.com> + * + * 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 <config.h> +#include "kfile_dds.h" + +#include <kprocess.h> +#include <klocale.h> +#include <kgenericfactory.h> +#include <kstringvalidator.h> +#include <kdebug.h> + +#include <qdict.h> +#include <qvalidator.h> +#include <qcstring.h> +#include <qfile.h> +#include <qdatetime.h> + + +typedef KGenericFactory<KDdsPlugin> DdsFactory; + +typedef Q_UINT32 uint; +typedef Q_UINT16 ushort; +typedef Q_UINT8 uchar; + +namespace { // Private. + +#if !defined(MAKEFOURCC) +# define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + (uint(uchar(ch0)) | (uint(uchar(ch1)) << 8) | \ + (uint(uchar(ch2)) << 16) | (uint(uchar(ch3)) << 24 )) +#endif + + static const uint FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' '); + static const uint FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1'); + static const uint FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2'); + static const uint FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3'); + static const uint FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4'); + static const uint FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5'); + static const uint FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B'); + + static const uint DDSD_CAPS = 0x00000001l; + static const uint DDSD_PIXELFORMAT = 0x00001000l; + static const uint DDSD_WIDTH = 0x00000004l; + static const uint DDSD_HEIGHT = 0x00000002l; + static const uint DDSD_PITCH = 0x00000008l; + + static const uint DDSCAPS_TEXTURE = 0x00001000l; + static const uint DDSCAPS2_VOLUME = 0x00200000l; + static const uint DDSCAPS2_CUBEMAP = 0x00000200l; + + static const uint DDPF_RGB = 0x00000040l; + static const uint DDPF_FOURCC = 0x00000004l; + static const uint DDPF_ALPHAPIXELS = 0x00000001l; + + enum DDSType { + DDS_A8R8G8B8 = 0, + DDS_A1R5G5B5 = 1, + DDS_A4R4G4B4 = 2, + DDS_R8G8B8 = 3, + DDS_R5G6B5 = 4, + DDS_DXT1 = 5, + DDS_DXT2 = 6, + DDS_DXT3 = 7, + DDS_DXT4 = 8, + DDS_DXT5 = 9, + DDS_RXGB = 10, + DDS_UNKNOWN + }; + + + struct DDSPixelFormat { + uint size; + uint flags; + uint fourcc; + uint bitcount; + uint rmask; + uint gmask; + uint bmask; + uint amask; + }; + + QDataStream & operator>> ( QDataStream & s, DDSPixelFormat & pf ) + { + s >> pf.size; + s >> pf.flags; + s >> pf.fourcc; + s >> pf.bitcount; + s >> pf.rmask; + s >> pf.gmask; + s >> pf.bmask; + s >> pf.amask; + return s; + } + + struct DDSCaps { + uint caps1; + uint caps2; + uint caps3; + uint caps4; + }; + + QDataStream & operator>> ( QDataStream & s, DDSCaps & caps ) + { + s >> caps.caps1; + s >> caps.caps2; + s >> caps.caps3; + s >> caps.caps4; + return s; + } + + struct DDSHeader { + uint size; + uint flags; + uint height; + uint width; + uint pitch; + uint depth; + uint mipmapcount; + uint reserved[11]; + DDSPixelFormat pf; + DDSCaps caps; + uint notused; + }; + + QDataStream & operator>> ( QDataStream & s, DDSHeader & header ) + { + s >> header.size; + s >> header.flags; + s >> header.height; + s >> header.width; + s >> header.pitch; + s >> header.depth; + s >> header.mipmapcount; + for( int i = 0; i < 11; i++ ) { + s >> header.reserved[i]; + } + s >> header.pf; + s >> header.caps; + s >> header.notused; + return s; + } + + static bool IsValid( const DDSHeader & header ) + { + if( header.size != 124 ) { + return false; + } + const uint required = (DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT); + if( (header.flags & required) != required ) { + return false; + } + if( header.pf.size != 32 ) { + return false; + } + if( !(header.caps.caps1 & DDSCAPS_TEXTURE) ) { + return false; + } + return true; + } + +} // namespace + + + +K_EXPORT_COMPONENT_FACTORY(kfile_dds, DdsFactory( "kfile_dds" )) + +// Constructor, init mime type info. +KDdsPlugin::KDdsPlugin(QObject *parent, const char *name, const QStringList &args) : + KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo * info = addMimeTypeInfo( "image/x-dds" ); + + KFileMimeTypeInfo::GroupInfo * group = 0L; + + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + KFileMimeTypeInfo::ItemInfo * item; + + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size); + setHint(item, KFileMimeTypeInfo::Size); + setUnit(item, KFileMimeTypeInfo::Pixels); + + item = addItemInfo(group, "Depth", i18n("Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::Pixels); + + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); + + addItemInfo(group, "MipmapCount", i18n("Mipmap Count"), QVariant::Int); + + addItemInfo(group, "Type", i18n("Type"), QVariant::String); + addItemInfo(group, "ColorMode", i18n("Color Mode"), QVariant::String); + addItemInfo(group, "Compression", i18n("Compression"), QVariant::String); +} + +// Read mime type info. +bool KDdsPlugin::readInfo( KFileMetaInfo& info, uint /*what*/) +{ + QFile file(info.path()); + + if (!file.open(IO_ReadOnly)) { + kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + QDataStream s(&file); + s.setByteOrder(QDataStream::LittleEndian); + + // Validate header. + uint fourcc; + s >> fourcc; + if( fourcc != FOURCC_DDS ) { + kdDebug(7034) << QFile::encodeName(info.path()) << " is not a DDS file." << endl; + return false; + } + + // Read image header. + DDSHeader header; + s >> header; + + // Check image file format. + if( s.atEnd() || !IsValid( header ) ) { + kdDebug(7034) << QFile::encodeName(info.path()) << " is not a valid DDS file." << endl; + return false; + } + + // Set file info. + KFileMetaInfoGroup group = appendGroup(info, "Technical"); + appendItem(group, "Dimensions", QSize(header.width, header.height)); + appendItem(group, "MipmapCount", header.mipmapcount); + + // Set file type. + if( header.caps.caps2 & DDSCAPS2_CUBEMAP ) { + appendItem(group, "Type", i18n("Cube Map Texture")); + } + else if( header.caps.caps2 & DDSCAPS2_VOLUME ) { + appendItem(group, "Type", i18n("Volume Texture")); + appendItem(group, "Depth", header.depth); + } + else { + appendItem(group, "Type", i18n("2D Texture")); + } + + // Set file color depth and compression. + if( header.pf.flags & DDPF_RGB ) { + appendItem(group, "BitDepth", header.pf.bitcount); + appendItem(group, "Compression", i18n("Uncompressed")); + if( header.pf.flags & DDPF_ALPHAPIXELS ) { + appendItem(group, "ColorMode", "RGB/Alpha"); + } + else { + appendItem(group, "ColorMode", "RGB"); + } + } + else if( header.pf.flags & DDPF_FOURCC ) { + switch( header.pf.fourcc ) { + case FOURCC_DXT1: + appendItem(group, "BitDepth", 4); + appendItem(group, "Compression", "DXT1"); + appendItem(group, "ColorMode", "RGB"); + break; + case FOURCC_DXT2: + appendItem(group, "BitDepth", 16); + appendItem(group, "Compression", "DXT2"); + appendItem(group, "ColorMode", "RGB/Alpha"); + break; + case FOURCC_DXT3: + appendItem(group, "BitDepth", 16); + appendItem(group, "Compression", "DXT3"); + appendItem(group, "ColorMode", "RGB/Alpha"); + break; + case FOURCC_DXT4: + appendItem(group, "BitDepth", 16); + appendItem(group, "Compression", "DXT4"); + appendItem(group, "ColorMode", "RGB/Alpha"); + break; + case FOURCC_DXT5: + appendItem(group, "BitDepth", 16); + appendItem(group, "Compression", "DXT5"); + appendItem(group, "ColorMode", "RGB/Alpha"); + break; + case FOURCC_RXGB: + appendItem(group, "BitDepth", 16); + appendItem(group, "Compression", "RXGB"); + appendItem(group, "ColorMode", "RGB"); + break; + default: + appendItem(group, "Compression", "Unknown"); + break; + } + } + else { + appendItem(group, "Compression", "Unknown"); + } + + return true; +} + +#include "kfile_dds.moc" + diff --git a/kfile-plugins/dds/kfile_dds.desktop b/kfile-plugins/dds/kfile_dds.desktop new file mode 100644 index 00000000..f6b4ae02 --- /dev/null +++ b/kfile-plugins/dds/kfile_dds.desktop @@ -0,0 +1,53 @@ +[Desktop Entry] +Type=Service +Name=DirectDraw Surface Info +Name[ca]=Informació de superfície DirectDraw +Name[cs]=DirectDraw Surface info +Name[da]=DirectDraw overflade-info +Name[de]=DirectDraw Oberflächeninfo +Name[el]=Πληροφορίες επιφάνειας DirectDraw +Name[eo]=DirectDraw surfac-informo +Name[es]=Información de la primera vista de DirectDraw +Name[et]=DirectDraw Surface'i info +Name[eu]=DirectDraw Surface informazioa +Name[fa]=اطلاعات سطح DirectDraw +Name[fi]=DirectDraw pintatieto +Name[fr]=Informations de surface DirectDraw +Name[ga]=Eolas faoi DirectDraw Surface +Name[gl]=Información de Superficie de DirectDraw +Name[he]=מיגע אודות משטח DirectDraw +Name[hu]=DirectDraw felületinformáció +Name[is]=DirectDraw yfirborðs upplýsingar +Name[it]=Informazioni superficie DirectDraw +Name[ja]=DDS (DirectDraw Surface) 情報 +Name[kk]=DirectDraw бедерінің мәлметі +Name[km]=ព័ត៌មានផ្ទៃខាងក្រៅអំពី DirectDraw +Name[lt]=DirectDraw Surface informacija +Name[ms]=Maklumat Permukaan LukisTerus +Name[nb]=DirectDraw Overflate info +Name[nds]="DirectDraw"-Böversietinfo +Name[ne]=प्रत्यक्ष रेखाचित्र सतह सूचना +Name[nl]=DirectDraw Surface-info +Name[nn]=DirectDraw-overflateinfo +Name[pl]=Informacja o powierzchni DirectDraw +Name[pt]=Informação de Superfície DirectDraw +Name[pt_BR]=Informações Sobre Superfícies Direct Draw +Name[ro]=Informaţii Suprafaţă DirectDraw +Name[ru]=Сведения о поверхности DirectDraw +Name[sk]=DirectDraw informácie o povrchu +Name[sl]=Podatki o površini DirectDraw +Name[sr]=Информације о DirectDraw површини +Name[sr@Latn]=Informacije o DirectDraw površini +Name[sv]=Directdraw ytinformation +Name[ta]=நேரடி மேற்பரப்பு தகவல் +Name[th]=ข้อมูลแฟ้มพื้นผิว DirectDraw +Name[tr]=DirectDraw Yüzey Bilgisi +Name[uk]=Інформація про поверхню DirectDraw +Name[zh_CN]=DirectDraw 表面信息 +Name[zh_HK]=DirectDraw 表面資訊 +Name[zh_TW]=DirectDraw Surface 資訊 +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_dds +MimeType=image/x-dds +PreferredGroups=Technical +PreferredItems=Dimensions,Depth,BitDepth,Type,ColorMode,Compression diff --git a/kfile-plugins/dds/kfile_dds.h b/kfile-plugins/dds/kfile_dds.h new file mode 100644 index 00000000..342581bb --- /dev/null +++ b/kfile-plugins/dds/kfile_dds.h @@ -0,0 +1,37 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Ignacio Castao <castano@ludicon.com> + * + * 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_DDS_H__ +#define __KFILE_DDS_H__ + +#include <kfilemetainfo.h> + +class QStringList; + +class KDdsPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KDdsPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); +}; + +#endif diff --git a/kfile-plugins/dvi/Makefile.am b/kfile-plugins/dvi/Makefile.am new file mode 100644 index 00000000..61791bdc --- /dev/null +++ b/kfile-plugins/dvi/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for the dvi file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_dvi.h + +kde_module_LTLIBRARIES = kfile_dvi.la + +kfile_dvi_la_SOURCES = kfile_dvi.cpp +kfile_dvi_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_dvi_la_LIBADD = $(LIB_KIO) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_dvi.pot + +services_DATA = kfile_dvi.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/dvi/kfile_dvi.cpp b/kfile-plugins/dvi/kfile_dvi.cpp new file mode 100644 index 00000000..4140b98b --- /dev/null +++ b/kfile-plugins/dvi/kfile_dvi.cpp @@ -0,0 +1,150 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Matthias Witzgall <witzi@gmx.net> + * + * 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. + * + */ + + +/* further informations about the dvi file format could be downloaded from: http://www.rpi.edu/~sofkam/DVI/archive/standards/dvistd0.dvi */ + +#include "kfile_dvi.h" + +#include <kgenericfactory.h> +#include <kdebug.h> +#include <klocale.h> +#include <kfilemetainfo.h> + +#include <qstring.h> +#include <qvariant.h> +#include <qdatetime.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qregexp.h> + + +// preprocessormacro K_EXPORT_COMPONENT_FACTORY loads shared library 'kfile_dvi.so' dynamic if necessary +typedef KGenericFactory<KDviPlugin> DviFactory; +K_EXPORT_COMPONENT_FACTORY(kfile_dvi, DviFactory("kfile_dvi")) + +KDviPlugin::KDviPlugin (QObject * parent, const char * name, const QStringList & preferredItems) + : KFilePlugin(parent, name, preferredItems) +{ + kdDebug(7034) << "dvi plugin" << endl; + + // set up our mime type + KFileMimeTypeInfo * info = this->addMimeTypeInfo("application/x-dvi"); + + + KFileMimeTypeInfo::GroupInfo * group = this->addGroupInfo(info, "General", "General"); + + this->addItemInfo(group, "3_Created", i18n("Created"), QVariant::String); + this->addItemInfo(group, "6_Comment", i18n("Comment"), QVariant::String); + this->addItemInfo(group, "7_Pages", i18n("Pages"), QVariant::UInt); +} + +bool KDviPlugin::readInfo (KFileMetaInfo & info, uint /* what (unused in this plugin) */) +{ + if ( info.path().isEmpty() ) + return false; + KFileMetaInfoGroup GeneralGroup = appendGroup(info, "General"); + QFile f(info.path()); + QFileInfo f_info; + Q_UINT16 bytes_to_read; + Q_UINT8 comment_length; + QString comment; + Q_UINT16 pages; + Q_UINT8 buffer[270]; // buffer for reading data; no data is read with more than 270 bytes + Q_UINT32 ptr; + int i; // running index + + // open file and try to get the comment + f.open(IO_ReadOnly); + + if ( f.isOpen() == false ){ + kdDebug(7034) << "cannot open file" << endl; + return false; + } + + f_info.setFile(f); // create fileinfoobject + bytes_to_read = QMIN(f_info.size(), 270); // check, if the file size is smaller than 270 bytes + // (if the comment is as large as possible, we don't have to + // read more than 270 bytes) + + if ( f.readBlock((char *)buffer, bytes_to_read) != bytes_to_read ){ // cast to (char *) is necessary + kdDebug(7034) << "read error (1)" << endl; + return false; + } + + if ( (buffer[0] != 247) || (buffer[1] != 2) ){ + // magic numbers are not right + kdDebug(7034) << "wrong file format" << endl;; + return false; + } + + comment_length = buffer[14]; // set up length of comment + comment.setLength(comment_length); // used to avoid permanent reallocation when extracting the comment from buffer + + for ( i = 15; i <= 14+comment_length; ++i ) // extract comment from buffer + comment[i-15] = (char)buffer[i]; + + appendItem(GeneralGroup, "6_Comment", comment.simplifyWhiteSpace() ); + + // comment is ok, now get total number of pages + f.at( f.size() - 13); + if ( f.readBlock((char *)buffer, 13) != 13 ){ + kdDebug(7034) << "read error (2)" << endl; + return false; + } + + i = 12; // reset running index i + while ( buffer[i] == 223 ){ --i; } // skip all trailing bytes + + if ( (buffer[i] != 2) || (i > 8) || (i < 5) ){ + kdDebug(7034) << "wrong file formatx" << endl; + return false; + } + + // now we know the position of the pointer to the beginning of the postamble and we can read it + ptr = buffer[i-4]; + ptr = (ptr << 8) | buffer[i-3]; + ptr = (ptr << 8) | buffer[i-2]; + ptr = (ptr << 8) | buffer[i-1]; + + // bytes for total number of pages have a offset of 27 to the beginning of the postamble + f.at(ptr + 27); + + // now read total number of pages from file + if ( f.readBlock((char *)buffer, 2) != 2 ){ + kdDebug(7034) << "read error (3)" << endl; + return false; + } + pages = buffer[0]; + pages = (pages << 8) | buffer[1]; + + appendItem(GeneralGroup, "7_Pages", QVariant(pages) ); + + f.close(); + + // now get and set up some basic informations about the file (same informations would be displayed, if there is no dvi-plugin) + appendItem(GeneralGroup, "1_Type", QVariant( i18n("TeX Device Independent file") ) ); // set up type of file + + appendItem(GeneralGroup, "4_Modified", QVariant(f_info.lastModified().toString("yyyy-MM-dd hh:mm")) ); + // ISO 8601 date format (without seconds) + + return true; +} + +#include "kfile_dvi.moc" diff --git a/kfile-plugins/dvi/kfile_dvi.desktop b/kfile-plugins/dvi/kfile_dvi.desktop new file mode 100644 index 00000000..ed640afb --- /dev/null +++ b/kfile-plugins/dvi/kfile_dvi.desktop @@ -0,0 +1,60 @@ +[Desktop Entry] +Icon= +MimeType=application/x-dvi +Name=DVI Info +Name[ar]=معلومات DVI +Name[br]=Titouroù DVI +Name[ca]=Informació de DVI +Name[cs]=DVI info +Name[cy]=Gwybodaeth DVI +Name[da]=DVI-info +Name[de]=DVI-Info +Name[el]=Πληροφορίες DVI +Name[eo]=DVI-informo +Name[es]=Info DVI +Name[et]=DVI info +Name[fa]=اطلاعات DVI +Name[fi]=DVI-tiedot +Name[fr]=Informations DVI +Name[ga]=Eolas faoi DVI +Name[gl]=Inf. DVI +Name[he]=מידע DVI +Name[hi]=DVI जानकारी +Name[hu]=DVI-jellemzők +Name[is]=DVI upplýsingar +Name[it]=Informazioni DVI +Name[ja]=DVI 情報 +Name[kk]=DVI мәліметі +Name[km]=ព័ត៌មាន DVI +Name[lt]=DVI informacija +Name[ms]=Maklumat DVI +Name[nds]=DVI-Info +Name[ne]=DVI सूचना +Name[nl]=DVI-info +Name[nn]=DVI-info +Name[pa]=DVI ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku DVI +Name[pt]=Informação do DVI +Name[pt_BR]=Informação sobre DVI +Name[ro]=Informaţii DVI +Name[ru]=Информация о DVI +Name[se]=DVI-dieđut +Name[sl]=Podatki o DVI +Name[sr]=DVI информације +Name[sr@Latn]=DVI informacije +Name[sv]=DVI-information +Name[ta]=DVI தகவல் +Name[tg]=Иттилоот оиди DVI +Name[th]=ข้อมูลแฟ้ม DVI +Name[tr]=DVI Bilgisi +Name[uk]=Інформація по DVI +Name[uz]=DVI haqida maʼlumot +Name[uz@cyrillic]=DVI ҳақида маълумот +Name[wa]=Informåcion sol documint DVI +Name[zh_CN]=DVI 信息 +Name[zh_HK]=DVI 資訊 +Name[zh_TW]=DVI 資訊 +ServiceTypes=KFilePlugin +Type=Service +X-KDE-Library=kfile_dvi +PreferredItems=Title,Author,Subject,Creator,Producer,CreationDate,ModDate,Keywords diff --git a/kfile-plugins/dvi/kfile_dvi.h b/kfile-plugins/dvi/kfile_dvi.h new file mode 100644 index 00000000..66e7b218 --- /dev/null +++ b/kfile-plugins/dvi/kfile_dvi.h @@ -0,0 +1,37 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Matthias Witzgall <witzi@gmx.net> + * + * 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_DVI_H__ +#define __KFILE_DVI_H__ + +#include <kfilemetainfo.h> + +class QStringList; + +class KDviPlugin : public KFilePlugin +{ + Q_OBJECT +public: + KDviPlugin ( QObject * parent, const char * name, const QStringList & preferredItems ); + + virtual bool readInfo (KFileMetaInfo & info, uint what); +}; + +#endif diff --git a/kfile-plugins/exr/Makefile.am b/kfile-plugins/exr/Makefile.am new file mode 100644 index 00000000..f337359c --- /dev/null +++ b/kfile-plugins/exr/Makefile.am @@ -0,0 +1,25 @@ +## Makefile.am for EXR file meta info plugin + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + +# set the include path for X, qt and KDE +INCLUDES = -Drestrict= $(all_includes) $(EXR_FLAGS) +# INCLUDES = $(all_includes) $(EXR_FLAGS) + +# these are the headers for your project +noinst_HEADERS = kfile_exr.h + +kde_module_LTLIBRARIES = kfile_exr.la + +kfile_exr_la_SOURCES = kfile_exr.cpp +kfile_exr_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_exr_la_LIBADD = $(LIB_KIO) $(LIB_EXR) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_exr.pot + +services_DATA = kfile_exr.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/exr/configure.in.in b/kfile-plugins/exr/configure.in.in new file mode 100644 index 00000000..2a9ff5e5 --- /dev/null +++ b/kfile-plugins/exr/configure.in.in @@ -0,0 +1,14 @@ +AC_ARG_WITH([openexr], + [AC_HELP_STRING([--with-openexr], + [Enable support for OpenEXR @<:@default=check@:>@])], + [], with_openexr=check) + +if test "x$with_openexr" != xno; then + KDE_FIND_LIBEXR + + if test "x$with_openexr" != xcheck && test -z "$LIB_EXR"; then + AC_MSG_ERROR([--with-openexr was given, but test for OpenEXR failed]) + fi +fi + +AM_CONDITIONAL(include_EXR_MODULES, test -n "$LIB_EXR") diff --git a/kfile-plugins/exr/kfile_exr.cpp b/kfile-plugins/exr/kfile_exr.cpp new file mode 100644 index 00000000..2e995fc6 --- /dev/null +++ b/kfile-plugins/exr/kfile_exr.cpp @@ -0,0 +1,393 @@ +// -*- C++;indent-tabs-mode: t; tab-width: 4; c-basic-offset: 4; -*- +/* This file is part of the KDE project + * Copyright (C) 2003 <bradh@frogmouth.net> + * + * 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. + * + * $Id$ + */ + +#include <ImfStandardAttributes.h> +#include <ImathBox.h> +#include <ImfInputFile.h> +#include <ImfBoxAttribute.h> +#include <ImfChannelListAttribute.h> +#include <ImfCompressionAttribute.h> +#include <ImfFloatAttribute.h> +#include <ImfIntAttribute.h> +#include <ImfLineOrderAttribute.h> +#include <ImfStringAttribute.h> +#include <ImfVecAttribute.h> +#include <ImfPreviewImage.h> +#include <ImfVersion.h> +#include <ImfCRgbaFile.h> + +#include <iostream> + +#include <stdlib.h> +#include <string> + +#include <kurl.h> +#include <kprocess.h> +#include <klocale.h> +#include <kgenericfactory.h> +#include <kdebug.h> + +#include <qcstring.h> +#include <qfile.h> +#include <qdatetime.h> +#include <qdict.h> +#include <qvalidator.h> +#include <qimage.h> + + +#include "kfile_exr.h" +using namespace Imf; + +typedef KGenericFactory<KExrPlugin> ExrFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_exr, ExrFactory("kfile_exr")) + +KExrPlugin::KExrPlugin(QObject *parent, const char *name, + const QStringList &args) + : KFilePlugin(parent, name, args) +{ + // set up our mime type + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-exr" ); + + KFileMimeTypeInfo::GroupInfo* group = 0; + KFileMimeTypeInfo::ItemInfo* item; + + // info group + group = addGroupInfo( info, "Info", i18n("Information") ); + addItemInfo( group, "Version", i18n("Format Version"), QVariant::Int ); + addItemInfo( group, "Tiled image", i18n("Tiled Image"), QVariant::String ); + item = addItemInfo( group, "Dimensions", i18n("Dimensions"), QVariant::Size ); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit( item, KFileMimeTypeInfo::Pixels ); + item = addItemInfo( group, "ThumbnailDimensions", + i18n("Thumbnail Dimensions"), QVariant::Size ); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit( item, KFileMimeTypeInfo::Pixels ); + addItemInfo( group, "Comment", i18n("Comment"), QVariant::String ); + item = addItemInfo( group, "Thumbnail", i18n("Thumbnail"), QVariant::Image ); + setHint( item, KFileMimeTypeInfo::Thumbnail ); + + // standard attributes group + group = addGroupInfo( info, "Standard", i18n("Standard Attributes") ); + addItemInfo( group, "Owner", i18n("Owner"), QVariant::String ); + addItemInfo( group, "Comments", i18n("Comments"), QVariant::String ); + addItemInfo( group, "Capture Date", i18n("Capture Date"), QVariant::String ); + item = addItemInfo( group, "UTC Offset", i18n("UTC Offset"), QVariant::String ); + item = addItemInfo( group, "Exposure time", i18n("Exposure Time"), QVariant::Double); + setUnit( item, KFileMimeTypeInfo::Seconds ); + item = addItemInfo( group, "Focus", i18n("Focus"), QVariant::Double); + setSuffix( item, i18n("Metres", "m") ); + item = addItemInfo( group, "X Density", i18n("X Density"), QVariant::Double); + setSuffix( item, i18n("Pixels Per Inch", " ppi") ); + item = addItemInfo( group, "White luminance", i18n("White Luminance"), QVariant::Double); + setSuffix( item, i18n("Candelas per square metre", " Nits") ); + addItemInfo( group, "Longitude", i18n("Longitude"), QVariant::String ); + addItemInfo( group, "Latitude", i18n("Latitude"), QVariant::String ); + item = addItemInfo( group, "Altitude", i18n("Altitude"), QVariant::String ); + setSuffix( item, i18n("Metres", "m") ); + addItemInfo( group, "ISO speed", i18n("ISO Speed"), QVariant::Double ); + addItemInfo( group, "Aperture", i18n("Aperture"), QVariant::Double ); + + // channel group + group = addGroupInfo( info, "Channel", i18n("Channels") ); + addItemInfo( group, "A", i18n("A"), QVariant::String ); + addItemInfo( group, "R", i18n("R"), QVariant::String ); + addItemInfo( group, "G", i18n("G"), QVariant::String ); + addItemInfo( group, "B", i18n("B"), QVariant::String ); + addItemInfo( group, "Z", i18n("Z"), QVariant::String ); + addItemInfo( group, "NX", i18n("NX"), QVariant::String ); + addItemInfo( group, "NY", i18n("NY"), QVariant::String ); + addItemInfo( group, "NZ", i18n("NZ"), QVariant::String ); + addItemInfo( group, "R", i18n("R"), QVariant::String ); + addItemInfo( group, "U", i18n("U"), QVariant::String ); + addItemInfo( group, "V", i18n("V"), QVariant::String ); + addItemInfo( group, "materialID", i18n("materialID"), QVariant::String ); + addItemInfo( group, "objectID", i18n("objectID"), QVariant::String ); + addItemInfo( group, "renderID", i18n("renderID"), QVariant::String ); + addItemInfo( group, "pixelCover", i18n("pixelCover"), QVariant::String ); + addItemInfo( group, "velX", i18n("velX"), QVariant::String ); + addItemInfo( group, "velY", i18n("velY"), QVariant::String ); + addItemInfo( group, "packedRGBA", i18n("packedRGBA"), QVariant::String ); + + + // technical group + group = addGroupInfo( info, "Technical", i18n("Technical Details") ); + addItemInfo( group, "Compression", i18n("Compression"), QVariant::String ); + addItemInfo( group, "Line Order", i18n("Line Order"), QVariant::String ); + + // 3dsMax group + // This supports a special plugin for 3D Studio Max + group = addGroupInfo( info, "3dsMax", i18n("3dsMax Details") ); + addItemInfo( group, "Local time", i18n("Local Time"), QVariant::String ); + addItemInfo( group, "System time", i18n("System Time"), QVariant::String ); + addItemInfo( group, "Plugin version", i18n("Plugin Version"), QVariant::String ); + addItemInfo( group, "EXR version", i18n("EXR Version"), QVariant::String ); + addItemInfo( group, "Computer name", i18n("Computer Name"), QVariant::String ); +} + +QCString doType( PixelType pt ) +{ + switch (pt) + { + case UINT: + return QCString("32-bit unsigned integer"); + break; + case HALF: + return QCString("16-bit floating-point"); + break; + case FLOAT: + return QCString("32-bit floating-point"); + break; + default: + return QCString(); + break; + } +} + +bool KExrPlugin::readInfo( KFileMetaInfo& info, uint what) +{ + try + { + InputFile in ( info.path().ascii() ); + const Header &h = in.header(); + + KFileMetaInfoGroup infogroup = appendGroup(info, "Info"); + KFileMetaInfoGroup stdgroup = appendGroup(info, "Standard"); + KFileMetaInfoGroup channelgroup = appendGroup(info, "Channel"); + KFileMetaInfoGroup techgroup = appendGroup(info, "Technical"); + KFileMetaInfoGroup threedsmaxgroup = appendGroup(info, "3dsMax"); + + appendItem( infogroup, "Version", getVersion(in.version()) ); + if (isTiled(in.version())) { + appendItem( infogroup, "Tiled image", "yes" ); + } else { + appendItem( infogroup, "Tiled image", "no" ); + } + + Imath::Box2i dw = h.dataWindow(); + appendItem( infogroup, "Dimensions", QSize( (dw.max.x - dw.min.x + 1 ), + (dw.max.y - dw.min.y + 1 ) ) ); + + if ( h.hasPreviewImage() ) { + const PreviewImage &preview = in.header().previewImage(); + appendItem( infogroup, "ThumbnailDimensions", QSize(preview.width(), preview.height()) ); + QImage qpreview(preview.width(), preview.height(), 32, 0, QImage::BigEndian); + for ( unsigned int y=0; y < preview.height(); y++ ) { + for ( unsigned int x=0; x < preview.width(); x++ ) { + const PreviewRgba &q = preview.pixels()[x+(y*preview.width())]; + qpreview.setPixel( x, y, qRgba(q.r, q.g, q.b, q.a) ); + } + } + appendItem( infogroup, "Thumbnail", qpreview); + } + + const StringAttribute *commentSA = h.findTypedAttribute <StringAttribute> ("comment"); + if (commentSA) { + std::string commentString = commentSA->value(); + QString qcommentString(commentString.data()); + qcommentString.setLength(commentString.size()); + appendItem( infogroup, "Comment", qcommentString ); + } + + // Standard Attributes we are interested in and can + // meaningfully represent. + if ( hasComments(h) ) { + std::string commentsString = comments(h); + QString qcommentsString(commentsString.data()); + qcommentsString.setLength(commentsString.size()); + appendItem( stdgroup, "Comments", qcommentsString ); + } + if ( hasOwner(h) ) { + std::string ownerString = owner(h); + QString qownerString(ownerString.data()); + qownerString.setLength(ownerString.size()); + appendItem( stdgroup, "Owner", qownerString ); + } + if ( hasCapDate(h) ) { + std::string capDateString = capDate(h); + QString qcapDateString(capDateString.data()); + qcapDateString.setLength(capDateString.size()); + appendItem( stdgroup, "Capture Date", qcapDateString ); + } + // This define was introduced in EXR 1.6.0 +#ifndef IMF_B44_COMPRESSION + // This is the 1.4 and earlier version + if ( hasutcOffset(h) ) { +#else + // This is the 1.6.0 and later version + if ( hasUtcOffset(h) ) { +#endif + QString UTCOffset; + if (utcOffset(h)>0.0) { + UTCOffset.append(QString("%1").arg(utcOffset(h)/3600, 0, 'f', 1)); + UTCOffset.append(" hours behind UTC"); + } else { + UTCOffset.append(QString("%1").arg(-1.0*utcOffset(h)/3600, 0, 'f', 1)); + UTCOffset.append(" hours ahead of UTC"); + } + appendItem( stdgroup, "UTC Offset", UTCOffset); + } + if ( hasExpTime(h) ) { + double exposureTime = expTime(h); + appendItem( stdgroup, "Exposure time", exposureTime ); + } + if ( hasFocus(h) ) { + double focusDistance = focus(h); + appendItem( stdgroup, "Focus", focusDistance ); + } + if ( hasXDensity(h) ) { + double XDensity = xDensity(h); + appendItem( stdgroup, "X Density", XDensity ); + } + if ( hasWhiteLuminance(h) ) { + double WhiteLuminance = whiteLuminance(h); + appendItem( stdgroup, "White luminance", WhiteLuminance ); + } + if ( hasLongitude(h) ) { + QString Longitude; + if (longitude(h)<0.0) { + Longitude.append(QString("%1").arg(-1.0*longitude(h),0,'f',3)); + Longitude.append(" deg West"); + } else { + Longitude.append(QString("%1").arg(longitude(h),0,'f',3)); + Longitude.append(" deg East"); + } + appendItem( stdgroup, "Longitude", Longitude); + } + if ( hasLatitude(h) ) { + QString Latitude; + if (latitude(h)<0.0) { + Latitude.append(QString("%1").arg(-1.0*latitude(h),0,'f',3)); + Latitude.append(" deg South"); + } else { + Latitude.append(QString("%1").arg(latitude(h),0,'f',3)); + Latitude.append(" deg North"); + } + appendItem( stdgroup, "Latitude", Latitude ); + } + if ( hasAltitude(h) ) { + double Altitude = altitude(h); + appendItem( stdgroup, "Altitude", QString("%1").arg(Altitude,0,'f',1) ); + } + if ( hasIsoSpeed(h) ) { + double IsoSpeed = isoSpeed(h); + appendItem( stdgroup, "ISO speed", IsoSpeed ); + } + if ( hasAperture(h) ) { + double Aperture = aperture(h); + appendItem( stdgroup, "Aperture", Aperture ); + } + + for (Header::ConstIterator i = h.begin(); i != h.end(); ++i) { + const Attribute *a = &i.attribute(); + + if (const CompressionAttribute *ta = dynamic_cast <const CompressionAttribute *> (a)) { + switch ( ta->value() ) + { + case NO_COMPRESSION: + appendItem( techgroup, "Compression", i18n("No compression")); + break; + case RLE_COMPRESSION: + appendItem( techgroup, "Compression", i18n("Run Length Encoding")); + break; + case ZIPS_COMPRESSION: + appendItem( techgroup, "Compression", i18n("zip, individual scanlines")); + break; + case ZIP_COMPRESSION: + appendItem( techgroup, "Compression", i18n("zip, multi-scanline blocks")); + break; + case PIZ_COMPRESSION: + appendItem( techgroup, "Compression", i18n("piz compression")); + break; + default: + break; + } + } else if (const LineOrderAttribute *ta = dynamic_cast <const LineOrderAttribute *> (a)) { + switch (ta->value()) + { + case INCREASING_Y: + appendItem( techgroup, "Line Order", i18n("increasing Y")); + break; + case DECREASING_Y: + appendItem( techgroup, "Line Order", i18n("decreasing Y")); + break; + default: + break; + }; + } else if (const ChannelListAttribute *ta = dynamic_cast <const ChannelListAttribute *> (a)) { + + for (ChannelList::ConstIterator i = ta->value().begin(); i != ta->value().end(); ++i) + { + appendItem( channelgroup, i.name(), doType(i.channel().type) ); + } + } + } + + // This section deals with some special case stuff for a 3D Studio Max + // plugin from Splutterfish. The weird construction is an + // attempt to to deal with class conversion. C++ string handling + // without Qt is a pain... + const StringAttribute *ver3DSM = h.findTypedAttribute <StringAttribute> ("version3dsMax"); + if (ver3DSM) { + std::string ver3DSMstring = ver3DSM->value(); + QString qver3DSMstring(ver3DSMstring.data()); + qver3DSMstring.setLength(ver3DSMstring.size()); + appendItem( threedsmaxgroup, "Plugin version", qver3DSMstring ); + } + const StringAttribute *verEXR = h.findTypedAttribute <StringAttribute> ("versionEXR"); + if (verEXR) { + std::string verEXRstring = verEXR->value(); + QString qverEXRstring(verEXRstring.data()); + qverEXRstring.setLength(verEXRstring.size()); + appendItem( threedsmaxgroup, "EXR version", QString( verEXRstring.data() ) ); + } + const StringAttribute *localTime = h.findTypedAttribute <StringAttribute> ("localTime"); + if (localTime) { + std::string localTimeString = localTime->value(); + QString qlocalTimeString(localTimeString.data()); + qlocalTimeString.setLength(localTimeString.size()); + appendItem( threedsmaxgroup, "Local time", qlocalTimeString ); + } + const StringAttribute *systemTime = h.findTypedAttribute <StringAttribute> ("systemTime"); + if (systemTime) { + std::string systemTimeString = systemTime->value(); + QString qsystemTimeString(systemTimeString.data()); + qsystemTimeString.setLength(systemTimeString.size()); + appendItem( threedsmaxgroup, "System time", qsystemTimeString ); + } + const StringAttribute *computerName = h.findTypedAttribute <StringAttribute> ("computerName"); + if (computerName) { + std::string computerNameString = computerName->value(); + QString qcomputerNameString(computerNameString.data()); + qcomputerNameString.setLength(computerNameString.size()); + appendItem( threedsmaxgroup, "Computer name", qcomputerNameString ); + } + + return true; + } + catch (const std::exception &e) + { + kdDebug(0) << e.what() << endl; + return false; + } +} + +#include "kfile_exr.moc" diff --git a/kfile-plugins/exr/kfile_exr.desktop b/kfile-plugins/exr/kfile_exr.desktop new file mode 100644 index 00000000..b1b3a583 --- /dev/null +++ b/kfile-plugins/exr/kfile_exr.desktop @@ -0,0 +1,57 @@ +[Desktop Entry] +Type=Service +Name=EXR Info +Name[br]=Titouroù EXR +Name[ca]=Informació EXR +Name[cs]=EXR info +Name[cy]=Gwybodaeth EXR +Name[da]=EXR-Info +Name[de]=EXR-Info +Name[el]=Πληροφορίες EXR +Name[eo]=EXR-informo +Name[es]=Info EXR +Name[et]=EXR info +Name[fa]=اطلاعات EXR +Name[fi]=EXR-tiedot +Name[fr]=Informations EXR +Name[ga]=Eolas faoi EXR +Name[gl]=Inf. EXR +Name[he]=מידע EXR +Name[hu]=EXR-jellemzők +Name[is]=EXR upplýsingar +Name[it]=Informazioni EXR +Name[ja]=EXR 情報 +Name[kk]=EXR мәліметі +Name[km]=ព័ត៌មាន EXR +Name[lt]=EXR informacija +Name[ms]=Maklumat EXR +Name[nds]=EXR-Info +Name[ne]=EXR सूचना +Name[nl]=EXR-info +Name[nn]=EXR-info +Name[pa]=EXR ਜਾਣਕਾਰੀ +Name[pl]=Informacja EXR +Name[pt]=Informação do EXR +Name[pt_BR]=Informação sobre EXR +Name[ro]=Informaţii EXR +Name[ru]=Информация о EXR +Name[se]=EXR-dieđut +Name[sl]=Podatki o EXR +Name[sr]=EXR информације +Name[sr@Latn]=EXR informacije +Name[sv]=EXR-information +Name[ta]=EXR தகவல் +Name[tg]=Иттилоот оиди EXR +Name[th]=ข้อมูลแฟ้ม EXR +Name[tr]=EXR Bilgisi +Name[uk]=Інформація по EXR +Name[uz]=EXR haqida maʼlumot +Name[uz@cyrillic]=EXR ҳақида маълумот +Name[zh_CN]=EXR 信息 +Name[zh_HK]=EXR 資訊 +Name[zh_TW]=EXR 資訊 +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_exr +MimeType=image/x-exr +PreferredGroups=Info,Standard,Channels,Technical,3dsMax +PreferredItems=Dimensions,Thumbnail,ThumbnailDimensions,Version,Comments,Owner,Latitude,Longitude,Altitude,Capture Date,UTC Offset diff --git a/kfile-plugins/exr/kfile_exr.h b/kfile-plugins/exr/kfile_exr.h new file mode 100644 index 00000000..cb795ba5 --- /dev/null +++ b/kfile-plugins/exr/kfile_exr.h @@ -0,0 +1,39 @@ +/* This file is part of the KDE project + * Copyright (C) 2003 <bradh@frogmouth.net> + * + * 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. + * + * $Id$ + */ + +#ifndef __KFILE_EXR_H__ +#define __KFILE_EXR_H__ + +#include <kfilemetainfo.h> +#include <kurl.h> + +class QStringList; + +class KExrPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KExrPlugin( QObject *parent, const char *name, const QStringList& preferredItems ); + + virtual bool readInfo( KFileMetaInfo& info, uint ); +}; + +#endif diff --git a/kfile-plugins/gif/Makefile.am b/kfile-plugins/gif/Makefile.am new file mode 100644 index 00000000..b847d002 --- /dev/null +++ b/kfile-plugins/gif/Makefile.am @@ -0,0 +1,24 @@ +## Makefile.am for gif 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_gif.h + +kde_module_LTLIBRARIES = kfile_gif.la + +kfile_gif_la_SOURCES = kfile_gif.cpp +kfile_gif_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_gif_la_LIBADD = $(LIB_KIO) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_gif.pot + +services_DATA = kfile_gif.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/gif/README b/kfile-plugins/gif/README new file mode 100644 index 00000000..e81cc913 --- /dev/null +++ b/kfile-plugins/gif/README @@ -0,0 +1,10 @@ +The original README for this file read: +<quote> +Note: Development of this module has been suspended. +Please feel free to contact me, and pick it up. All I ask +is that you preserve both command line and kfile abilities. Thanks. +bryce@obviously.com +</quote> + +I contacted Bryce, but received no response. The command line code +is unchanged - I just fixed the kfile code to work, read only. diff --git a/kfile-plugins/gif/gif-info.1 b/kfile-plugins/gif/gif-info.1 new file mode 100644 index 00000000..6c36b1c4 --- /dev/null +++ b/kfile-plugins/gif/gif-info.1 @@ -0,0 +1,25 @@ +.TH gif-info 1 "April 2002" + +.SH NAME +gif-info \- reads gif image info or sets comment. + +.SH SYNOPSIS +.B gif-info +.RB <filename> +['Comment'] + +.SH DESCRIPTION +.LP +.B gif-info +displays information about the given gif (Graphic Interchange Format) image. If a comment is specified, the comment is set instead. +.PP +Write a empty comment ('') to delete the comment block. +.PP +The GIF standard allows any number of 256 byte comment blocks in an image file, but most implementations (including this one) restrict you to just one block. The GIF standard restricts comment blocks to "7 Bit ASCII", but this is widely ignored. You are welcome to store text in your own native language, and are especially encouraged to use comments in utf-8 unicode format. + +.SH "SEE ALSO" +.BR wrjpgcom (1) +.BR rdjpgcom (1) + +.SH AUTHOR +Bryce Nesbitt diff --git a/kfile-plugins/gif/gif-info.c b/kfile-plugins/gif/gif-info.c new file mode 100644 index 00000000..2f64a2f2 --- /dev/null +++ b/kfile-plugins/gif/gif-info.c @@ -0,0 +1,561 @@ +/* +** $Id$ +** +** Minimal GIF parser, for use in extracting and setting metadata. +** Modified for standalone & KDE calling by Bryce Nesbitt +** +** TODO: +** Support gif comments that span more than one comment block. +** Verify that Unicode utf-8 is fully unmolested by this code. +** Implement gif structure verifier. +** +** Based on: GIFtrans v1.12.2 +** Copyright (C) 24.2.94 by Andreas Ley <ley@rz.uni-karlsruhe.de> +** +******************************************************************************* +** +** Original distribution site is +** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.c +** A man-page by knordlun@fltxa.helsinki.fi (Kai Nordlund) is at +** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.1 +** An online version by taylor@intuitive.com (Dave Taylor) is at +** http://www.intuitive.com/coolweb/Addons/giftrans-doc.html +** To compile for MS-DOS or OS/2, you need getopt: +** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/getopt.c +** MS-DOS executable can be found at +** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.exe +** OS/2 executable can be found at +** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.os2.exe +** A template rgb.txt for use with the MS-DOS version can be found at +** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/rgb.txt +** Additional info can be found on +** http://melmac.corp.harris.com/transparent_images.html +** +** The GIF file format is documented in +** ftp://ftp.uu.net/doc/literary/obi/Standards/Graphics/Formats/gif89a.doc.Z +** A good quick reference is at: +** http://www.goice.co.jp/member/mo/formats/gif.html +** +******************************************************************************* +** +** 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; either version 2 of the License, or +** (at your option) any later version. +** +** 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; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +** +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#define STANDALONE_COMPILE + +extern int set_gif_comment( const char * original_filename, char * comment ); +extern void * get_gif_info( const char * original_filename ); +extern int validate_gif_structure( const char * original_filename ); +int giftrans( FILE * src, FILE * dest); + +#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 */ + +/*****************************************************************************/ +#ifndef FALSE +#define FALSE (0) /* This is the naked Truth */ +#define TRUE (1) /* and this is the Light */ +#endif + +#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 SUCCESS (0) +#define FAILURE (1) + +static char skipcomment,list,verbose,output,debug; +char *global_comment; +static long int pos; + +static char true[] = "True"; +static char false[] = "False"; +static char id[] = "$Id$"; + +/*****************************************************************************/ + +#define readword(buffer) ((buffer)[0]+256*(buffer)[1]) +#define readflag(buffer) ((buffer)?true:false) +#define hex(c) ('a'<=(c)&&(c)<='z'?(c)-'a'+10:'A'<=(c)&&(c)<='Z'?(c)-'A'+10:(c)-'0') + +void dump(adr,data,len) +long int adr; +unsigned char *data; +size_t len; +{ + int i; + + while (len>0) { + (void)fprintf(stderr,"%08lx:%*s",adr,(int)((adr%16)*3+(adr%16>8?1:0)),""); + for (i=adr%16;i<16&&len>0;i++,adr++,data++,len--) + (void)fprintf(stderr,"%s%02x",i==8?" ":" ",*data); + (void)fprintf(stderr,"\n"); + } +} + +void writedata(dest,data,len) +FILE *dest; +unsigned char *data; +size_t len; +{ + unsigned char size; + + while (len) { + size=len<256?len:255; + (void)fwrite((void *)&size,1,1,dest); + (void)fwrite((void *)data,(size_t)size,1,dest); + data+=size; + len-=size; + } + size=0; + (void)fwrite((void *)&size,1,1,dest); +} + +void skipdata(src) +FILE *src; +{ + unsigned char size,buffer[256]; + + do { + pos=ftell(src); + (void)fread((void *)&size,1,1,src); + if (debug) + dump(pos,&size,1); + if (debug) { + pos=ftell(src); + (void)fread((void *)buffer,(size_t)size,1,src); + dump(pos,buffer,(size_t)size); + } + else + (void)fseek(src,(long int)size,SEEK_CUR); + } while (!feof(src)&&size>0); +} + +void transblock(src,dest) +FILE *src; +FILE *dest; +{ + unsigned char size,buffer[256]; + + pos=ftell(src); + (void)fread((void *)&size,1,1,src); + if (debug) + dump(pos,&size,1); + if (output) + (void)fwrite((void *)&size,1,1,dest); + pos=ftell(src); + (void)fread((void *)buffer,(size_t)size,1,src); + if (debug) + dump(pos,buffer,(size_t)size); + if (output) + (void)fwrite((void *)buffer,(size_t)size,1,dest); +} + +void dumpcomment(src) +FILE *src; +{ + unsigned char size,buffer[256]; + size_t i; + + pos=ftell(src); + (void)fread((void *)&size,1,1,src); + if (debug) + dump(pos,&size,1); + (void)fread((void *)buffer,(size_t)size,1,src); + if (debug) + dump(pos+1,buffer,(size_t)size); + for (i=0; i<(size_t)size; i++) + { + if ( buffer[i] >= 0x20 || buffer[i] == '\t' || + buffer[i] =='\r' || buffer[i] == '\n') + (void)putc(buffer[i],stderr); + else + (void)fprintf(stderr,"\\%03o",buffer[i]); + } + (void)fseek(src,(long int)pos,SEEK_SET); +} + +void transdata(src,dest) +FILE *src; +FILE *dest; +{ + unsigned char size,buffer[256]; + + do { + pos=ftell(src); + (void)fread((void *)&size,1,1,src); + if (debug) + dump(pos,&size,1); + if (output) + (void)fwrite((void *)&size,1,1,dest); + pos=ftell(src); + (void)fread((void *)buffer,(size_t)size,1,src); + if (debug) + dump(pos,buffer,(size_t)size); + if (output) + (void)fwrite((void *)buffer,(size_t)size,1,dest); + } while (!feof(src)&&size>0); +} + + +/*****************************************************************************/ + +int giftrans(src,dest) +FILE *src; +FILE *dest; +{ + unsigned char buffer[3*256],lsd[7],gct[3*256]; + unsigned int cnt,cols,size,gct_size; + + /* Header */ + pos=ftell(src); + (void)fread((void *)buffer,6,1,src); + if (strncmp((char *)buffer,"GIF",3)) { + (void)fprintf(stderr,"Not GIF file!\n"); + return(1); + } + if (verbose && debug) { + buffer[6]='\0'; + (void)fprintf(stderr,"Header: \"%s\"\n",buffer); + } + if (debug) + dump(pos,buffer,6); + if (output) { + (void)fwrite((void *)buffer,6,1,dest); + } + + /* Logical Screen Descriptor */ + pos=ftell(src); + (void)fread((void *)lsd,7,1,src); + if (verbose) { + //(void)fprintf(stderr,"Logical Screen Descriptor:\n"); + (void)fprintf(stderr,"Size : %dx%d pixels\n",readword(lsd), readword(lsd+2)); + //(void)fprintf(stderr,"Global Color Table Flag: %s\n",readflag(lsd[4]&0x80)); + (void)fprintf(stderr,"Depth : %d bits\n",(lsd[4]&0x70>>4)+1); + //if (lsd[4]&0x80) { + // (void)fprintf(stderr,"\tSort Flag: %s\n",readflag(lsd[4]&0x8)); + // (void)fprintf(stderr,"\tSize of Global Color Table: %d colors\n",2<<(lsd[4]&0x7)); + // (void)fprintf(stderr,"\tBackground Color Index: %d\n",lsd[5]); + //} + if (lsd[6]) + (void)fprintf(stderr,"Pixel Aspect Ratio: %d (Aspect Ratio %f)\n",lsd[6],((double)lsd[6]+15)/64); + } + if (debug) + dump(pos,lsd,7); + if (output) + (void)fwrite((void *)lsd,7,1,dest); + + /* Global Color Table */ + if (lsd[4]&0x80) { + gct_size=2<<(lsd[4]&0x7); + pos=ftell(src); + (void)fread((void *)gct,gct_size,3,src); + if (output) + (void)fwrite((void *)gct,gct_size,3,dest); + } + + do { + pos=ftell(src); + (void)fread((void *)buffer,1,1,src); + switch (buffer[0]) { + case 0x2c: /* Image Descriptor */ + if (verbose && debug) + (void)fprintf(stderr,"Image Descriptor:\n"); + (void)fread((void *)(buffer+1),9,1,src); + if (debug) + dump(pos,buffer,10); + if (output) + (void)fwrite((void *)buffer,10,1,dest); + /* Local Color Table */ + if (buffer[8]&0x80) { + size=2<<(buffer[8]&0x7); + pos=ftell(src); + (void)fread((void *)buffer,size,3,src); + if (verbose && debug) { + (void)fprintf(stderr,"Local Color Table:\n"); + for(cnt=0;cnt<size;cnt++) + (void)fprintf(stderr,"\tColor %d: Red %d, Green %d, Blue %d\n",cnt,buffer[3*cnt],buffer[3*cnt+1],buffer[3*cnt+2]); + } + if (debug) + dump(pos,buffer,size*3); + if (output) + (void)fwrite((void *)buffer,size,3,dest); + } + /* Table Based Image Data */ + pos=ftell(src); + (void)fread((void *)buffer,1,1,src); + if (verbose && debug) { + (void)fprintf(stderr,"Table Based Image Data:\n"); + (void)fprintf(stderr,"\tLZW Minimum Code Size: 0x%02x\n",buffer[0]); + } + if (debug) + dump(pos,buffer,1); + if (output) + (void)fwrite((void *)buffer,1,1,dest); + transdata(src,dest); + break; + case 0x21: /* Extension */ + (void)fread((void *)(buffer+1),1,1,src); + switch (buffer[1]) { + case 0xfe: /* Comment Extension */ + if (verbose) + { + (void)fprintf(stderr,"Comment: "); + dumpcomment(src); + (void)fprintf(stderr,"\n"); + } + if (debug) + dump(pos,buffer,2); + if (skipcomment) + skipdata(src); + else { + if (output) + (void)fwrite((void *)buffer,2,1,dest); + transdata(src,dest); + } + break; + case 0x01: /* Plain Text Extension */ + case 0xf9: /* Graphic Control Extension */ + case 0xff: /* Application Extension */ + default: + if (verbose && debug) + (void)fprintf(stderr,"Extension type: 0x%02x\n",buffer[1]); + if (debug) + dump(pos,buffer,2); + if (output) + (void)fwrite((void *)buffer,2,1,dest); + transblock(src,dest); + transdata(src,dest); + break; + } + break; + case 0x3b: /* Trailer (write comment just before here) */ + if (verbose && debug) + (void)fprintf(stderr,"Trailer %o\n", pos); + if (debug) + dump(pos,buffer,1); + if (global_comment && *global_comment && output) { + (void)fputs("\041\376",dest); + writedata(dest,(unsigned char *)global_comment,strlen(global_comment)); + } + if (output) + (void)fwrite((void *)buffer,1,1,dest); + break; + default: + (void)fprintf(stderr,"0x%08lx: Error, unknown block 0x%02x!\n",ftell(src)-1,buffer[0]); + if (debug) + dump(pos,buffer,1); + return(1); + } + } while (buffer[0]!=0x3b&&!feof(src)); + return(buffer[0]==0x3b?SUCCESS:FAILURE); +} + + +/****************************************************************************/ +extern int validate_gif_structure( const char * original_filename ) +{ +FILE * infile; +int rc; + + if ((infile = fopen(original_filename, READ_BINARY)) == NULL) { + fprintf(stderr, "can't open gif image '%s'\n", original_filename); + return( 1 ); + } + output = FALSE; + verbose = FALSE; + debug = FALSE; + skipcomment = FALSE; + rc = giftrans( infile, NULL ); + fclose( infile ); + return( rc ); +} + + +/****************************************************************************/ +extern void * get_gif_info( const char * original_filename ) +{ +FILE * infile; + + if ((infile = fopen(original_filename, READ_BINARY)) == NULL) { + fprintf(stderr, "can't open gif image '%s'\n", original_filename); + return( NULL ); + } + + output = FALSE; + verbose = TRUE; + debug = FALSE; + skipcomment = FALSE; + giftrans( infile, NULL ); + return( NULL ); +} + + +/***************************************************************************** + 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 in same directory (filenameXX). + 3) Copy the data, writing a new comment block. + 4) Sync everything to disc. + 5) Validate the temporary file. + 6) Move the temporary file over the original. +*/ +extern int set_gif_comment( const char * original_filename, char * comment ) +{ +int i; +int rc; +char * temp_filename; +int temp_filename_length; +struct stat statbuf; +FILE * infile; +FILE * outfile; + + + /* + * Make sure we're dealing with a proper input file. Safety first! + */ + if( validate_gif_structure( original_filename ) ) { + fprintf(stderr, "error validating gif image '%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 unsafe string functions in C... + */ + 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)) ) { + //fprintf(stderr, "opened temporary file '%s'\n", temp_filename); + break; + } + } + if( !outfile ) { + fprintf(stderr, "failed opening temporary file '%s'\n", temp_filename); + return(ERROR_TEMP_FILE); + } + + if ((infile = fopen(original_filename, READ_BINARY)) == NULL) { + fclose( outfile ); + fprintf(stderr, "can't open gif image '%s'\n", original_filename); + return(ERROR_NOT_A_JPEG); + } + /* Let's do it */ + output = TRUE; + verbose = FALSE; + debug = FALSE; + skipcomment = TRUE; + global_comment = comment; + rc = giftrans( infile, outfile ); + fclose( infile ); + fsync( fileno( outfile) ); /* Flush it to disk. IMPORTANT!! */ + /* We really should also flush the directory */ + + /* If everything is OK, and if the new file validates, move + it over the top of the original */ + if ( fclose( outfile ) || validate_gif_structure( temp_filename ) ) { + fprintf(stderr, "error in temporary file '%s'\n", temp_filename); + return(ERROR_TEMP_FILE); + } + if( rc ) { + unlink( temp_filename ); + return( rc ); + } + if( rename( temp_filename, original_filename ) ) { + fprintf(stderr, "error renaming '%s' to '%s'\n", temp_filename, original_filename); + return(ERROR_TEMP_FILE); + } + + return(0); +} + + +/*****************************************************************************/ +#ifdef STANDALONE_COMPILE +int +main (int argc, char **argv) +{ + char * progname; + char * filename; + char * comment; + FILE * fp; + int error; + + /* Process command line arguments... */ + progname = argv[0]; + if (progname == NULL || progname[0] == 0) + progname = "gif-info"; /* in case C library doesn't provide it */ + if( argc < 2 || argc > 3) { + fprintf(stderr, "Usage: %s <filename> [\"<comment>\"]\nReads gif image info or sets 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); + return(5); + } + fclose(fp); + + /* Check if we really have a commentable image file here... */ + if( validate_gif_structure( filename ) ) { + fprintf(stderr, "Error: error parsing file '%s' as a gif image\n", filename); + return(5); + } + + if( argc == 2 ) { + get_gif_info( filename ); + } + else { + set_gif_comment( filename, comment ); + } + + return( 0 ); +} +#endif + diff --git a/kfile-plugins/gif/kfile_gif.cpp b/kfile-plugins/gif/kfile_gif.cpp new file mode 100644 index 00000000..3c29f05f --- /dev/null +++ b/kfile-plugins/gif/kfile_gif.cpp @@ -0,0 +1,122 @@ +/* + * This file is part of the KDE project, added by Bryce Nesbitt + * + * This is a plugin for Konqeror/KFile which processes 'extra' information + * contained in a .gif image file (In particular the comment, and resolution). + * + ************************************** + * + * 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_gif.h" + +#include <kurl.h> +#include <kprocess.h> +#include <klocale.h> +#include <kgenericfactory.h> +#include <kdebug.h> + +#include <qcstring.h> +#include <qfile.h> +#include <qdatetime.h> +#include <qdict.h> +#include <qvalidator.h> +#include <qimage.h> + +typedef KGenericFactory<KGifPlugin> GifFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_gif, GifFactory("kfile_gif")) + +KGifPlugin::KGifPlugin(QObject *parent, const char *name, + const QStringList &args) + : KFilePlugin(parent, name, args) +{ + kdDebug(7034) << "gif KFileMetaInfo plugin\n"; + + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/gif" ); + + KFileMimeTypeInfo::GroupInfo* group = 0L; + + group = addGroupInfo(info, "General", i18n("General")); + + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo(group, "Version", i18n("Version"), QVariant::String); + + item = addItemInfo( group, "Dimensions", i18n("Dimensions"), QVariant::Size ); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit( item, KFileMimeTypeInfo::Pixels ); + + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); + +} + +bool KGifPlugin::readInfo( KFileMetaInfo& info, uint what ) +{ + Q_UNUSED( what ); + + kdDebug(7034) << "gif KFileMetaInfo readInfo\n"; + + QFile file(info.path()); + + if (!file.open(IO_ReadOnly)) { + kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + QDataStream fstream(&file); + + bool isGIF87a = false; + char magic[7]; + Q_UINT16 width = 0; + Q_UINT16 height = 0; + Q_UINT8 miscInfo = 0; + + fstream.readRawBytes( magic, 6 ); + magic[6] = 0x00; // null terminate + + // I have special requirements... + fstream.setByteOrder( QDataStream::LittleEndian ); + fstream >> width; + fstream >> height; + fstream >> miscInfo; + + KFileMetaInfoGroup group = appendGroup(info, "General"); + + if ( 0 == strncmp( magic, "GIF89a", 6 ) ) { + appendItem( group, "Version", i18n("GIF Version 89a") ); + } else if ( 0 == strncmp( magic, "GIF87a", 6 ) ) { + appendItem( group, "Version", i18n("GIF Version 87a") ); + isGIF87a = true; + } else { + appendItem( group, "Version", i18n("Unknown") ); + } + + appendItem( group, "Dimensions", QSize(width, height) ); + + if ( isGIF87a ) { + appendItem( group, "BitDepth", ( (miscInfo & 0x07) + 1) ); + } + + file.close(); + + return true; +} + +#include "kfile_gif.moc" diff --git a/kfile-plugins/gif/kfile_gif.desktop b/kfile-plugins/gif/kfile_gif.desktop new file mode 100644 index 00000000..8188f60f --- /dev/null +++ b/kfile-plugins/gif/kfile_gif.desktop @@ -0,0 +1,65 @@ +[Desktop Entry] +Type=Service +Name=GIF Info +Name[af]=Gif Inligting +Name[ar]=معلومات GIF +Name[br]=Titouroù GIF +Name[ca]=Informació de GIF +Name[cs]=GIF info +Name[cy]=Gwybodaeth GIF +Name[da]=GIF-info +Name[de]=GIF-Info +Name[el]=Πληροφορίες GIF +Name[eo]=GIF-informo +Name[es]=Info GIF +Name[et]=GIF info +Name[fa]=اطلاعات GIF +Name[fi]=GIF-tiedot +Name[fr]=Informations GIF +Name[ga]=Eolas faoi GIF +Name[gl]=Inf. Gif +Name[he]=מידע GIF +Name[hi]=GIF जानकारी +Name[hr]=GIF Informacije +Name[hu]=GIF-jellemzők +Name[is]=GIF upplýsingar +Name[it]=Informazioni GIF +Name[ja]=GIF 情報 +Name[kk]=GIF мәліметі +Name[km]=ព័ត៌មាន GIF +Name[lt]=GIF informacija +Name[ms]=Maklumat GIF +Name[nds]=GIF-Info +Name[ne]=GIF सूचना +Name[nl]=GIF-info +Name[nn]=GIF-info +Name[nso]=Tshedimoso ya GIF +Name[pa]=GIF ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku GIF +Name[pt]=Informação do GIF +Name[pt_BR]=Informação sobre GIF +Name[ro]=Informaţii GIF +Name[ru]=Информация о GIF +Name[se]=GIF-dieđut +Name[sl]=Podatki o GIF +Name[sr]=GIF информације +Name[sr@Latn]=GIF informacije +Name[sv]=Gif-information +Name[ta]=GIF தகவல் +Name[tg]=Иттилоот оиди GIF +Name[th]=ข้อมูลแฟ้ม GIF +Name[tr]=GIF Bilgisi +Name[uk]=Інформація по GIF +Name[uz]=GIF haqida maʼlumot +Name[uz@cyrillic]=GIF ҳақида маълумот +Name[ven]=Mafhungo a GIF +Name[wa]=Informåcion sol imådje GIF +Name[xh]=Ulwazi lwe GIF +Name[zh_CN]=GIF 信息 +Name[zh_HK]=GIF 資訊 +Name[zh_TW]=GIF 資訊 +Name[zu]=Ulwazi lwe-GIF +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_gif +MimeType=image/gif +PreferredItems=Comment,Resolution diff --git a/kfile-plugins/gif/kfile_gif.h b/kfile-plugins/gif/kfile_gif.h new file mode 100644 index 00000000..6f932f37 --- /dev/null +++ b/kfile-plugins/gif/kfile_gif.h @@ -0,0 +1,37 @@ +/* This file is part of the KDE project + * + * 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_GIF_H__ +#define __KFILE_GIF_H__ + +#include <kfilemetainfo.h> +#include <kurl.h> + +class QStringList; + +class KGifPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KGifPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo ( KFileMetaInfo& info, uint what ); +}; + +#endif diff --git a/kfile-plugins/ico/Makefile.am b/kfile-plugins/ico/Makefile.am new file mode 100644 index 00000000..df3d65ca --- /dev/null +++ b/kfile-plugins/ico/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for ico file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_ico.h + +kde_module_LTLIBRARIES = kfile_ico.la + +kfile_ico_la_SOURCES = kfile_ico.cpp +kfile_ico_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_ico_la_LIBADD = $(LIB_KSYCOCA) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_ico.cpp -o $(podir)/kfile_ico.pot + +services_DATA = kfile_ico.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/ico/kfile_ico.cpp b/kfile-plugins/ico/kfile_ico.cpp new file mode 100644 index 00000000..01c5b65e --- /dev/null +++ b/kfile-plugins/ico/kfile_ico.cpp @@ -0,0 +1,148 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk> + * + * 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 <config.h> +#include "kfile_ico.h" + +#include <kprocess.h> +#include <klocale.h> +#include <kgenericfactory.h> +#include <kstringvalidator.h> +#include <kdebug.h> + +#include <qdict.h> +#include <qvalidator.h> +#include <qcstring.h> +#include <qfile.h> +#include <qdatetime.h> + +#if !defined(__osf__) +#include <inttypes.h> +#else +typedef unsigned long uint32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; +#endif + +typedef KGenericFactory<KIcoPlugin> IcoFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_ico, IcoFactory( "kfile_ico" )) + +KIcoPlugin::KIcoPlugin(QObject *parent, const char *name, + const QStringList &args) + + : KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-ico" ); + + KFileMimeTypeInfo::GroupInfo* group = 0L; + + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo(group, "Number", i18n("Number of Icons"), QVariant::Int); + + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size); + item = addItemInfo(group, "Colors", i18n("Colors"), QVariant::Int); + + item = addItemInfo(group, "DimensionsM", i18n("Dimensions (1st icon)"), QVariant::Size); + item = addItemInfo(group, "ColorsM", i18n("Colors (1st icon)"), QVariant::Int); +} + + +bool KIcoPlugin::readInfo( KFileMetaInfo& info, uint what) +{ + + + QFile file(info.path()); + + if (!file.open(IO_ReadOnly)) + { + kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + QDataStream dstream(&file); + + // ICO files are little-endian + dstream.setByteOrder(QDataStream::LittleEndian); + + + // read the beginning of the file and make sure it looks ok + uint16_t ico_reserved; + uint16_t ico_type; + uint16_t ico_count; + + dstream >> ico_reserved; + dstream >> ico_type; + dstream >> ico_count; + + if ((ico_reserved != 0) || (ico_type != 1) || (ico_count < 1)) + return false; + + + // now loop through each of the icon entries + uint8_t icoe_width; + uint8_t icoe_height; + uint8_t icoe_colorcount; + uint8_t icoe_reserved; + uint16_t icoe_planes; + uint16_t icoe_bitcount; + uint32_t icoe_bytesinres; + uint32_t icoe_imageoffset; + + // read the data on the 1st icon + dstream >> icoe_width; + dstream >> icoe_height; + dstream >> icoe_colorcount; + dstream >> icoe_reserved; + dstream >> icoe_planes; + dstream >> icoe_bitcount; + dstream >> icoe_bytesinres; + dstream >> icoe_imageoffset; + + + // output the useful bits + KFileMetaInfoGroup group = appendGroup(info, "Technical"); + appendItem(group, "Number", ico_count); + + if (ico_count == 1) { + appendItem(group, "Dimensions", QSize(icoe_width, icoe_height)); + + if (icoe_colorcount > 0) + appendItem(group, "Colors", icoe_colorcount); + else if (icoe_bitcount > 0) + appendItem(group, "Colors", 2 ^ icoe_bitcount); + + } else { + + appendItem(group, "DimensionsM", QSize(icoe_width, icoe_height)); + + if (icoe_colorcount > 0) + appendItem(group, "ColorsM", icoe_colorcount); + else if (icoe_bitcount > 0) + appendItem(group, "ColorsM", 2 ^ icoe_bitcount); + + } + + return true; +} + +#include "kfile_ico.moc" diff --git a/kfile-plugins/ico/kfile_ico.desktop b/kfile-plugins/ico/kfile_ico.desktop new file mode 100644 index 00000000..dcd98f50 --- /dev/null +++ b/kfile-plugins/ico/kfile_ico.desktop @@ -0,0 +1,65 @@ +[Desktop Entry] +Type=Service +Name=ICO Info +Name[af]=Ico Inligting +Name[ar]=معلومات ICO +Name[br]=Titouroù ICO +Name[ca]=Informació d'ICO +Name[cs]=ICO info +Name[cy]=Gwybodaeth ICO +Name[da]=ICO-info +Name[de]=ICO-Info +Name[el]=Πληροφορίες ICO +Name[eo]=ICO-informo +Name[es]=Info ICO +Name[et]=ICO info +Name[fa]=اطلاعات ICO +Name[fi]=ICO-tiedot +Name[fr]=Informations ICO +Name[gl]=Inf. ICO +Name[he]=מידע ICO +Name[hi]=ICO जानकारी +Name[hr]=ICO informacije +Name[hu]=ICO-jellemzők +Name[is]=ICO upplýsingar +Name[it]=Informazioni ICO +Name[ja]=ICO 情報 +Name[kk]=ICO мәліметі +Name[km]=ព័ត៌មាន ICO +Name[lt]=ICO informacija +Name[ms]= Maklumat ICO +Name[nds]=ICO-Info +Name[ne]=ICO सूचना +Name[nl]=ICO-info +Name[nn]=ICO-info +Name[nso]=Tshedimoso ya ICO +Name[pa]=ICO ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku ICO +Name[pt]=Informação do ICO +Name[pt_BR]=Informação sobre ICO +Name[ro]=Informaţii ICO +Name[ru]=Информация об ICO +Name[se]=ICO-dieđut +Name[sl]=Podatki o ICO +Name[sr]=ICO информације +Name[sr@Latn]=ICO informacije +Name[sv]=Ico-information +Name[ta]=ICO தகவல் +Name[tg]=Иттилоот оиди ICO +Name[th]=ข้อมูลแฟ้ม ICO +Name[tr]=ICO Bilgisi +Name[uk]=Інформація по ICO +Name[uz]=ICO haqida maʼlumot +Name[uz@cyrillic]=ICO ҳақида маълумот +Name[ven]=Mafhungo a ICO +Name[wa]=Informåcion sol imådjete ICO +Name[xh]=Ulwazi lwe ICO +Name[zh_CN]=ICO 信息 +Name[zh_HK]=ICO 資訊 +Name[zh_TW]=ICO 資訊 +Name[zu]=Ulwazi lwe-ICO +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_ico +MimeType=image/x-ico +PreferredGroups=Technical +PreferredItems=Number,Resolution,Colors,ResolutionM,ColorsM diff --git a/kfile-plugins/ico/kfile_ico.h b/kfile-plugins/ico/kfile_ico.h new file mode 100644 index 00000000..e06e8094 --- /dev/null +++ b/kfile-plugins/ico/kfile_ico.h @@ -0,0 +1,37 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk> + * + * 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_ICO_H__ +#define __KFILE_ICO_H__ + +#include <kfilemetainfo.h> + +class QStringList; + +class KIcoPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KIcoPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); +}; + +#endif diff --git a/kfile-plugins/jpeg/Makefile.am b/kfile-plugins/jpeg/Makefile.am new file mode 100644 index 00000000..fac3b392 --- /dev/null +++ b/kfile-plugins/jpeg/Makefile.am @@ -0,0 +1,24 @@ +## 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 new file mode 100644 index 00000000..6b714426 --- /dev/null +++ b/kfile-plugins/jpeg/README @@ -0,0 +1,35 @@ +------------------------------------------------------------------------------- +Thanks to: +Matthias Wandel <matt@rim.net> +jhead (http://www.sentex.net/~mwandel/jhead/) + +Groult Richard <rgroult@jalix.org> +showimg (http://ric.jalix.org/) + +Bryce Nesbitt for setcomment +based on wrjpgcom.c, Copyright (C) 1994-1997, Thomas G. Lane. + +Frank Pieczynski <pieczy@knuut.de> + +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 new file mode 100644 index 00000000..f25e8a78 --- /dev/null +++ b/kfile-plugins/jpeg/exif.cpp @@ -0,0 +1,961 @@ +//-------------------------------------------------------------------------- +// 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 <qwmatrix.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 (QFile & 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, 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 = QString::fromLatin1((const char*)ValuePtr, 31); + break; + + case TAG_MODEL: + ExifData::CameraModel = QString::fromLatin1((const char*)ValuePtr, 39); + break; + + case TAG_ORIENTATION: + Orientation = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_DATETIME_ORIGINAL: + DateTime = QString::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 = QString::fromLatin1((const char*)(a+ValuePtr), 199); + break; + } + } + }else{ + UserComment = QString::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 (schoech@gmx.de) + + 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 = QString::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 QString & path) +{ + int ret; + + QFile 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 +//-------------------------------------------------------------------------- +QImage ExifData::getThumbnail() { + if (!isThumbnailSane()) return NULL; + if (!Orientation || Orientation == 1) return Thumbnail; + + // now fix orientation + QWMatrix M; + QWMatrix flip= QWMatrix(-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 new file mode 100644 index 00000000..2b4e5606 --- /dev/null +++ b/kfile-plugins/jpeg/exif.h @@ -0,0 +1,127 @@ +#ifndef __EXIF_H__ +#define __EXIF_H__ + +/** + exif.h +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <time.h> + +#include "qstring.h" +#include "qfile.h" +#include "qimage.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]; + + QString CameraMake; + QString CameraModel; + QString 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; + QString UserComment; + QString Comment; + QImage Thumbnail; + + int ReadJpegSections (QFile & 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 QString &); + QString getCameraMake() { return CameraMake; } + QString getCameraModel() { return CameraModel; } + QString 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; } + QString getUserComment() { return UserComment; } + QString getComment() { return Comment; } + QImage 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 new file mode 100644 index 00000000..d302cf65 --- /dev/null +++ b/kfile-plugins/jpeg/kfile_jpeg.cpp @@ -0,0 +1,531 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Frank Pieczynski <pieczy@knuut.de>, + * 2002 Carsten Pfeiffer <pfeiffer@kde.org> + * 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 <qcstring.h> +#include <qfile.h> +#include <qdatetime.h> +#include <qdict.h> +#include <qvalidator.h> +#include <qimage.h> + +#include "exif.h" + +#define EXIFGROUP "Jpeg EXIF Data" + +typedef KGenericFactory<KJpegPlugin> JpegFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_jpeg, JpegFactory("kfile_jpeg")) + +KJpegPlugin::KJpegPlugin(QObject *parent, const char *name, + const QStringList &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"), QVariant::String); + setAttributes( item, + KFileMimeTypeInfo::Modifiable | + KFileMimeTypeInfo::Addable | + KFileMimeTypeInfo::MultiLine ); + + item = addItemInfo( exifGroup, "Manufacturer", i18n("Camera Manufacturer"), + QVariant::String ); + + item = addItemInfo( exifGroup, "Model", i18n("Camera Model"), + QVariant::String ); + + item = addItemInfo( exifGroup, "Date/time", i18n("Date/Time"), + QVariant::DateTime ); + + item = addItemInfo( exifGroup, "CreationDate", i18n("Creation Date"), + QVariant::Date ); + + item = addItemInfo( exifGroup, "CreationTime", i18n("Creation Time"), + QVariant::Time ); + + item = addItemInfo( exifGroup, "Dimensions", i18n("Dimensions"), + QVariant::Size ); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit( item, KFileMimeTypeInfo::Pixels ); + + item = addItemInfo( exifGroup, "Orientation", i18n("Orientation"), + QVariant::Int ); + + item = addItemInfo( exifGroup, "ColorMode", i18n("Color Mode"), + QVariant::String ); + + item = addItemInfo( exifGroup, "Flash used", i18n("Flash Used"), + QVariant::String ); + item = addItemInfo( exifGroup, "Focal length", i18n("Focal Length"), + QVariant::String ); + setUnit( item, KFileMimeTypeInfo::Millimeters ); + + item = addItemInfo( exifGroup, "35mm equivalent", i18n("35mm Equivalent"), + QVariant::Int ); + setUnit( item, KFileMimeTypeInfo::Millimeters ); + + item = addItemInfo( exifGroup, "CCD width", i18n("CCD Width"), + QVariant::String ); + setUnit( item, KFileMimeTypeInfo::Millimeters ); + + item = addItemInfo( exifGroup, "Exposure time", i18n("Exposure Time"), + QVariant::String ); + setHint( item, KFileMimeTypeInfo::Seconds ); + + item = addItemInfo( exifGroup, "Aperture", i18n("Aperture"), + QVariant::String ); + + item = addItemInfo( exifGroup, "Focus dist.", i18n("Focus Dist."), + QVariant::String ); + + item = addItemInfo( exifGroup, "Exposure bias", i18n("Exposure Bias"), + QVariant::String ); + + item = addItemInfo( exifGroup, "Whitebalance", i18n("Whitebalance"), + QVariant::String ); + + item = addItemInfo( exifGroup, "Metering mode", i18n("Metering Mode"), + QVariant::String ); + + item = addItemInfo( exifGroup, "Exposure", i18n("Exposure"), + QVariant::String ); + + item = addItemInfo( exifGroup, "ISO equiv.", i18n("ISO Equiv."), + QVariant::String ); + + item = addItemInfo( exifGroup, "JPEG quality", i18n("JPEG Quality"), + QVariant::String ); + + item = addItemInfo( exifGroup, "User comment", i18n("User Comment"), + QVariant::String ); + setHint(item, KFileMimeTypeInfo::Description); + + item = addItemInfo( exifGroup, "JPEG process", i18n("JPEG Process"), + QVariant::String ); + + item = addItemInfo( exifGroup, "Thumbnail", i18n("Thumbnail"), + QVariant::Image ); + setHint( item, KFileMimeTypeInfo::Thumbnail ); + +// ### +// exifGroup.setSupportsVariableKeys(true); +} + +QValidator* KJpegPlugin::createValidator(const KFileMetaInfoItem& /*item*/, + QObject */*parent*/, + const char */*name*/ ) const +{ + // no need to return a validator that validates everything as OK :) +// if (item.isEditable()) +// return new QRegExpValidator(QRegExp(".*"), parent, name); +// else + return 0L; +} + +bool KJpegPlugin::writeInfo( const KFileMetaInfo& info ) const +{ + QString comment = info[EXIFGROUP].value("Comment").toString(); + QString 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( QFile::encodeName( path ), comment.utf8() ) ) { + return false; + } + return true; +} + +bool KJpegPlugin::readInfo( KFileMetaInfo& info, uint what ) +{ + const QString path( info.path() ); + if ( path.isEmpty() ) // remote file + return false; + + QString 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()){ + QDateTime 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", QSize( 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 ) { + QString 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", + QString().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", + QString().sprintf("%4.2f", ImageInfo.getCCDWidth()) ); + } + + if (ImageInfo.getExposureTime()){ + tag=QString().sprintf("%6.3f", ImageInfo.getExposureTime()); + float exposureTime = ImageInfo.getExposureTime(); + if (exposureTime > 0 && exposureTime <= 0.5){ + tag+=QString().sprintf(" (1/%d)", (int)(0.5 + 1/exposureTime) ); + } + appendItem( exifGroup, "Exposure time", tag ); + } + + if (ImageInfo.getApertureFNumber()){ + appendItem( exifGroup, "Aperture", + QString().sprintf("f/%3.1f", + (double)ImageInfo.getApertureFNumber())); + } + + if (ImageInfo.getDistance()){ + if (ImageInfo.getDistance() < 0){ + tag=i18n("Infinite"); + }else{ + tag=QString().sprintf("%5.2fm",(double)ImageInfo.getDistance()); + } + appendItem( exifGroup, "Focus dist.", tag ); + } + + if (ImageInfo.getExposureBias()){ + appendItem( exifGroup, "Exposure bias", + QString().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.", + QString().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", + QString::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 +QDateTime KJpegPlugin::parseDateTime( const QString& string ) +{ + QDateTime dt; + if ( string.length() != 19 ) + return dt; + + QString year = string.left( 4 ); + QString month = string.mid( 5, 2 ); + QString day = string.mid( 8, 2 ); + QString hour = string.mid( 11, 2 ); + QString minute = string.mid( 14, 2 ); + QString 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( QDate( y, mo, d ) ); + dt.setTime( QTime( 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 new file mode 100644 index 00000000..3ca5a011 --- /dev/null +++ b/kfile-plugins/jpeg/kfile_jpeg.desktop @@ -0,0 +1,64 @@ +[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-KDE-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 new file mode 100644 index 00000000..5c585fb0 --- /dev/null +++ b/kfile-plugins/jpeg/kfile_jpeg.h @@ -0,0 +1,43 @@ +/* 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 <qdatetime.h> +#include <kfilemetainfo.h> + +class KJpegPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KJpegPlugin( QObject *parent, const char *name, + const QStringList& args ); + + virtual bool readInfo ( KFileMetaInfo& info, uint what ); + virtual bool writeInfo( const KFileMetaInfo& info ) const; + virtual QValidator* createValidator( const KFileMetaInfoItem& item, + QObject* parent, const char* name) const; + +private: + QDateTime parseDateTime( const QString& string ); +}; + +#endif diff --git a/kfile-plugins/jpeg/kfile_setcomment.cpp b/kfile-plugins/jpeg/kfile_setcomment.cpp new file mode 100644 index 00000000..07dca273 --- /dev/null +++ b/kfile-plugins/jpeg/kfile_setcomment.cpp @@ -0,0 +1,536 @@ +/* + * 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 diff --git a/kfile-plugins/pcx/Makefile.am b/kfile-plugins/pcx/Makefile.am new file mode 100644 index 00000000..111b4c28 --- /dev/null +++ b/kfile-plugins/pcx/Makefile.am @@ -0,0 +1,21 @@ +## Makefile.am for PCX file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +noinst_HEADERS = kfile_pcx.h + +kde_module_LTLIBRARIES = kfile_pcx.la + +kfile_pcx_la_SOURCES = kfile_pcx.cpp +kfile_pcx_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_pcx_la_LIBADD = $(LIB_KIO) $(LIBTIFF) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_pcx.pot + +services_DATA = kfile_pcx.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/pcx/kfile_pcx.cpp b/kfile-plugins/pcx/kfile_pcx.cpp new file mode 100644 index 00000000..a7468a57 --- /dev/null +++ b/kfile-plugins/pcx/kfile_pcx.cpp @@ -0,0 +1,122 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Nadeem Hasan <nhasan@kde.org> + * + * 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 "kfile_pcx.h" + +#include <kgenericfactory.h> +#include <kdebug.h> + +#include <qdatastream.h> +#include <qfile.h> + +typedef KGenericFactory<KPcxPlugin> PcxFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_pcx, PcxFactory("kfile_pcx")) + +QDataStream &operator>>( QDataStream &s, PALETTE &pal ) +{ + for ( int i=0; i<16; ++i ) + s >> pal.p[ i ].r >> pal.p[ i ].g >> pal.p[ i ].b; + + return s; +} + +QDataStream &operator>>( QDataStream &s, PCXHEADER &ph ) +{ + s >> ph.Manufacturer; + s >> ph.Version; + s >> ph.Encoding; + s >> ph.Bpp; + s >> ph.XMin >> ph.YMin >> ph.XMax >> ph.YMax; + s >> ph.HDpi >> ph.YDpi; + s >> ph.Palette; + s >> ph.Reserved; + s >> ph.NPlanes; + s >> ph.BytesPerLine; + s >> ph.PaletteInfo; + s >> ph.HScreenSize; + s >> ph.VScreenSize; + + return s; +} + +KPcxPlugin::KPcxPlugin( QObject *parent, const char *name, + const QStringList &args ) : KFilePlugin( parent, name, args ) +{ + kdDebug(7034) << "PCX file meta info plugin" << endl; + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-pcx" ); + + KFileMimeTypeInfo::GroupInfo* group = + addGroupInfo( info, "General", i18n( "General" ) ); + + KFileMimeTypeInfo::ItemInfo* item; + item = addItemInfo( group, "Dimensions", i18n( "Dimensions" ), + QVariant::Size ); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit( item, KFileMimeTypeInfo::Pixels ); + item = addItemInfo( group, "BitDepth", i18n( "Bit Depth" ), + QVariant::Int ); + setUnit( item, KFileMimeTypeInfo::BitsPerPixel ); + item = addItemInfo( group, "Resolution", i18n( "Resolution" ), + QVariant::Size ); + setUnit( item, KFileMimeTypeInfo::DotsPerInch ); + item = addItemInfo( group, "Compression", i18n( "Compression" ), + QVariant::String ); +} + +bool KPcxPlugin::readInfo( KFileMetaInfo& info, uint ) +{ + if ( info.path().isEmpty() ) + return false; + + struct PCXHEADER header; + + QFile f( info.path() ); + if ( !f.open( IO_ReadOnly ) ) + return false; + + QDataStream s( &f ); + s.setByteOrder( QDataStream::LittleEndian ); + + s >> header; + + int w = ( header.XMax-header.XMin ) + 1; + int h = ( header.YMax-header.YMin ) + 1; + int bpp = header.Bpp*header.NPlanes; + + KFileMetaInfoGroup group = appendGroup( info, "General" ); + + appendItem( group, "Dimensions", QSize( w, h ) ); + appendItem( group, "BitDepth", bpp ); + appendItem( group, "Resolution", QSize( header.HDpi, header.YDpi ) ); + if ( header.Encoding == 1 ) + appendItem( group, "Compression", i18n( "Yes (RLE)" ) ); + else + appendItem( group, "Compression", i18n( "None" ) ); + + f.close(); + + return true; +} + +#include "kfile_pcx.moc" + +/* vim: et sw=2 ts=2 +*/ + diff --git a/kfile-plugins/pcx/kfile_pcx.desktop b/kfile-plugins/pcx/kfile_pcx.desktop new file mode 100644 index 00000000..9a3f2090 --- /dev/null +++ b/kfile-plugins/pcx/kfile_pcx.desktop @@ -0,0 +1,62 @@ +[Desktop Entry] +Type=Service +Name=PCX File Meta Info +Name[ar]=معلومات ملف PCX +Name[br]=Meta-titouroù ar restr PCX +Name[bs]=PCX meta-podaci +Name[ca]=Metainformació de fitxer PCX +Name[cs]=Metainformace obrázku typu PCX +Name[cy]=Meta-wybodaeth Ffeil PCX +Name[da]=PCX Fil-meta-info +Name[de]=PCX Metainformation +Name[el]=Μετα-πληροφορίες αρχείου PCX +Name[eo]=PCX-dosiera metainformo +Name[es]=Info meta de archivos PCX +Name[et]=PCX faili metainfo +Name[eu]=PCX fitxategi meta info +Name[fa]=فرااطلاعات پروندۀ PCX +Name[fi]=PCX-tiedoston metatiedot +Name[fr]=Méta Informations sur les fichiers PCX +Name[gl]=Inf. metaficheiro PCX +Name[he]=מידע PCX +Name[hi]=PCX फ़ाइल मेटा जानकारी +Name[hu]=PCX-jellemzők +Name[is]=PCX File Meta upplýsingar +Name[it]=Informazioni PCX +Name[ja]=PCX ファイルメタ情報 +Name[kk]=PCX файлдың мета деректері +Name[km]=ព័ត៌មានមេតារបស់ឯកសារ PCX +Name[lt]=PCX bylos meta informacija +Name[ms]=Maklumat Meta Fail PCX +Name[nb]=PCX-filmetainfo +Name[nds]=PCX-Metainfo +Name[ne]=PCX फाइल मेटा सूचना +Name[nl]=PCX meta-info +Name[nn]=PCX-filmetainfo +Name[pl]=Informacja o pliku PCX +Name[pt]=Meta-Informação do Ficheiro PCX +Name[pt_BR]=Informação sobre Meta Arquivo PCX +Name[ro]=Metainformaţii PCX +Name[ru]=Информация о метафайле PCX +Name[se]=PCX-filla metadieđut +Name[sk]=Meta-info o súbore PCX +Name[sl]=Meta podatki o PCX +Name[sr]=Мета информације PCX фајла +Name[sr@Latn]=Meta informacije PCX fajla +Name[sv]=Metainformation om PCX-fil +Name[ta]=PCX File Meta தகவல் +Name[tg]=Иттилоот оиди метафайли PCX +Name[th]=ข้อมูลเมตาแฟ้ม PCX +Name[tr]=PCX Dosya Bilgisi +Name[uk]=Метаінформація про файл PCX +Name[uz]=PCX-faylining meta-maʼlumoti +Name[uz@cyrillic]=PCX-файлининг мета-маълумоти +Name[wa]=Informåcion sol imådje PCX +Name[zh_CN]=PCX 文件元信息 +Name[zh_HK]=PCX 檔案 Meta 資訊 +Name[zh_TW]=PCX 檔案 Meta 資訊 +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_pcx +MimeType=image/x-pcx +PreferredGroups=General +PreferredItems=Dimensions,Resolution,BitDepth,Compression diff --git a/kfile-plugins/pcx/kfile_pcx.h b/kfile-plugins/pcx/kfile_pcx.h new file mode 100644 index 00000000..434f89a3 --- /dev/null +++ b/kfile-plugins/pcx/kfile_pcx.h @@ -0,0 +1,88 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Nadeem Hasan <nhasan@kde.org> + * + * 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_PCX_H_ +#define __KFILE_PCX_H_ + +#include <kfilemetainfo.h> + +struct PALETTE +{ + struct + { + Q_UINT8 r; + Q_UINT8 g; + Q_UINT8 b; + } p[ 16 ]; +}; + +struct PCXHEADER +{ + Q_UINT8 Manufacturer; // Constant Flag, 10 = ZSoft .pcx + Q_UINT8 Version; // Version information + // 0 = Version 2.5 of PC Paintbrush + // 2 = Version 2.8 w/palette information + // 3 = Version 2.8 w/o palette information + // 4 = PC Paintbrush for Windows(Plus for + // Windows uses Ver 5) + // 5 = Version 3.0 and > of PC Paintbrush + // and PC Paintbrush +, includes + // Publisher's Paintbrush . Includes + // 24-bit .PCX files + Q_UINT8 Encoding; // 1 = .PCX run length encoding + Q_UINT8 Bpp; // Number of bits to represent a pixel + // (per Plane) - 1, 2, 4, or 8 + Q_UINT16 XMin; + Q_UINT16 YMin; + Q_UINT16 XMax; + Q_UINT16 YMax; + Q_UINT16 HDpi; + Q_UINT16 YDpi; + struct PALETTE Palette; + Q_UINT8 Reserved; // Should be set to 0. + Q_UINT8 NPlanes; // Number of color planes + Q_UINT16 BytesPerLine; // Number of bytes to allocate for a scanline + // plane. MUST be an EVEN number. Do NOT + // calculate from Xmax-Xmin. + Q_UINT16 PaletteInfo; // How to interpret palette- 1 = Color/BW, + // 2 = Grayscale ( ignored in PB IV/ IV + ) + Q_UINT16 HScreenSize; // Horizontal screen size in pixels. New field + // found only in PB IV/IV Plus + Q_UINT16 VScreenSize; // Vertical screen size in pixels. New field + // found only in PB IV/IV Plus + Q_UINT8 Filler[ 54 ]; // Blank to fill out 128 byte header. Set all + // bytes to 0 +}; + +class KPcxPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KPcxPlugin(QObject *parent, const char *name, const QStringList& args); + virtual bool readInfo(KFileMetaInfo& info, uint what); + +private: +}; + +#endif + +/* vim: et sw=2 ts=2 +*/ + diff --git a/kfile-plugins/pdf/Makefile.am b/kfile-plugins/pdf/Makefile.am new file mode 100644 index 00000000..841d9980 --- /dev/null +++ b/kfile-plugins/pdf/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for the pdf file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) $(POPPLER_CFLAGS) + +# these are the headers for your project +noinst_HEADERS = kfile_pdf.h + +kde_module_LTLIBRARIES = kfile_pdf.la + +kfile_pdf_la_SOURCES = kfile_pdf.cpp +kfile_pdf_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_pdf_la_LIBADD = $(LIB_KIO) $(POPPLER_LIBS) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_pdf.pot + +services_DATA = kfile_pdf.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/pdf/configure.in.in b/kfile-plugins/pdf/configure.in.in new file mode 100644 index 00000000..926497a5 --- /dev/null +++ b/kfile-plugins/pdf/configure.in.in @@ -0,0 +1,15 @@ +AC_ARG_WITH([poppler], + [AC_HELP_STRING([--with-poppler], + [Enable PDF support through poppler @<:@default=check@:>@])], + [], with_poppler=check) + +# Compile the pdf meta info plugin only if Poppler is available +if test "x$with_poppler" != xno; then + PKG_CHECK_MODULES(POPPLER, poppler-qt >= 0.3.1, have_poppler=yes, have_poppler=no) + + if test "x$with_poppler" != xcheck && test "x$have_poppler" != xyes; then + AC_MSG_ERROR([--with-poppler was given, but test for poppler failed]) + fi +fi + +AM_CONDITIONAL(include_PDF, test "x$have_poppler" = xyes) diff --git a/kfile-plugins/pdf/kfile_pdf.cpp b/kfile-plugins/pdf/kfile_pdf.cpp new file mode 100644 index 00000000..d5beeb60 --- /dev/null +++ b/kfile-plugins/pdf/kfile_pdf.cpp @@ -0,0 +1,104 @@ +/* This file is part of the KDE project + * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@kde.org> + * + * 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. + * + * $Id$ + */ + +#include "kfile_pdf.h" + +#include <kgenericfactory.h> +#include <kdebug.h> + +typedef KGenericFactory<KPdfPlugin> PdfFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_pdf, PdfFactory("kfile_pdf")) + +KPdfPlugin::KPdfPlugin(QObject *parent, const char *name, const QStringList &preferredItems) + : KFilePlugin(parent, name, preferredItems) +{ + kdDebug(7034) << "pdf plugin\n"; + + // set up our mime type + KFileMimeTypeInfo* info = addMimeTypeInfo( "application/pdf" ); + + // general group + KFileMimeTypeInfo::GroupInfo* group = addGroupInfo(info, "General", i18n("General")); + + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo(group, "Title", i18n("Title"), QVariant::String); + setHint(item, KFileMimeTypeInfo::Name); + item = addItemInfo(group, "Subject", i18n("Subject"), QVariant::String); + setHint(item, KFileMimeTypeInfo::Description); + item = addItemInfo(group, "Author", i18n("Author"), QVariant::String); + setHint(item, KFileMimeTypeInfo::Author); + addItemInfo(group, "Keywords", i18n("Key Words"), QVariant::String); + addItemInfo(group, "Creator", i18n("Creator"), QVariant::String); + addItemInfo(group, "Producer", i18n("Producer"), QVariant::String); + addItemInfo(group, "CreationDate", i18n("Creation Date"), QVariant::DateTime); + addItemInfo(group, "ModificationDate", i18n("Modified"), QVariant::DateTime); + addItemInfo(group, "Pages", i18n("Pages"), QVariant::Int); + addItemInfo(group, "Protected", i18n("Protected"), QVariant::String); + addItemInfo(group, "Linearized", i18n("Linearized"), QVariant::String); + addItemInfo(group, "Version", i18n("Version"), QVariant::String); +} + +bool KPdfPlugin::readInfo( KFileMetaInfo& info, uint /* what */) +{ + Poppler::Document *doc = Poppler::Document::load(info.path()); + if (!doc || doc->isLocked()) + { + delete doc; + return false; + } + + KFileMetaInfoGroup generalGroup = appendGroup(info, "General"); + + appendItem(generalGroup, "Title", doc->getInfo("Title") ); + appendItem(generalGroup, "Subject", doc->getInfo("Subject") ); + appendItem(generalGroup, "Author", doc->getInfo("Author") ); + appendItem(generalGroup, "Keywords", doc->getInfo("Keywords") ); + appendItem(generalGroup, "Creator", doc->getInfo("Creator") ); + appendItem(generalGroup, "Producer", doc->getInfo("Producer") ); + + appendItem(generalGroup, "CreationDate", doc->getDate("CreationDate") ); + appendItem(generalGroup, "ModificationDate", doc->getDate("ModDate") ); + appendItem(generalGroup, "Pages", doc->getNumPages() ); + + QString enc; + if (doc->isEncrypted()) + { + enc = i18n("Yes (Can Print:%1 Can Copy:%2 Can Change:%3 Can Add notes:%4)") + .arg(doc->okToPrint() ? i18n("Yes") : i18n("No")) + .arg(doc->okToCopy() ? i18n("Yes") : i18n("No")) + .arg(doc->okToChange() ? i18n("Yes") : i18n("No")) + .arg(doc->okToAddNotes() ? i18n("Yes") : i18n("No")); + } + else enc = i18n("No"); + + appendItem(generalGroup, "Protected", enc ); + appendItem(generalGroup, "Linearized", doc->isLinearized() ? i18n("Yes") : i18n("No") ); + QString versionString = QString("%1").arg( doc->getPDFVersion(), 0, 'f', 1 ); + appendItem(generalGroup, "Version", versionString ); + + delete doc; + + return true; +} + +#include "kfile_pdf.moc" + diff --git a/kfile-plugins/pdf/kfile_pdf.desktop b/kfile-plugins/pdf/kfile_pdf.desktop new file mode 100644 index 00000000..cdc6a8e8 --- /dev/null +++ b/kfile-plugins/pdf/kfile_pdf.desktop @@ -0,0 +1,64 @@ +[Desktop Entry] +Type=Service +Name=PDF Info +Name[af]=Pdf Inligting +Name[ar]=معلومات PDF +Name[br]=Titouroù PDF +Name[ca]=Informació de PDF +Name[cs]=PDF info +Name[cy]=Gybodaeth PDF +Name[da]=PDF-info +Name[de]=PDF-Info +Name[el]=Πληροφορίες PDF +Name[eo]=PDF-informo +Name[es]=Info PDF +Name[et]=PDF info +Name[fa]=اطلاعات PDF +Name[fi]=PDF-tiedot +Name[fr]=Informations PDF +Name[gl]=Inf. PDF +Name[he]=מידע PDF +Name[hi]=PDF जानकारी +Name[hr]=PDF Informacije +Name[hu]=PDF-jellemzők +Name[is]=PDF upplýsingar +Name[it]=Informazioni PDF +Name[ja]=PDF 情報 +Name[kk]=PDF мәліметі +Name[km]=ព័ត៌មាន PDF +Name[lt]=PDF informacija +Name[ms]=Maklumat PDF +Name[nds]=PDF-Info +Name[ne]=PDF सूचना +Name[nl]=PDF-info +Name[nn]=PDF-info +Name[nso]=Tshedimoso ya PDF +Name[pa]=PDF ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku PDF +Name[pt]=Informação do PDF +Name[pt_BR]=Informação sobre PDF +Name[ro]=Informaţii PDF +Name[ru]=Информация о PDF +Name[se]=PDF-dieđut +Name[sl]=Podatki o PDF +Name[sr]=PDF информације +Name[sr@Latn]=PDF informacije +Name[sv]=PDF-information +Name[ta]=PDF தகவல் +Name[tg]=Иттилоот оиди PDF +Name[th]=ข้อมูลแฟ้ม PDF +Name[tr]=PDF Bilgisi +Name[uk]=Інформація про PDF +Name[uz]=PDF haqida maʼlumot +Name[uz@cyrillic]=PDF ҳақида маълумот +Name[ven]=Mafhungo a PDF +Name[wa]=Informåcion sol documint PDF +Name[xh]=PDF Ulwazi +Name[zh_CN]=PDF 信息 +Name[zh_HK]=PDF 資訊 +Name[zh_TW]=PDF 資訊 +Name[zu]=Ulwazi lwe-PDF +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_pdf +MimeType=application/pdf +PreferredItems=Title,Subject,Author,Keywords,Creator,Producer,CreationDate,ModificationDate,Pages,Protected,Linearized,Version diff --git a/kfile-plugins/pdf/kfile_pdf.h b/kfile-plugins/pdf/kfile_pdf.h new file mode 100644 index 00000000..b0214f54 --- /dev/null +++ b/kfile-plugins/pdf/kfile_pdf.h @@ -0,0 +1,38 @@ +/* This file is part of the KDE project + * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@kde.org> + * + * 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. + * + * $Id$ + */ + +#ifndef __KFILE_PDF_H__ +#define __KFILE_PDF_H__ + +#include <kfilemetainfo.h> +#include <poppler-qt.h> + +class QStringList; + +class KPdfPlugin: public KFilePlugin +{ +Q_OBJECT +public: + KPdfPlugin( QObject *parent, const char *name, const QStringList& preferredItems ); + + virtual bool readInfo(KFileMetaInfo& info, uint what); +}; + +#endif diff --git a/kfile-plugins/png/Makefile.am b/kfile-plugins/png/Makefile.am new file mode 100644 index 00000000..9aa820b6 --- /dev/null +++ b/kfile-plugins/png/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for png file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_png.h + +kde_module_LTLIBRARIES = kfile_png.la + +kfile_png_la_SOURCES = kfile_png.cpp +kfile_png_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_png_la_LIBADD = $(LIB_KIO) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_png.pot + +services_DATA = kfile_png.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/png/kfile_png.cpp b/kfile-plugins/png/kfile_png.cpp new file mode 100644 index 00000000..c3e54b66 --- /dev/null +++ b/kfile-plugins/png/kfile_png.cpp @@ -0,0 +1,315 @@ +/* This file is part of the KDE project + * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@kde.org> + * + * 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. + * + * $Id$ + */ + +#include <stdlib.h> +#include "kfile_png.h" + +#include <kurl.h> +#include <kprocess.h> +#include <klocale.h> +#include <kgenericfactory.h> +#include <kdebug.h> + +#include <qcstring.h> +#include <qfile.h> +#include <qdatetime.h> +#include <qdict.h> +#include <qvalidator.h> +#include <zlib.h> + +// some defines to make it easier +// don't tell me anything about preprocessor usage :) +#define CHUNK_SIZE(data, index) ((data[index ]<<24) + (data[index+1]<<16) + \ + (data[index+2]<< 8) + data[index+3]) +#define CHUNK_TYPE(data, index) &data[index+4] +#define CHUNK_HEADER_SIZE 12 +#define CHUNK_DATA(data, index, offset) data[8+index+offset] + +// known translations for common png keys +static const char* knownTranslations[] +#ifdef __GNUC__ +__attribute__((unused)) +#endif + = { + I18N_NOOP("Title"), + I18N_NOOP("Author"), + I18N_NOOP("Description"), + I18N_NOOP("Copyright"), + I18N_NOOP("Creation Time"), + I18N_NOOP("Software"), + I18N_NOOP("Disclaimer"), + I18N_NOOP("Warning"), + I18N_NOOP("Source"), + I18N_NOOP("Comment") +}; + +// and for the colors +static const char* colors[] = { + I18N_NOOP("Grayscale"), + I18N_NOOP("Unknown"), + I18N_NOOP("RGB"), + I18N_NOOP("Palette"), + I18N_NOOP("Grayscale/Alpha"), + I18N_NOOP("Unknown"), + I18N_NOOP("RGB/Alpha") +}; + + // and compressions +static const char* compressions[] = +{ + I18N_NOOP("Deflate") +}; + + // interlaced modes +static const char* interlaceModes[] = { + I18N_NOOP("None"), + I18N_NOOP("Adam7") +}; + +typedef KGenericFactory<KPngPlugin> PngFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_png, PngFactory("kfile_png")) + +KPngPlugin::KPngPlugin(QObject *parent, const char *name, + const QStringList &args) + : KFilePlugin(parent, name, args) +{ + kdDebug(7034) << "png plugin\n"; + + // set up our mime type + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/png" ); + + KFileMimeTypeInfo::GroupInfo* group = 0; + KFileMimeTypeInfo::ItemInfo* item = 0; + + // comment group + group = addGroupInfo(info, "Comment", i18n("Comment")); + addVariableInfo(group, QVariant::String, 0); + + // technical group + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit(item, KFileMimeTypeInfo::Pixels); + + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); + + addItemInfo(group, "ColorMode", i18n("Color Mode"), QVariant::String); + addItemInfo(group, "Compression", i18n("Compression"), QVariant::String); + addItemInfo(group, "InterlaceMode", i18n("Interlace Mode"),QVariant::String); +} + +bool KPngPlugin::readInfo( KFileMetaInfo& info, uint what) +{ + if ( info.path().isEmpty() ) // remote file + return false; + QFile f(info.path()); + if ( !f.open(IO_ReadOnly) ) + return false; + + QIODevice::Offset fileSize = f.size(); + + if (fileSize < 29) return false; + // the technical group will be read from the first 29 bytes. If the file + // is smaller, we can't even read this. + + bool readComments = false; + if (what & (KFileMetaInfo::Fastest | + KFileMetaInfo::DontCare | + KFileMetaInfo::ContentInfo)) readComments = true; + else + fileSize = 29; // No need to read more + + uchar *data = new uchar[fileSize+1]; + f.readBlock(reinterpret_cast<char*>(data), fileSize); + data[fileSize]='\n'; + + // find the start + if (data[0] == 137 && data[1] == 80 && data[2] == 78 && data[3] == 71 && + data[4] == 13 && data[5] == 10 && data[6] == 26 && data[7] == 10 ) + { + // ok + // the IHDR chunk should be the first + if (!strncmp((char*)&data[12], "IHDR", 4)) + { + // we found it, get the dimensions + ulong x,y; + x = (data[16]<<24) + (data[17]<<16) + (data[18]<<8) + data[19]; + y = (data[20]<<24) + (data[21]<<16) + (data[22]<<8) + data[23]; + + uint type = data[25]; + uint bpp = data[24]; + kdDebug(7034) << "dimensions " << x << "*" << y << endl; + + // the bpp are only per channel, so we need to multiply the with + // the channel count + switch (type) + { + case 0: break; // Grayscale + case 2: bpp *= 3; break; // RGB + case 3: break; // palette + case 4: bpp *= 2; break; // grayscale w. alpha + case 6: bpp *= 4; break; // RGBA + + default: // we don't get any sensible value here + bpp = 0; + } + + KFileMetaInfoGroup techgroup = appendGroup(info, "Technical"); + + appendItem(techgroup, "Dimensions", QSize(x, y)); + appendItem(techgroup, "BitDepth", bpp); + appendItem(techgroup, "ColorMode", + (type < sizeof(colors)/sizeof(colors[0])) + ? i18n(colors[data[25]]) : i18n("Unknown")); + + appendItem(techgroup, "Compression", + (data[26] < sizeof(compressions)/sizeof(compressions[0])) + ? i18n(compressions[data[26]]) : i18n("Unknown")); + + appendItem(techgroup, "InterlaceMode", + (data[28] < sizeof(interlaceModes)/sizeof(interlaceModes[0])) + ? i18n(interlaceModes[data[28]]) : i18n("Unknown")); + } + + // look for a tEXt chunk + if (readComments) + { + uint index = 8; + index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE; + KFileMetaInfoGroup commentGroup = appendGroup(info, "Comment"); + + while(index<fileSize-12) + { + while (index < fileSize - 12 && + strncmp((char*)CHUNK_TYPE(data,index), "tEXt", 4) && + strncmp((char*)CHUNK_TYPE(data,index), "zTXt", 4)) + + { + if (!strncmp((char*)CHUNK_TYPE(data,index), "IEND", 4)) + goto end; + + index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE; + } + + if (index < fileSize - 12) + { + // we found a tEXt or zTXt field + + // get the key, it's a null terminated string at the + // chunk start + + uchar* key = &CHUNK_DATA(data,index,0); + + int keysize=0; + for (;key[keysize]!=0; keysize++) + // look if we reached the end of the file + // (it might be corrupted) + if (8+index+keysize>=fileSize) + goto end; + + QByteArray arr; + if(!strncmp((char*)CHUNK_TYPE(data,index), "zTXt", 4)) { + kdDebug(7034) << "We found a zTXt field\n"; + // we get the compression method after the key + uchar* compressionMethod = &CHUNK_DATA(data,index,keysize+1); + if ( *compressionMethod != 0x00 ) { + // then it isn't zlib compressed and we are sunk + kdDebug(7034) << "Non-standard compression method." << endl; + goto end; + } + // compressed string after the compression technique spec + uchar* compressedText = &CHUNK_DATA(data, index, keysize+2); + uint compressedTextSize = CHUNK_SIZE(data, index)-keysize-2; + + // security check, also considering overflow wraparound from the addition -- + // we may endup with a /smaller/ index if we wrap all the way around + uint firstIndex = (uint)(compressedText - data); + uint onePastLastIndex = firstIndex + compressedTextSize; + if ( onePastLastIndex > fileSize || onePastLastIndex <= firstIndex) + goto end; + + uLongf uncompressedLen = compressedTextSize * 2; // just a starting point + int zlibResult; + do { + arr.resize(uncompressedLen); + zlibResult = uncompress((Bytef*)arr.data(), &uncompressedLen, + compressedText, compressedTextSize); + if (Z_OK == zlibResult) { + // then it is all OK + arr.resize(uncompressedLen); + } else if (Z_BUF_ERROR == zlibResult) { + // the uncompressedArray needs to be larger + // kdDebug(7034) << "doubling size for decompression" << endl; + uncompressedLen *= 2; + + // DoS protection. can't be bigger than 64k + if ( uncompressedLen > 131072 ) + break; + } else { + // something bad happened + goto end; + } + } while (Z_BUF_ERROR == zlibResult); + + if (Z_OK != zlibResult) + goto end; + } else if (!strncmp((char*)CHUNK_TYPE(data,index), "tEXt", 4)) { + kdDebug(7034) << "We found a tEXt field\n"; + // the text comes after the key, but isn't null terminated + uchar* text = &CHUNK_DATA(data,index, keysize+1); + uint textsize = CHUNK_SIZE(data, index)-keysize-1; + + // security check, also considering overflow wraparound from the addition -- + // we may endup with a /smaller/ index if we wrap all the way around + uint firstIndex = (uint)(text - data); + uint onePastLastIndex = firstIndex + textsize; + + if ( onePastLastIndex > fileSize || onePastLastIndex <= firstIndex) + goto end; + + arr.resize(textsize); + arr = QByteArray(textsize).duplicate((const char*)text, + textsize); + + } else { + kdDebug(7034) << "We found a field, not expected though\n"; + goto end; + } + appendItem(commentGroup, + QString(reinterpret_cast<char*>(key)), + QString(arr)); + + kdDebug(7034) << "adding " << key << " / " + << QString(arr) << endl; + + index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE; + } + } + } + } +end: + delete[] data; + return true; +} + +#include "kfile_png.moc" diff --git a/kfile-plugins/png/kfile_png.desktop b/kfile-plugins/png/kfile_png.desktop new file mode 100644 index 00000000..b4819b8d --- /dev/null +++ b/kfile-plugins/png/kfile_png.desktop @@ -0,0 +1,65 @@ +[Desktop Entry] +Type=Service +Name=PNG Info +Name[af]=Png Inligting +Name[ar]=معلومات PNG +Name[br]=Titouroù PNG +Name[ca]=Informació de PNG +Name[cs]=PNG info +Name[cy]=Gybodaeth PNG +Name[da]=PNG-info +Name[de]=PNG-Info +Name[el]=Πληροφορίες PNG +Name[eo]=PNG-informo +Name[es]=Info PNG +Name[et]=PNG info +Name[fa]=اطلاعات PNG +Name[fi]=PNG-tiedot +Name[fr]=Informations PNG +Name[gl]=Inf. PNG +Name[he]=מידע PNG +Name[hi]=PNG जानकारी +Name[hr]=PNG Informacije +Name[hu]=PNG-jellemzők +Name[is]=PNG upplýsingar +Name[it]=Informazioni PNG +Name[ja]=PNG 情報 +Name[kk]=PNG мәліметі +Name[km]=ព័ត៌មាន PNG +Name[lt]=PNG informacija +Name[ms]=Maklumat PNG +Name[nds]=PNG-Info +Name[ne]=PNG सूचना +Name[nl]=PNG-Info +Name[nn]=PNG-info +Name[nso]=Tshedimoso ya PNG +Name[pa]=PNG ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku PNG +Name[pt]=Informação do PNG +Name[pt_BR]= Informação sobre PNG +Name[ro]=Informaţii PNG +Name[ru]=Информация о PNG +Name[se]=PNG-dieđut +Name[sl]=Podatki o PNG +Name[sr]=PNG информације +Name[sr@Latn]=PNG informacije +Name[sv]=PNG-information +Name[ta]=PNG தகவல் +Name[tg]=Иттилоот оиди PNG +Name[th]=ข้อมูลแฟ้ม PNG +Name[tr]=PNG Bilgisi +Name[uk]=Інформація про PNG +Name[uz]=PNG haqida maʼlumot +Name[uz@cyrillic]=PNG ҳақида маълумот +Name[ven]=Mafhungo a PNG +Name[wa]=Informåcion sol imådje PNG +Name[xh]=PNG Ulwazi +Name[zh_CN]=PNG 信息 +Name[zh_HK]=PNG 資訊 +Name[zh_TW]=PNG 資訊 +Name[zu]=Ulwazi lwe-PNG +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_png +MimeType=image/png +PreferredGroups=Comment,Technical +PreferredItems=Title,Author,Dimensions,BitDepth,ColorMode,Compression diff --git a/kfile-plugins/png/kfile_png.h b/kfile-plugins/png/kfile_png.h new file mode 100644 index 00000000..0873d55d --- /dev/null +++ b/kfile-plugins/png/kfile_png.h @@ -0,0 +1,39 @@ +/* This file is part of the KDE project + * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@kde.org> + * + * 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. + * + * $Id$ + */ + +#ifndef __KFILE_PNG_H__ +#define __KFILE_PNG_H__ + +#include <kfilemetainfo.h> +#include <kurl.h> + +class QStringList; + +class KPngPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KPngPlugin( QObject *parent, const char *name, const QStringList& preferredItems ); + + virtual bool readInfo( KFileMetaInfo& info, uint ); +}; + +#endif diff --git a/kfile-plugins/pnm/Makefile.am b/kfile-plugins/pnm/Makefile.am new file mode 100644 index 00000000..7148232a --- /dev/null +++ b/kfile-plugins/pnm/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for pnm file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_pnm.h + +kde_module_LTLIBRARIES = kfile_pnm.la + +kfile_pnm_la_SOURCES = kfile_pnm.cpp +kfile_pnm_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_pnm_la_LIBADD = $(LIB_KIO) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_pnm.pot + +services_DATA = kfile_pnm.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/pnm/kfile_pnm.cpp b/kfile-plugins/pnm/kfile_pnm.cpp new file mode 100644 index 00000000..b0a1dcca --- /dev/null +++ b/kfile-plugins/pnm/kfile_pnm.cpp @@ -0,0 +1,137 @@ +/* This file is part of the KDE project + * Copyright (C) 2003 Volker Krause <volker.krause@rwth-aachen.de> + * + * 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 "kfile_pnm.h" + +#include <math.h> +#include <kgenericfactory.h> +#include <qfile.h> +#include <qtextstream.h> + +static const char* formats[] = { + I18N_NOOP("plain"), + I18N_NOOP("raw") +}; + +typedef KGenericFactory<KPnmPlugin> PnmFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_pnm, PnmFactory("kfile_pnm")) + +KPnmPlugin::KPnmPlugin(QObject *parent, const char *name, const QStringList &args) : KFilePlugin(parent, name, args) +{ + makeMimeTypeInfo( "image/x-portable-bitmap" ); + makeMimeTypeInfo( "image/x-portable-greymap" ); + makeMimeTypeInfo( "image/x-portable-pixmap" ); +} + +void KPnmPlugin::makeMimeTypeInfo(const QString& mimetype) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( mimetype ); + + KFileMimeTypeInfo::GroupInfo* group = 0; + KFileMimeTypeInfo::ItemInfo* item = 0; + + group = addGroupInfo(info, "General", i18n("General")); + + addItemInfo(group, "Format", i18n("Format"), QVariant::String); + + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size); + setUnit(item, KFileMimeTypeInfo::Pixels); + + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); + + addItemInfo(group, "Comment", i18n("Comment"), QVariant::String); +} + + +bool KPnmPlugin::readInfo( KFileMetaInfo& info, uint /*what*/) +{ + QFile f(info.path()); + if(!f.open(IO_ReadOnly)) + return false; + if(f.size() <= 2) + return false; + QTextStream stream(&f); + + char c; + stream >> c; + if(c != 'P') + return false; + + // image format and type + int n; + stream >> n; + int format = (n - 1) / 3; + if(format != 0 && format != 1) + return false; + int type = (n - 1) % 3; + + QString comments, buffer; + while(!stream.atEnd()) { + stream >> c; + // comment + if( c == '#') { + buffer = stream.readLine(); + comments += buffer.stripWhiteSpace(); + comments += '\n'; + } + // image size + // unfortunately Qt doesn't have some kind of push-back method for + // QTextStream, so we need to manually decode the first part of the + // image size. + if( c >= '0' && c <= '9' ) { + buffer = ""; + QChar tmp(c); + while(!stream.atEnd() && tmp.isDigit()) { + buffer += tmp; + stream >> tmp; + } + break; + } + } + + // image size + int x, y, max; + x = buffer.toInt(); + stream >> y; + stream >> max; + + // bit depth + // PNM doesn't provide a conventional bit depth value, only the highest value + // per pixel. To have comparable values with other formats, we convert it to + // a normal bit depth value. + int bpp = 1; + if(type != 0) + bpp = (int)ceil(log((double)max) / log(2.0)); + if(type == 2) + bpp *= 3; + + KFileMetaInfoGroup group = appendGroup(info, "General"); + appendItem(group, "Format", formats[format]); + appendItem(group, "Dimensions", QSize(x, y)); + if(!comments.isEmpty()) + appendItem(group, "Comment", comments.stripWhiteSpace()); + appendItem(group, "BitDepth", bpp); + + f.close(); + return true; +} + +#include "kfile_pnm.moc" diff --git a/kfile-plugins/pnm/kfile_pnm.desktop b/kfile-plugins/pnm/kfile_pnm.desktop new file mode 100644 index 00000000..cfb475d2 --- /dev/null +++ b/kfile-plugins/pnm/kfile_pnm.desktop @@ -0,0 +1,60 @@ +[Desktop Entry] +Type=Service +Name=PNM Info +Name[ar]=معلومات PNM +Name[br]=Titouroù PNM +Name[ca]=Informació de PNM +Name[cs]=PNM info +Name[cy]=Gybodaeth PNM +Name[da]=PNG-info +Name[de]=PNM-Info +Name[el]=Πληροφορίες PNM +Name[eo]=PNM-informo +Name[es]=Info PNM +Name[et]=PNM info +Name[fa]=اطلاعات PNM +Name[fi]=PNM-tiedot +Name[fr]=Informations PNM +Name[gl]=Inf. PNM +Name[he]=מידע PNM +Name[hi]=PNM जानकारी +Name[hu]=PNM-jellemzők +Name[is]=PNM upplýsingar +Name[it]=Informazioni PNM +Name[ja]=PNM 情報 +Name[kk]=PNM мәліметі +Name[km]=ព័ត៌មាន PNM +Name[lt]=PNM informacija +Name[ms]=Maklumat PNM +Name[nb]=PNM-info +Name[nds]=PNM-Info +Name[ne]=PNM सूचना +Name[nl]=PNG-info +Name[nn]=PNM-info +Name[pa]=PNM ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku PNM +Name[pt]=Informação do PNM +Name[pt_BR]=Informação sobre PNG +Name[ro]=Informaţii PNM +Name[ru]=Информация о PNM +Name[se]=PNM-dieđut +Name[sl]=Podatki o PNM +Name[sr]=PNM информације +Name[sr@Latn]=PNM informacije +Name[sv]=PNM-information +Name[ta]=PNM தகவல் +Name[tg]=Иттилоот оиди PNM +Name[th]=ข้อมูลแฟ้ม PNM +Name[tr]=PNM Bilgisi +Name[uk]=Інформація про PNM +Name[uz]=PNM haqida maʼlumot +Name[uz@cyrillic]=PNM ҳақида маълумот +Name[wa]=Informåcion sol imådje PNM +Name[zh_CN]=PNM 信息 +Name[zh_HK]=PNM 資訊 +Name[zh_TW]=PNM 資訊 +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_pnm +MimeType=image/x-portable-bitmap;image/x-portable-greymap;image/x-portable-pixmap +PreferredGroups=General +PreferredItems=Format,Dimensions,BitDepth,Comment diff --git a/kfile-plugins/pnm/kfile_pnm.h b/kfile-plugins/pnm/kfile_pnm.h new file mode 100644 index 00000000..4f1043e5 --- /dev/null +++ b/kfile-plugins/pnm/kfile_pnm.h @@ -0,0 +1,39 @@ +/* This file is part of the KDE project + * Copyright (C) 2003 Volker Krause <volker.krause@rwth-aachen.de> + * + * 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_PNM_H__ +#define __KFILE_PNM_H__ + +#include <kfilemetainfo.h> + +class QStringList; + +class KPnmPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KPnmPlugin( QObject *parent, const char *name, const QStringList& preferredItems ); + virtual bool readInfo( KFileMetaInfo& info, uint ); + +private: + void makeMimeTypeInfo( const QString&); +}; + +#endif diff --git a/kfile-plugins/ps/Makefile.am b/kfile-plugins/ps/Makefile.am new file mode 100644 index 00000000..9c5b20a3 --- /dev/null +++ b/kfile-plugins/ps/Makefile.am @@ -0,0 +1,26 @@ +## Makefile.am for the ps file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = -I$(top_srcdir)/kghostview $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_ps.h gscreator.h + +kde_module_LTLIBRARIES = kfile_ps.la gsthumbnail.la + +kfile_ps_la_SOURCES = kfile_ps.cpp +kfile_ps_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_ps_la_LIBADD = $(LIB_KIO) ../../kghostview/libdscparse.la + +gsthumbnail_la_SOURCES = gscreator.cpp +gsthumbnail_la_LIBADD = $(LIB_KDECORE) ../../kghostview/libdscparse.la +gsthumbnail_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_ps.pot + +services_DATA = kfile_ps.desktop gsthumbnail.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/ps/gscreator.cpp b/kfile-plugins/ps/gscreator.cpp new file mode 100644 index 00000000..33cbc141 --- /dev/null +++ b/kfile-plugins/ps/gscreator.cpp @@ -0,0 +1,619 @@ +/* This file is part of the KDE libraries + Copyright (C) 2001 Malte Starostik <malte@kde.org> + + Handling of EPS previews Copyright (C) 2003 Philipp Hullmann <phull@gmx.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +/* This function gets a path of a DVI, EPS, PS or PDF file and + produces a PNG-Thumbnail which is stored as a QImage + + The program works as follows + + 1. Test if file is a DVI file + + 2. Create a child process (1), in which the + file is to be changed into a PNG + + 3. Child-process (1) : + + 4. If file is DVI continue with 6 + + 5. If file is no DVI continue with 9 + + 6. Create another child process (2), in which the DVI is + turned into PS using dvips + + 7. Parent process (2) : + Turn the recently created PS file into a PNG file using gs + + 8. continue with 10 + + 9. Turn the PS,PDF or EPS file into a PNG file using gs + + 10. Parent process (1) + store data in a QImage +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + +#include <assert.h> +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <signal.h> +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#include <sys/time.h> +#include <sys/wait.h> +#include <fcntl.h> +#include <errno.h> +#include <kdemacros.h> + +#include <qcolor.h> +#include <qfile.h> +#include <qimage.h> +#include <qregexp.h> + + +#include "gscreator.h" +#include "dscparse_adapter.h" +#include "dscparse.h" + +extern "C" +{ + KDE_EXPORT ThumbCreator *new_creator() + { + return new GSCreator; + } +} + +// This PS snippet will be prepended to the actual file so that only +// the first page is output. +static const char *psprolog = + "%!PS-Adobe-3.0\n" + "/.showpage.orig /showpage load def\n" + "/.showpage.firstonly {\n" + " .showpage.orig\n" + " quit\n" + "} def\n" + "/showpage { .showpage.firstonly } def\n"; + +// This is the code recommended by Adobe tech note 5002 for including +// EPS files. +static const char *epsprolog = + "%!PS-Adobe-3.0\n" + "userdict begin /pagelevel save def /showpage { } def\n" + "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit\n" + "[ ] 0 setdash newpath false setoverprint false setstrokeadjust\n"; + +static const char * gsargs_ps[] = { + "gs", + "-sDEVICE=png16m", + "-sOutputFile=-", + "-dSAFER", + "-dPARANOIDSAFER", + "-dNOPAUSE", + "-dFirstPage=1", + "-dLastPage=1", + "-q", + "-", + 0, // file name + "-c", + "showpage", + "-c", + "quit", + 0 +}; + +static const char * gsargs_eps[] = { + "gs", + "-sDEVICE=png16m", + "-sOutputFile=-", + "-dSAFER", + "-dPARANOIDSAFER", + "-dNOPAUSE", + 0, // page size + 0, // resolution + "-q", + "-", + 0, // file name + "-c", + "pagelevel", + "-c", + "restore", + "-c", + "end", + "-c", + "showpage", + "-c", + "quit", + 0 +}; + +static const char *dvipsargs[] = { + "dvips", + "-n", + "1", + "-q", + "-o", + "-", + 0, // file name + 0 +}; + +static bool correctDVI(const QString& filename); + + +namespace { + bool got_sig_term = false; + void handle_sigterm( int ) { + got_sig_term = true; + } +} + + +bool GSCreator::create(const QString &path, int width, int height, QImage &img) +{ +// The code in the loop (when testing whether got_sig_term got set) +// should read some variation of: +// parentJob()->wasKilled() +// +// Unfortunatelly, that's currently impossible without breaking BIC. +// So we need to catch the signal ourselves. +// Otherwise, on certain funny PS files (for example +// http://www.tjhsst.edu/~Eedanaher/pslife/life.ps ) +// gs would run forever after we were dead. +// #### Reconsider for KDE 4 ### +// (24/12/03 - luis_pedro) +// + typedef void ( *sighandler_t )( int ); + // according to linux's "man signal" the above typedef is a gnu extension + sighandler_t oldhandler = signal( SIGTERM, handle_sigterm ); + + int input[2]; + int output[2]; + int dvipipe[2]; + + QByteArray data(1024); + + bool ok = false; + + // Test if file is DVI + bool no_dvi =!correctDVI(path); + + if (pipe(input) == -1) { + return false; + } + if (pipe(output) == -1) { + close(input[0]); + close(input[1]); + return false; + } + + KDSC dsc; + endComments = false; + dsc.setCommentHandler(this); + + if (no_dvi) + { + FILE* fp = fopen(QFile::encodeName(path), "r"); + if (fp == 0) return false; + + char buf[4096]; + int count; + while ((count = fread(buf, sizeof(char), 4096, fp)) != 0 + && !endComments) { + dsc.scanData(buf, count); + } + fclose(fp); + + if (dsc.pjl() || dsc.ctrld()) { + // this file is a mess. + return false; + } + } + + const bool is_encapsulated = no_dvi && + (path.find(QRegExp("\\.epsi?$", false, false)) > 0) && + (dsc.bbox()->width() > 0) && (dsc.bbox()->height() > 0) && + (dsc.page_count() <= 1); + + char translation[64] = ""; + char pagesize[32] = ""; + char resopt[32] = ""; + std::auto_ptr<KDSCBBOX> bbox = dsc.bbox(); + if (is_encapsulated) { + // GhostScript's rendering at the extremely low resolutions + // required for thumbnails leaves something to be desired. To + // get nicer images, we render to four times the required + // resolution and let QImage scale the result. + const int hres = (width * 72) / bbox->width(); + const int vres = (height * 72) / bbox->height(); + const int resolution = (hres > vres ? vres : hres) * 4; + const int gswidth = ((bbox->urx() - bbox->llx()) * resolution) / 72; + const int gsheight = ((bbox->ury() - bbox->lly()) * resolution) / 72; + + snprintf(pagesize, 31, "-g%ix%i", gswidth, gsheight); + snprintf(resopt, 31, "-r%i", resolution); + snprintf(translation, 63, + " 0 %i sub 0 %i sub translate\n", bbox->llx(), + bbox->lly()); + } + + const CDSC_PREVIEW_TYPE previewType = + static_cast<CDSC_PREVIEW_TYPE>(dsc.preview()); + + switch (previewType) { + case CDSC_TIFF: + case CDSC_WMF: + case CDSC_PICT: + // FIXME: these should take precedence, since they can hold + // color previews, which EPSI can't (or can it?). + break; + case CDSC_EPSI: + { + const int xscale = bbox->width() / width; + const int yscale = bbox->height() / height; + const int scale = xscale < yscale ? xscale : yscale; + if (getEPSIPreview(path, + dsc.beginpreview(), + dsc.endpreview(), + img, + bbox->width() / scale, + bbox->height() / scale)) + return true; + // If the preview extraction routine fails, gs is used to + // create a thumbnail. + } + break; + case CDSC_NOPREVIEW: + default: + // need to run ghostscript in these cases + break; + } + + pid_t pid = fork(); + if (pid == 0) { + // Child process (1) + + // close(STDERR_FILENO); + + // find first zero entry in gsargs and put the filename + // or - (stdin) there, if DVI + const char **gsargs = gsargs_ps; + const char **arg = gsargs; + + if (no_dvi && is_encapsulated) { + gsargs = gsargs_eps; + arg = gsargs; + + // find first zero entry and put page size there + while (*arg) ++arg; + *arg = pagesize; + + // find second zero entry and put resolution there + while (*arg) ++arg; + *arg = resopt; + } + + // find next zero entry and put the filename there + QCString fname = QFile::encodeName( path ); + while (*arg) + ++arg; + if( no_dvi ) + *arg = fname.data(); + else + *arg = "-"; + + // find first zero entry in dvipsargs and put the filename there + arg = dvipsargs; + while (*arg) + ++arg; + *arg = fname.data(); + + if( !no_dvi ){ + pipe(dvipipe); + pid_t pid_two = fork(); + if( pid_two == 0 ){ + // Child process (2), reopen stdout on the pipe "dvipipe" and exec dvips + + close(input[0]); + close(input[1]); + close(output[0]); + close(output[1]); + close(dvipipe[0]); + + dup2( dvipipe[1], STDOUT_FILENO); + + execvp(dvipsargs[0], const_cast<char *const *>(dvipsargs)); + exit(1); + } + else if(pid_two != -1){ + close(input[1]); + close(output[0]); + close(dvipipe[1]); + + dup2( dvipipe[0], STDIN_FILENO); + dup2( output[1], STDOUT_FILENO); + + execvp(gsargs[0], const_cast<char *const *>(gsargs)); + exit(1); + } + else{ + // fork() (2) failed, close these + close(dvipipe[0]); + close(dvipipe[1]); + } + + } + else if( no_dvi ){ + // Reopen stdin/stdout on the pipes and exec gs + close(input[1]); + close(output[0]); + + dup2(input[0], STDIN_FILENO); + dup2(output[1], STDOUT_FILENO); + + execvp(gsargs[0], const_cast<char *const *>(gsargs)); + exit(1); + } + } + else if (pid != -1) { + // Parent process, write first-page-only-hack (the hack is not + // used if DVI) and read the png output + close(input[0]); + close(output[1]); + const char *prolog; + if (is_encapsulated) + prolog = epsprolog; + else + prolog = psprolog; + int count = write(input[1], prolog, strlen(prolog)); + if (is_encapsulated) + write(input[1], translation, strlen(translation)); + + close(input[1]); + if (count == static_cast<int>(strlen(prolog))) { + int offset = 0; + while (!ok) { + fd_set fds; + FD_ZERO(&fds); + FD_SET(output[0], &fds); + struct timeval tv; + tv.tv_sec = 20; + tv.tv_usec = 0; + + got_sig_term = false; + if (select(output[0] + 1, &fds, 0, 0, &tv) <= 0) { + if ( ( errno == EINTR || errno == EAGAIN ) && !got_sig_term ) continue; + break; // error, timeout or master wants us to quit (SIGTERM) + } + if (FD_ISSET(output[0], &fds)) { + count = read(output[0], data.data() + offset, 1024); + if (count == -1) + break; + else + if (count) // prepare for next block + { + offset += count; + data.resize(offset + 1024); + } + else // got all data + { + data.resize(offset); + ok = true; + } + } + } + } + if (!ok) // error or timeout, gs probably didn't exit yet + { + kill(pid, SIGTERM); + } + + int status = 0; + if (waitpid(pid, &status, 0) != pid || (status != 0 && status != 256) ) + ok = false; + } + else { + // fork() (1) failed, close these + close(input[0]); + close(input[1]); + close(output[1]); + } + close(output[0]); + + int l = img.loadFromData( data ); + + if ( got_sig_term && + oldhandler != SIG_ERR && + oldhandler != SIG_DFL && + oldhandler != SIG_IGN ) { + oldhandler( SIGTERM ); // propagate the signal. Other things might rely on it + } + if ( oldhandler != SIG_ERR ) signal( SIGTERM, oldhandler ); + + return ok && l; +} + +ThumbCreator::Flags GSCreator::flags() const +{ + return static_cast<Flags>(DrawFrame); +} + +void GSCreator::comment(Name name) +{ + switch (name) { + case EndPreview: + case BeginProlog: + case Page: + endComments = true; + break; + + default: + break; + } +} + +// Quick function to check if the filename corresponds to a valid DVI +// file. Returns true if <filename> is a DVI file, false otherwise. + +static bool correctDVI(const QString& filename) +{ + QFile f(filename); + if (!f.open(IO_ReadOnly)) + return FALSE; + + unsigned char test[4]; + if ( f.readBlock( (char *)test,2)<2 || test[0] != 247 || test[1] != 2 ) + return FALSE; + + int n = f.size(); + if ( n < 134 ) // Too short for a dvi file + return FALSE; + f.at( n-4 ); + + unsigned char trailer[4] = { 0xdf,0xdf,0xdf,0xdf }; + + if ( f.readBlock( (char *)test, 4 )<4 || strncmp( (char *)test, (char*) trailer, 4 ) ) + return FALSE; + // We suppose now that the dvi file is complete and OK + return TRUE; +} + +bool GSCreator::getEPSIPreview(const QString &path, long start, long + end, QImage &outimg, int imgwidth, int imgheight) +{ + FILE *fp; + fp = fopen(QFile::encodeName(path), "r"); + if (fp == 0) return false; + + const long previewsize = end - start + 1; + + char *buf = (char *) malloc(previewsize); + fseek(fp, start, SEEK_SET); + int count = fread(buf, sizeof(char), previewsize - 1, fp); + fclose(fp); + buf[previewsize - 1] = 0; + if (count != previewsize - 1) + { + free(buf); + return false; + } + + QString previewstr = QString::fromLatin1(buf); + free(buf); + + int offset = 0; + while ((offset < previewsize) && !(previewstr[offset].isDigit())) offset++; + int digits = 0; + while ((offset + digits < previewsize) && previewstr[offset + digits].isDigit()) digits++; + int width = previewstr.mid(offset, digits).toInt(); + offset += digits + 1; + while ((offset < previewsize) && !(previewstr[offset].isDigit())) offset++; + digits = 0; + while ((offset + digits < previewsize) && previewstr[offset + digits].isDigit()) digits++; + int height = previewstr.mid(offset, digits).toInt(); + offset += digits + 1; + while ((offset < previewsize) && !(previewstr[offset].isDigit())) offset++; + digits = 0; + while ((offset + digits < previewsize) && previewstr[offset + digits].isDigit()) digits++; + int depth = previewstr.mid(offset, digits).toInt(); + + // skip over the rest of the BeginPreview comment + while ((offset < previewsize) && + previewstr[offset] != '\n' && + previewstr[offset] != '\r') offset++; + while ((offset < previewsize) && previewstr[offset] != '%') offset++; + + unsigned int imagedepth; + switch (depth) { + case 1: + case 2: + case 4: + case 8: + imagedepth = 8; + break; + case 12: // valid, but not (yet) supported + default: // illegal value + return false; + } + + unsigned int colors = (1U << depth); + QImage img(width, height, imagedepth, colors); + img.setAlphaBuffer(false); + + if (imagedepth <= 8) { + for (unsigned int gray = 0; gray < colors; gray++) { + unsigned int grayvalue = (255U * (colors - 1 - gray)) / + (colors - 1); + img.setColor(gray, qRgb(grayvalue, grayvalue, grayvalue)); + } + } + + const unsigned int bits_per_scan_line = width * depth; + unsigned int bytes_per_scan_line = bits_per_scan_line / 8; + if (bits_per_scan_line % 8) bytes_per_scan_line++; + const unsigned int bindatabytes = height * bytes_per_scan_line; + QMemArray<unsigned char> bindata(bindatabytes); + + for (unsigned int i = 0; i < bindatabytes; i++) { + if (offset >= previewsize) + return false; + + while (!isxdigit(previewstr[offset].latin1()) && + offset < previewsize) + offset++; + + bool ok = false; + bindata[i] = static_cast<unsigned char>(previewstr.mid(offset, 2).toUInt(&ok, 16)); + if (!ok) + return false; + + offset += 2; + } + + for (int scanline = 0; scanline < height; scanline++) { + unsigned char *scanlineptr = img.scanLine(scanline); + + for (int pixelindex = 0; pixelindex < width; pixelindex++) { + unsigned char pixelvalue = 0; + const unsigned int bitoffset = + scanline * bytes_per_scan_line * 8U + pixelindex * depth; + for (int depthindex = 0; depthindex < depth; + depthindex++) { + const unsigned int byteindex = (bitoffset + depthindex) / 8U; + const unsigned int bitindex = + 7 - ((bitoffset + depthindex) % 8U); + const unsigned char bitvalue = + (bindata[byteindex] & static_cast<unsigned char>(1U << bitindex)) >> bitindex; + pixelvalue |= (bitvalue << depthindex); + } + scanlineptr[pixelindex] = pixelvalue; + } + } + + outimg = img.convertDepth(32).smoothScale(imgwidth, imgheight); + + return true; +} diff --git a/kfile-plugins/ps/gscreator.h b/kfile-plugins/ps/gscreator.h new file mode 100644 index 00000000..b91fb0b0 --- /dev/null +++ b/kfile-plugins/ps/gscreator.h @@ -0,0 +1,42 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 Malte Starostik <malte@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _GSCREATOR_H_ +#define _GSCREATOR_H_ + +#include <kio/thumbcreator.h> +#include "dscparse_adapter.h" + +class GSCreator : public ThumbCreator, public KDSCCommentHandler +{ +public: + GSCreator() {}; + virtual bool create(const QString &path, int, int, QImage &img); + virtual Flags flags() const; + void comment(Name name); + +private: + static bool getEPSIPreview(const QString &path, + long start, long end, + QImage &outimg, + int imgwidth, int imgheight); + bool endComments; +}; + +#endif diff --git a/kfile-plugins/ps/gsthumbnail.desktop b/kfile-plugins/ps/gsthumbnail.desktop new file mode 100644 index 00000000..0211020e --- /dev/null +++ b/kfile-plugins/ps/gsthumbnail.desktop @@ -0,0 +1,60 @@ +[Desktop Entry] +Type=Service +Name=PostScript, PDF and DVI Files +Name[ar]=ملفات الــ PostScript ، PDF و DVI +Name[br]=Restroù PostScript, PDF ha DVI +Name[bs]=Postscript, PDF i DVI datoteke +Name[ca]=Fitxers PostScript, PDF i DVI +Name[cs]=Postscriptové, PDF a DVI soubory +Name[cy]=Ffeiliau PostScript, PDF a DVI +Name[da]=PostScript, PDF- og DVI-filer +Name[de]=PostScript-, PDF- und DVI-Dateien +Name[el]=Αρχεία PostScript, PDF και DVI +Name[eo]=Postskriptaj, PDF- kaj DVI-dosieroj +Name[es]=Archivos PostScript, PDF y DVI +Name[et]=PostScript-, PDF- ja DVI-failid +Name[eu]=PostScript, PDF eta DVI fitxategiak +Name[fa]=پروندههای PostScript، PDF و DVI +Name[fi]=PostScript-, PDF- ja DVI-tiedostot +Name[fr]=Fichiers PostScript, PDF et DVI +Name[ga]=Comhaid PostScript, PDF agus DVI +Name[gl]=Ficheiros PostScript, PDF e DVI +Name[he]=קבצי PostScript, PDF ו־DVI +Name[hu]=PostScript-, PDF- és DVI-fájlok +Name[is]=PostScript PDF og DVI skrár +Name[it]=File PostScript, PDF e DVI +Name[ja]=Postscript,PDF,DVIファイル +Name[kk]=PostScript, PDF және DVI файлдары +Name[km]=ឯកសារ PostScript, PDF និង DVI +Name[lt]=Postscript, PDF ir DVI bylos +Name[ms]=PostScript, PDF dan Fail DVI +Name[nb]=PostScript, PDF og DVI filer +Name[nds]=PostScript-, PDF- un DVI-Dateien +Name[ne]=पोष्टस्क्रिप्ट, PDF र DVI फाइल +Name[nl]=PostScript-, DVI- en PDF-bestanden +Name[nn]=PostScript-, PDF- og DVI-filer +Name[pl]=Pliki PostScript, PDF i DVI +Name[pt]=Ficheiros PostScript, PDF e DVI +Name[pt_BR]=Arquivos PostScript, PDF e DVI +Name[ro]=Fişiere PostScript, PDF şi DVI +Name[ru]=Файлы PostScript, PDF и DVI +Name[se]=PostScript-, PDF- ja DVI-fiillat +Name[sk]=PostScript, PDF a DVI súbory +Name[sl]=Datoteke PostScript, PDF in DVI +Name[sr]=PostScript, PDF и DVI фајлови +Name[sr@Latn]=PostScript, PDF i DVI fajlovi +Name[sv]=Postscript, PDF och DVI-filer +Name[ta]= போஸ்ட்கிரிப்ட், பிடிஃப் மற்றும் டிவிஐ கோப்புகள் +Name[tg]=Файлҳои PostScript, PDF ва DVI +Name[th]=แฟ้ม PDF, DVI และ โพสต์สคริปต์ +Name[tr]=PostScript, PDF ve DVI Dosyaları +Name[uk]=Файли PostScript, PDF та DVI +Name[uz]=PostScript, PDF va DVI fayllari +Name[uz@cyrillic]=PostScript, PDF ва DVI файллари +Name[zh_CN]=PostScript、PDF 和 DVI 文件 +Name[zh_HK]=PostScript 、PDF 及 DVI 檔案 +Name[zh_TW]=PostScript,PDF 與 DVI 檔 +ServiceTypes=ThumbCreator +MimeTypes=application/x-dvi,application/postscript,application/pdf,image/x-eps +X-KDE-Library=gsthumbnail +CacheThumbnail=true diff --git a/kfile-plugins/ps/kfile_ps.cpp b/kfile-plugins/ps/kfile_ps.cpp new file mode 100644 index 00000000..6d3caa31 --- /dev/null +++ b/kfile-plugins/ps/kfile_ps.cpp @@ -0,0 +1,124 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Wilco Greven <greven@kde.org> + * + * 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. + * + * $Id$ + */ + +#include "kfile_ps.h" + +#include <qfile.h> + +#include <klocale.h> +#include <kgenericfactory.h> +#include <kdebug.h> + +typedef KGenericFactory<KPSPlugin> PSFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_ps, PSFactory("kfile_ps")) + +KPSPlugin::KPSPlugin(QObject *parent, const char *name, + const QStringList &preferredItems) : + KFilePlugin( parent, name, preferredItems ) +{ + kdDebug(7034) << "ps plugin\n"; + + // set up our mimetypes + makeMimeTypeInfo( "application/postscript" ); + makeMimeTypeInfo( "image/x-eps" ); +} + +void KPSPlugin::makeMimeTypeInfo( const char* mimeType ) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( mimeType ); + + // general group + KFileMimeTypeInfo::GroupInfo* group = addGroupInfo(info, "General", i18n("General")); + addItemInfo(group, "Title", i18n("Title"), QVariant::String); + addItemInfo(group, "Creator", i18n("Creator"), QVariant::String); + addItemInfo(group, "CreationDate", i18n("Creation Date"), QVariant::String); + addItemInfo(group, "For", i18n("For"), QVariant::String); + addItemInfo(group, "Pages", i18n("Pages"), QVariant::UInt); +} + +bool KPSPlugin::readInfo( KFileMetaInfo& info, uint /* what */) +{ + _info = info; + _group = appendGroup(info, "General"); + _endComments = false; + _setData = 0; + + _dsc = new KDSC; + _dsc->setCommentHandler( this ); + FILE* fp = fopen( QFile::encodeName( info.path() ), "r" ); + if( fp == 0 ) + return false; + + char buf[4096]; + int count; + while( ( count = fread( buf, sizeof(char), sizeof( buf ), fp ) ) ) { + if ( !_dsc->scanData( buf, count ) ) break; + if ( _endComments || _setData == 5 ) break; // Change if new item scanned + } + fclose( fp ); + delete _dsc; + _dsc = 0; + + return _setData > 0; +} + +void KPSPlugin::comment( Name name ) +{ + switch( name ) + { + case Title: + appendItem(_group, "Title", _dsc->dsc_title()); + ++_setData; + break; + case Creator: + appendItem(_group, "Creator", _dsc->dsc_creator()); + ++_setData; + break; + case CreationDate: + appendItem(_group, "CreationDate", _dsc->dsc_date()); + ++_setData; + break; + case For: + appendItem(_group, "For", _dsc->dsc_for()); + ++_setData; + break; + case Pages: { + int pages = _dsc->page_pages(); + if (pages) + { + appendItem(_group, "Pages", pages); + ++_setData; + } + } + break; + + // Right now we watch for 5 elements: + // Title, Creator, CreationDate, For, Pages + // + // If you add another one(s), please update the 5 in "_setData == 5" above + // + case EndComments: _endComments = true; + default: ; // Ignore + } +} + +#include "kfile_ps.moc" + diff --git a/kfile-plugins/ps/kfile_ps.desktop b/kfile-plugins/ps/kfile_ps.desktop new file mode 100644 index 00000000..75b3e055 --- /dev/null +++ b/kfile-plugins/ps/kfile_ps.desktop @@ -0,0 +1,66 @@ +[Desktop Entry] +Type=Service +Name=PostScript Info +Name[af]=Postscript Inligting +Name[ar]=معلومات PostScript +Name[br]=Procinfo PostScript +Name[ca]=Informació de PostScript +Name[cs]=PostScript info +Name[cy]=Gwybodaeth PostScript +Name[da]=PostScript-info +Name[de]=PostScript-Info +Name[el]=Πληροφορίες PostScript +Name[eo]=Postskriptinformo +Name[es]=Info PostScript +Name[et]=PostScript info +Name[fa]=اطلاعات PostScript +Name[fi]=PostScript-tiedot +Name[fr]=Informations PostScript +Name[gl]=Inf. PostScript +Name[he]=מידע PostScript +Name[hi]=पोस्टस्क्रिप्ट जानकारी +Name[hr]=Postscript informacije +Name[hu]=PostScript-jellemzők +Name[is]=PostScript upplýsingar +Name[it]=Informazioni PostScript +Name[ja]=PostScript 情報 +Name[kk]=PostScript мәліметі +Name[km]=ព័ត៌មាន PostScript +Name[lt]=PostScript informacija +Name[lv]=Postscript Info +Name[ms]=Maklumat PostScript +Name[nb]=PostScript-info +Name[nds]=PostScript-Info +Name[ne]=पोष्टस्क्रिप्ट सूचना +Name[nl]=PostScript-info +Name[nn]=PostScript-info +Name[nso]=Tshedimoso ya PostScript +Name[pa]=PostScript ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku PostScriptu +Name[pt]=Informação do PostScript +Name[pt_BR]=Informação sobre PostScript +Name[ro]=Informaţii PostScript +Name[ru]=Информация о PostScript +Name[se]=PostScript-dieđut +Name[sl]=Podatki o PostScriptu +Name[sr]=PostScript информације +Name[sr@Latn]=PostScript informacije +Name[sv]=Postscript-information +Name[ta]=முன் எழுத்தாக்க தகவல் +Name[tg]=Иттилоот оиди PostScript +Name[th]=ข้อมูลโพสต์สคริปต์ +Name[tr]=PostScript Bilgisi +Name[uk]=Інформація про PostScript +Name[uz]=PostScript haqida maʼlumot +Name[uz@cyrillic]=PostScript ҳақида маълумот +Name[ven]=Mafhungo a mabammbiri a poso +Name[wa]=Informåcion sol documint PostScript +Name[xh]=Ulwazi Lwe PostScript +Name[zh_CN]=PostScript 信息 +Name[zh_HK]=PostScript 資訊 +Name[zh_TW]=PostScript 資訊 +Name[zu]=Ulwazi Lwesi-PostScript +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_ps +MimeType=application/postscript;image/x-eps +PreferredItems=Title,Creator,CreationDate,For,Pages diff --git a/kfile-plugins/ps/kfile_ps.h b/kfile-plugins/ps/kfile_ps.h new file mode 100644 index 00000000..339020d1 --- /dev/null +++ b/kfile-plugins/ps/kfile_ps.h @@ -0,0 +1,50 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Wilco Greven <greven@kde.org> + * + * 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. + * + * $Id$ + */ + +#ifndef __KFILE_PS_H__ +#define __KFILE_PS_H__ + +#include <kfilemetainfo.h> + +#include "dscparse_adapter.h" + +class QStringList; + +class KPSPlugin: public KFilePlugin, public KDSCCommentHandler +{ + Q_OBJECT +public: + KPSPlugin( QObject *parent, const char *name, + const QStringList& preferredItems ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); + + void comment( Name ); + void makeMimeTypeInfo( const char* mimeType ); + +private: + KFileMetaInfo _info; + KFileMetaInfoGroup _group; + KDSC* _dsc; + bool _endComments; + int _setData; +}; + +#endif diff --git a/kfile-plugins/raw/Makefile.am b/kfile-plugins/raw/Makefile.am new file mode 100644 index 00000000..c68309bc --- /dev/null +++ b/kfile-plugins/raw/Makefile.am @@ -0,0 +1,19 @@ +## Makefile.am for the raw thumbnail extration plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kcamerarawplugin.h + +kde_module_LTLIBRARIES = kfile_raw.la + +kfile_raw_la_SOURCES = kcamerarawplugin.cpp parse.c +kfile_raw_la_LIBADD = $(LIB_KIO) +kfile_raw_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +services_DATA = kfile_raw.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/raw/kcamerarawplugin.cpp b/kfile-plugins/raw/kcamerarawplugin.cpp new file mode 100644 index 00000000..525e53ae --- /dev/null +++ b/kfile-plugins/raw/kcamerarawplugin.cpp @@ -0,0 +1,141 @@ +/* This file is part of the KDE project + * Copyright (C) Steffen Hansen <hansen@kde.org> + * + * 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 "kcamerarawplugin.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <klocale.h> +#include <kgenericfactory.h> +#include <kdebug.h> +#include <ktempfile.h> +#include <kimageio.h> +#include <qfile.h> +#include <qimage.h> +#include <qwmatrix.h> +#include <cstdio> + + +typedef KGenericFactory<KCameraRawPlugin> RawFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_raw, RawFactory("kfile_raw")) + +#ifndef KDE_EXPORT +# define KDE_EXPORT +#endif + +/* Main entry point into raw parser */ +extern "C" { + int extract_thumbnail( FILE*, FILE*, int* ); + extern char make[]; + extern char model[]; +} + +bool KCameraRawPlugin::createPreview(const QString &path, QImage &img) +{ + /* Open file and extract thumbnail */ + FILE* input = fopen( QFile::encodeName(path), "rb" ); + if( !input ) return false; + KTempFile output; + output.setAutoDelete(true); + int orientation = 0; + if( extract_thumbnail( input, output.fstream(), &orientation ) ) { + fclose(input); + return false; + } + fclose(input); + output.close(); + if( !img.load( output.name() ) ) return false; + + if(orientation) { + QWMatrix M; + QWMatrix flip= QWMatrix(-1,0,0,1,0,0); + switch(orientation+1) { // 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 + } + img = img.xForm(M); + } + return true; +} + +KCameraRawPlugin::KCameraRawPlugin(QObject *parent, const char *name, + const QStringList &args ) + : KFilePlugin(parent, name, args) +{ + kdDebug(7034) << "KCameraRawPlugin c'tor" << endl; + + // + // define all possible meta info items + // + KFileMimeTypeInfo *info = addMimeTypeInfo("image/x-raw"); + KFileMimeTypeInfo::GroupInfo *group = addGroupInfo( info, "Info", + i18n("Image Info") ); + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo( group, "Manufacturer", i18n("Camera Manufacturer"), + QVariant::String ); + item = addItemInfo( group, "Model", i18n("Camera Model"), + QVariant::String ); + item = addItemInfo( group, "Thumbnail", i18n("Thumbnail"), + QVariant::Image ); + setHint( item, KFileMimeTypeInfo::Thumbnail ); +} + +bool KCameraRawPlugin::readInfo( KFileMetaInfo& info, uint what ) +{ + kdDebug(7034) << "KCameraRawPlugin::readInfo()" << endl; + + const QString path( info.path() ); + if ( path.isEmpty() ) // remote file + return false; + + KFileMetaInfoGroup group = appendGroup( info, "Info" ); + if ( what & KFileMetaInfo::Thumbnail ){ + QImage img; + if( createPreview( path,img ) ) { + appendItem( group, "Thumbnail", img ); + kdDebug(7034) << "thumbnail " << path << " created" << endl; + } + } else { + // HACK: We have to extract thumbnail to get any info... + QImage img; + createPreview( path,img ); + } + kdDebug(7034) << "make=" << make << endl; + kdDebug(7034) << "model=" << model << endl; + if( make[0] ) { + appendItem( group, "Manufacturer", &make[0] ); + } + if( model[0] ) { + appendItem( group, "Model", &model[0] ); + } + + return true; +} + +#include "kcamerarawplugin.moc" diff --git a/kfile-plugins/raw/kcamerarawplugin.h b/kfile-plugins/raw/kcamerarawplugin.h new file mode 100644 index 00000000..5a097784 --- /dev/null +++ b/kfile-plugins/raw/kcamerarawplugin.h @@ -0,0 +1,38 @@ +/* This file is part of the KDE project + * Copyright (C) 2005 Steffen Hansen <hansen@kde.org> + * + * 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 KCAMERARAWPLUGIN_H +#define KCAMERARAWPLUGIN_H + +#include <kfilemetainfo.h> + +class QImage; + +class KCameraRawPlugin: public KFilePlugin { + Q_OBJECT + +public: + KCameraRawPlugin(QObject *parent, const char *name, const QStringList& args); + virtual bool readInfo(KFileMetaInfo& info, uint what); + +private: + bool createPreview(const QString &path, QImage &img); +}; + +#endif /* KCAMERARAWPLUGIN_H */ diff --git a/kfile-plugins/raw/kfile_raw.desktop b/kfile-plugins/raw/kfile_raw.desktop new file mode 100644 index 00000000..696d286e --- /dev/null +++ b/kfile-plugins/raw/kfile_raw.desktop @@ -0,0 +1,53 @@ +[Desktop Entry] +Type=Service +Name=RAW Camera Files +Name[br]=Restroù kamera kriz +Name[bs]=RAW kamera datoteke +Name[ca]=Fitxers RAW de càmera +Name[cs]=RAW soubory +Name[da]=RAW kamera-filer +Name[de]=RAW Kamera-Dateien +Name[el]=RAW αρχείο κάμερας +Name[es]=Archivos RAW de cámara +Name[et]=Toored kaamerafailid +Name[eu]=RAW kamera-fitxategiak +Name[fa]=پروندههای خام دوربین +Name[fi]=RAW-kuvatiedostot +Name[fr]=Fichiers RAW d'appareil photo numérique +Name[ga]=Comhaid Cheamara RAW +Name[gl]=Ficheiros RAW de Cámara +Name[he]=קבצי מצלמה דיגיטלית גולמיים +Name[hu]=RAW-fájlok +Name[is]=RAW myndavélaskrár +Name[it]=File grezzi fotocamera digitale +Name[ja]=RAW カメラファイル +Name[kk]=Камераның RAW пішімдегі файлдары +Name[km]=ឯកសារចេញពីម៉ាស៊ីនថតរូប +Name[lt]=RAW fotoaparato bylos +Name[nb]=RAW-kamerafiler +Name[nds]=RAW-Kameradateien +Name[ne]=RAW क्यामेरा फाइल +Name[nl]=Rauwe camerabestanden +Name[nn]=RAW-kamerafiler +Name[pa]=RAW ਕੈਮਰਾ ਫਾਇਲਾਂ +Name[pl]=Pliki RAW z aparatów cyfrowych +Name[pt]=Ficheiros de Máquina Fotográfica Digital RAW +Name[pt_BR]=Arquivos de Câmeras +Name[ro]=Fişiere foto brute +Name[ru]=Необработанные Файлы с цифровой камеры (RAW) +Name[sk]=RAW súbory digitálneho fotoaparátu +Name[sl]=Surove datoteke s fotoaparata +Name[sr]=RAW фајлови слика +Name[sr@Latn]=RAW fajlovi slika +Name[sv]=Obehandlade kamerafiler +Name[th]=แฟ้มภาพ RAW จากกล้อง +Name[tr]=RAW Kamera Dosyaları +Name[uk]=Файли цифрової камери RAW +Name[zh_CN]=RAW 相机文件 +Name[zh_HK]=RAW 相機檔案 +Name[zh_TW]=原始相機檔 +ServiceTypes=KFilePlugin +MimeType=image/x-raw +X-KDE-Library=kfile_raw +CacheThumbnail=false +SupportsThumbnail=true diff --git a/kfile-plugins/raw/parse.c b/kfile-plugins/raw/parse.c new file mode 100644 index 00000000..1abbbfce --- /dev/null +++ b/kfile-plugins/raw/parse.c @@ -0,0 +1,1080 @@ +/* + Raw Photo Parser + Copyright 2004 by Dave Coffin, dcoffin a cybercom o net + + This program extracts thumbnail images (preferably JPEGs) + from any raw digital camera formats that have them, and + shows table contents. + + $Revision: 1.36 $ + $Date: 2005/05/10 21:43:10 $ + */ + +/* Hacked for thumbnail extraction in KDE by + Steffen Hansen <hansen@kde.org> + + Based on parse.c and parts of dcraw.c by Dave Coffin +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <time.h> +#include <sys/types.h> + +#ifdef WIN32 +#include <winsock2.h> +typedef __int64 INT64; +#else +#include <netinet/in.h> +typedef long long INT64; +#endif + +/* + TIFF and CIFF data blocks can be quite large. + Display only the first DLEN bytes. + */ +#ifndef DLEN +#define DLEN 768 +#endif + +typedef unsigned char uchar; +/*typedef unsigned short ushort;*/ + +FILE *ifp; +short order; +char *fname; +char make[128], model[128], model2[128], thumb_head[128]; +int width, height, offset, length, bps, is_dng; +int thumb_offset, thumb_length, thumb_layers; +float cam_mul[4], pre_mul[4], coeff[3][4]; +#define camera_red cam_mul[0] +#define camera_blue cam_mul[2] +/*float flash_used, canon_5814;*/ +time_t timestamp; +/*int data_offset, meta_offset*/ +int raw_height, raw_width, top_margin, left_margin; +static int flip = 0; + +struct decode { + struct decode *branch[2]; + int leaf; +} first_decode[640], *free_decode; + +#define CLASS + +#define FORC3 for (c=0; c < 3; c++) +#define FORC4 for (c=0; c < 4; c++) +#define FORCC for (c=0; c < colors; c++) + +/* + Get a 2-byte integer, making no assumptions about CPU byte order. + Nor should we assume that the compiler evaluates left-to-right. + */ +ushort get2() +{ + uchar a, b; + + a = fgetc(ifp); b = fgetc(ifp); + + if (order == 0x4949) /* "II" means little-endian */ + return a | b << 8; + else /* "MM" means big-endian */ + return a << 8 | b; +} + +/* + Same for a 4-byte integer. + */ +int get4() +{ + uchar a, b, c, d; + + a = fgetc(ifp); b = fgetc(ifp); + c = fgetc(ifp); d = fgetc(ifp); + + if (order == 0x4949) + return a | b << 8 | c << 16 | d << 24; + else + return a << 24 | b << 16 | c << 8 | d; +} + +void tiff_dump(int base, int tag, int type, int count, int level) +{ + int save, j, num, den; + uchar c; + int size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 }; + + if (count * size[type < 13 ? type:0] > 4) + fseek (ifp, get4()+base, SEEK_SET); + save = ftell(ifp); + fseek (ifp, save, SEEK_SET); +} + +void nikon_decrypt (uchar ci, uchar cj, int tag, int i, int size, uchar *buf) +{ +} + +int parse_tiff_ifd (int base, int level); + +void nef_parse_makernote (base) +{ + int offset=0, entries, tag, type, count, val, save; + unsigned serial=0, key=0; + uchar buf91[630], buf97[608], buf98[31]; + short sorder; + char buf[10]; + +/* + The MakerNote might have its own TIFF header (possibly with + its own byte-order!), or it might just be a table. + */ + sorder = order; + fread (buf, 1, 10, ifp); + if (!strcmp (buf,"Nikon")) { /* starts with "Nikon\0\2\0\0\0" ? */ + base = ftell(ifp); + order = get2(); /* might differ from file-wide byteorder */ + val = get2(); /* should be 42 decimal */ + offset = get4(); + fseek (ifp, offset-8, SEEK_CUR); + } else if (!strncmp (buf,"FUJIFILM",8) || + !strcmp (buf,"Panasonic")) { + order = 0x4949; + fseek (ifp, 2, SEEK_CUR); + } else if (!strcmp (buf,"OLYMP") || + !strcmp (buf,"LEICA") || + !strcmp (buf,"EPSON")) + fseek (ifp, -2, SEEK_CUR); + else if (!strcmp (buf,"AOC")) + fseek (ifp, -4, SEEK_CUR); + else + fseek (ifp, -10, SEEK_CUR); + + entries = get2(); + if (entries > 100) return; + while (entries--) { + save = ftell(ifp); + tag = get2(); + type = get2(); + count= get4(); + tiff_dump (base, tag, type, count, 2); + if (tag == 0x1d) + fscanf (ifp, "%d", &serial); + if (tag == 0x91) + fread (buf91, sizeof buf91, 1, ifp); + if (tag == 0x97) + fread (buf97, sizeof buf97, 1, ifp); + if (tag == 0x98) + fread (buf98, sizeof buf98, 1, ifp); + if (tag == 0xa7) + key = fgetc(ifp)^fgetc(ifp)^fgetc(ifp)^fgetc(ifp); + + if (tag == 0x100 && type == 7 && !strncmp(make,"OLYMPUS",7)) { + thumb_offset = ftell(ifp); + thumb_length = count; + } + if (tag == 0x280 && type == 1) { /* EPSON */ + strncpy (thumb_head, "\xff", sizeof(thumb_head) ); + thumb_offset = ftell(ifp)+1; + thumb_length = count-1; + } + if (strstr(make,"Minolta") || strstr(make,"MINOLTA")) { + switch (tag) { + case 0x81: + thumb_offset = ftell(ifp); + thumb_length = count; + break; + case 0x88: + thumb_offset = get4() + base; + break; + case 0x89: + thumb_length = get4(); + } + } + if (!strcmp (buf,"OLYMP") && tag >> 8 == 0x20) + parse_tiff_ifd (base, 3); + fseek (ifp, save+12, SEEK_SET); + } + nikon_decrypt (serial, key, 0x91, 4, sizeof buf91, buf91); + nikon_decrypt (serial, key, 0x97, 284, sizeof buf97, buf97); + nikon_decrypt (serial, key, 0x98, 4, sizeof buf98, buf98); + order = sorder; +} + +void nef_parse_exif(int base) +{ + int entries, tag, type, count, save; + + entries = get2(); + while (entries--) { + save = ftell(ifp); + tag = get2(); + type = get2(); + count= get4(); + tiff_dump (base, tag, type, count, 1); + if (tag == 0x927c) + nef_parse_makernote (base); + fseek (ifp, save+12, SEEK_SET); + } +} + +int parse_tiff_ifd (int base, int level) +{ + int entries, tag, type, count, slen, save, save2, val, i; + int comp=0; + static const int flip_map[] = { 0,1,3,2,4,6,7,5 }; + + entries = get2(); + if (entries > 255) return 1; + while (entries--) { + save = ftell(ifp); + tag = get2(); + type = get2(); + count= get4(); + slen = count; + if (slen > 128) slen = 128; + + tiff_dump (base, tag, type, count, level); + + save2 = ftell(ifp); + if (type == 3) /* short int */ + val = get2(); + else + val = get4(); + fseek (ifp, save2, SEEK_SET); + + if (tag > 50700 && tag < 50800) + is_dng = 1; + + if (level == 3) { /* Olympus E-1 and E-300 */ + if (type == 4) { + if (tag == 0x101) + thumb_offset = val; + else if (tag == 0x102) + thumb_length = val; + } + goto cont; + } + switch (tag) { + case 0x100: /* ImageWidth */ + if (!width) width = val; + break; + case 0x101: /* ImageHeight */ + if (!height) height = val; + break; + case 0x102: /* Bits per sample */ + if (bps) break; + bps = val; + if (count == 1) + thumb_layers = 1; + break; + case 0x103: /* Compression */ + comp = val; + break; + case 0x10f: /* Make tag */ + fgets (make, slen, ifp); + break; + case 0x110: /* Model tag */ + fgets (model, slen, ifp); + break; + case 33405: /* Model2 tag */ + fgets (model2, slen, ifp); + break; + case 0x111: /* StripOffset */ + if (!offset || is_dng) offset = val; + break; + case 0x112: /* Orientation */ + flip = flip_map[(val-1) & 7]; + break; + case 0x117: /* StripByteCounts */ + if (!length || is_dng) length = val; + if (offset > val && !strncmp(make,"KODAK",5) && !is_dng) + offset -= val; + break; + case 0x14a: /* SubIFD tag */ + save2 = ftell(ifp); + for (i=0; i < count; i++) { + fseek (ifp, save2 + i*4, SEEK_SET); + fseek (ifp, get4()+base, SEEK_SET); + parse_tiff_ifd (base, level+1); + } + break; + case 0x201: + if (strncmp(make,"OLYMPUS",7) || !thumb_offset) + thumb_offset = val; + break; + case 0x202: + if (strncmp(make,"OLYMPUS",7) || !thumb_length) + thumb_length = val; + break; + case 34665: + fseek (ifp, get4()+base, SEEK_SET); + nef_parse_exif (base); + break; + case 50706: + is_dng = 1; + } +cont: + fseek (ifp, save+12, SEEK_SET); + } + if ((comp == 6 && !strcmp(make,"Canon")) || + (comp == 7 && is_dng)) { + thumb_offset = offset; + thumb_length = length; + } + return 0; +} + +/* + Parse a TIFF file looking for camera model and decompress offsets. + */ +void parse_tiff (int base) +{ + int doff, spp=3, ifd=0; + + width = height = offset = length = bps = is_dng = 0; + fseek (ifp, base, SEEK_SET); + order = get2(); + if (order != 0x4949 && order != 0x4d4d) return; + get2(); + while ((doff = get4())) { + fseek (ifp, doff+base, SEEK_SET); + printf ("IFD #%d:\n", ifd++); + if (parse_tiff_ifd (base, 0)) break; + } + if (is_dng) return; + + if (strncmp(make,"KODAK",5)) + thumb_layers = 0; + if (!strncmp(make,"Kodak",5)) { + fseek (ifp, 12+base, SEEK_SET); + puts ("\nSpecial Kodak image directory:"); + parse_tiff_ifd (base, 0); + } + if (!strncmp(model,"DCS460A",7)) { + spp = 1; + thumb_layers = 0; + } + if (!thumb_length && offset) { + thumb_offset = offset; + sprintf (thumb_head, "P%d %d %d %d\n", + spp > 1 ? 6:5, width, height, (1 << bps) - 1); + thumb_length = width * height * spp * ((bps+7)/8); + } +} + +void parse_minolta() +{ + int data_offset, save, tag, len; + + fseek (ifp, 4, SEEK_SET); + data_offset = get4() + 8; + while ((save=ftell(ifp)) < data_offset) { + tag = get4(); + len = get4(); + printf ("Tag %c%c%c offset %06x length %06x\n", + tag>>16, tag>>8, tag, save, len); + switch (tag) { + case 0x545457: /* TTW */ + parse_tiff (ftell(ifp)); + } + fseek (ifp, save+len+8, SEEK_SET); + } + strncpy (thumb_head, "\xff", sizeof(thumb_head) ); + thumb_offset++; + thumb_length--; +} + +/* + Parse a CIFF file, better known as Canon CRW format. + */ +void parse_ciff (int offset, int length, int level /*unused*/) +{ + int tboff, nrecs, i, c, type, len, roff, aoff, save, wbi=-1; + static const int remap[] = { 1,2,3,4,5,1 }; + static const int remap_10d[] = { 0,1,3,4,5,6,0,0,2,8 }; + static const int remap_s70[] = { 0,1,2,9,4,3,6,7,8,9,10,0,0,0,7,0,0,8 }; + ushort key[] = { 0x410, 0x45f3 }; + + if (strcmp(model,"Canon PowerShot G6") && + strcmp(model,"Canon PowerShot S60") && + strcmp(model,"Canon PowerShot S70") && + strcmp(model,"Canon PowerShot Pro1")) + key[0] = key[1] = 0; + fseek (ifp, offset+length-4, SEEK_SET); + tboff = get4() + offset; + fseek (ifp, tboff, SEEK_SET); + nrecs = get2(); + if (nrecs > 100) return; + for (i = 0; i < nrecs; i++) { + type = get2(); + len = get4(); + roff = get4(); + aoff = offset + roff; + save = ftell(ifp); + if (type == 0x080a) { /* Get the camera make and model */ + fseek (ifp, aoff, SEEK_SET); + fread (make, 64, 1, ifp); + fseek (ifp, aoff+strlen(make)+1, SEEK_SET); + fread (model, 64, 1, ifp); + } + if (type == 0x102a) { /* Find the White Balance index */ + fseek (ifp, aoff+14, SEEK_SET); /* 0=auto, 1=daylight, 2=cloudy ... */ + wbi = get2(); + if (((!strcmp(model,"Canon EOS DIGITAL REBEL") || + !strcmp(model,"Canon EOS 300D DIGITAL"))) && wbi == 6) + wbi++; + } + if (type == 0x102c) { /* Get white balance (G2) */ + if (!strcmp(model,"Canon PowerShot G1") || + !strcmp(model,"Canon PowerShot Pro90 IS")) { + fseek (ifp, aoff+120, SEEK_SET); + FORC4 cam_mul[c ^ 2] = get2(); + } else { + fseek (ifp, aoff+100, SEEK_SET); + goto common; + } + } + if (type == 0x0032) { /* Get white balance (D30 & G3) */ + if (!strcmp(model,"Canon EOS D30")) { + fseek (ifp, aoff+72, SEEK_SET); +common: + camera_red = get2() ^ key[0]; + camera_red =(get2() ^ key[1]) / camera_red; + camera_blue = get2() ^ key[0]; + camera_blue /= get2() ^ key[1]; + } else if (!strcmp(model,"Canon PowerShot G6") || + !strcmp(model,"Canon PowerShot S60") || + !strcmp(model,"Canon PowerShot S70")) { + fseek (ifp, aoff+96 + remap_s70[wbi]*8, SEEK_SET); + goto common; + } else if (!strcmp(model,"Canon PowerShot Pro1")) { + fseek (ifp, aoff+96 + wbi*8, SEEK_SET); + goto common; + } else { + fseek (ifp, aoff+80 + (wbi < 6 ? remap[wbi]*8 : 0), SEEK_SET); + if (!camera_red) + goto common; + } + } + if (type == 0x10a9) { /* Get white balance (D60) */ + if (!strcmp(model,"Canon EOS 10D")) + wbi = remap_10d[wbi]; + fseek (ifp, aoff+2 + wbi*8, SEEK_SET); + camera_red = get2(); + camera_red /= get2(); + camera_blue = get2(); + camera_blue = get2() / camera_blue; + } + /* Skip this for now /steffen */ +#if 0 + if (type == 0x1030 && (wbi == 6 || wbi == 15)) { + fseek (ifp, aoff, SEEK_SET); /* Get white sample */ + ciff_block_1030(); + } +#endif + if (type == 0x1031) { /* Get the raw width and height */ + fseek (ifp, aoff+2, SEEK_SET); + raw_width = get2(); + raw_height = get2(); + } + if (type == 0x180e) { /* Get the timestamp */ + fseek (ifp, aoff, SEEK_SET); + timestamp = get4(); + } + if (type == 0x580e) + timestamp = len; +#if 0 + if (type == 0x5813) + flash_used = *((float *) &len); + if (type == 0x5814) + canon_5814 = *((float *) &len); +#endif + if (type == 0x1810) { /* Get the rotation */ + fseek (ifp, aoff+12, SEEK_SET); + flip = get4(); + } + /* Skip this for now /steffen */ +#if 0 + if (type == 0x1835) { /* Get the decoder table */ + fseek (ifp, aoff, SEEK_SET); + crw_init_tables (get4()); + } +#endif + if (type == 0x2007) { /* Found the JPEG thumbnail */ + thumb_offset = aoff; + thumb_length = len; + } + if (type >> 8 == 0x28 || type >> 8 == 0x30) /* Get sub-tables */ + parse_ciff(aoff, len, level+1); + fseek (ifp, save, SEEK_SET); + } + if (wbi == 0 && !strcmp(model,"Canon EOS D30")) + camera_red = -1; /* Use my auto WB for this photo */ +} + + +void parse_mos(int level) +{ + uchar data[256]; + int i, j, skip, save; + char *cp; + + save = ftell(ifp); + while (1) { + fread (data, 1, 8, ifp); + if (strcmp(data,"PKTS")) break; + strcpy (model, "Valeo"); + fread (data, 1, 40, ifp); + skip = get4(); + if (!strcmp(data,"icc_camera_to_tone_matrix")) { + for (i=0; i < skip/4; i++) { + j = get4(); + } + continue; + } + if (!strcmp(data,"JPEG_preview_data")) { + thumb_head[0] = 0; + thumb_offset = ftell(ifp); + thumb_length = skip; + } + fread (data, 1, sizeof data, ifp); + fseek (ifp, -sizeof data, SEEK_CUR); + data[sizeof data - 1] = 0; + while ((cp=index(data,'\n'))) + *cp = ' '; + parse_mos(level+2); + fseek (ifp, skip, SEEK_CUR); + } + fseek (ifp, save, SEEK_SET); +} + +void parse_rollei() +{ + char line[128], *val; + + fseek (ifp, 0, SEEK_SET); + do { + fgets (line, 128, ifp); + fputs (line, stdout); + if ((val = strchr(line,'='))) + *val++ = 0; + else + val = line + strlen(line); + if (!strcmp(line,"HDR")) + thumb_offset = atoi(val); + if (!strcmp(line,"TX ")) + width = atoi(val); + if (!strcmp(line,"TY ")) + height = atoi(val); + } while (strncmp(line,"EOHD",4)); + strcpy (make, "Rollei"); + strcpy (model, "d530flex"); + thumb_length = width*height*2; +} + +void rollei_decode (FILE *tfp) +{ + ushort data; + int row, col; + + fseek (ifp, thumb_offset, SEEK_SET); + fprintf (tfp, "P6\n%d %d\n255\n", width, height); + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + fread (&data, 2, 1, ifp); + data = ntohs(data); + putc (data << 3, tfp); + putc (data >> 5 << 2, tfp); + putc (data >> 11 << 3, tfp); + } +} + +void get_utf8 (int offset, char *buf, int len) +{ + ushort c; + char *cp; + + fseek (ifp, offset, SEEK_SET); + for (cp=buf; (c = get2()) && cp+3 < buf+len; ) { + if (c < 0x80) + *cp++ = c; + else if (c < 0x800) { + *cp++ = 0xc0 + (c >> 6); + *cp++ = 0x80 + (c & 0x3f); + } else { + *cp++ = 0xe0 + (c >> 12); + *cp++ = 0x80 + (c >> 6 & 0x3f); + *cp++ = 0x80 + (c & 0x3f); + } + } + *cp = 0; +} + +ushort sget2 (uchar *s) +{ + return s[0] + (s[1]<<8); +} + +int sget4 (uchar *s) +{ + return s[0] + (s[1]<<8) + (s[2]<<16) + (s[3]<<24); +} + +void parse_foveon() +{ + int entries, img=0, off, len, tag, save, i, j, k, pent, poff[256][2]; + char name[128], value[128], camf[0x20000], *pos, *cp, *dp; + unsigned val, key, type, num, ndim, dim[3]; + + order = 0x4949; /* Little-endian */ + fseek (ifp, -4, SEEK_END); + fseek (ifp, get4(), SEEK_SET); + if (get4() != 0x64434553) { /* SECd */ + printf ("Bad Section identifier at %6x\n", (int)ftell(ifp)-4); + return; + } + get4(); + entries = get4(); + while (entries--) { + off = get4(); + len = get4(); + tag = get4(); + save = ftell(ifp); + fseek (ifp, off, SEEK_SET); + if (get4() != (0x20434553 | (tag << 24))) { + printf ("Bad Section identifier at %6x\n", off); + goto next; + } + val = get4(); + switch (tag) { + case 0x32414d49: /* IMA2 */ + case 0x47414d49: /* IMAG */ + if (++img == 2) { /* second image */ + thumb_offset = off; + thumb_length = 1; + } + printf ("type %d, " , get4()); + printf ("format %2d, " , get4()); + printf ("columns %4d, " , get4()); + printf ("rows %4d, " , get4()); + printf ("rowsize %d\n" , get4()); + break; + case 0x464d4143: /* CAMF */ + printf ("type %d, ", get4()); + get4(); + for (i=0; i < 4; i++) + putchar(fgetc(ifp)); + val = get4(); + printf (" version %d.%d:\n",val >> 16, val & 0xffff); + key = get4(); + if ((len -= 28) > 0x20000) + len = 0x20000; + fread (camf, 1, len, ifp); + for (i=0; i < len; i++) { + key = (key * 1597 + 51749) % 244944; + val = key * (INT64) 301593171 >> 24; + camf[i] ^= ((((key << 8) - val) >> 1) + val) >> 17; + } + for (pos=camf; (unsigned) (pos-camf) < len; pos += sget4(pos+8)) { + if (strncmp (pos, "CMb", 3)) { + printf("Bad CAMF tag \"%.4s\"\n", pos); + break; + } + val = sget4(pos+4); + printf (" %4.4s version %d.%d: ", pos, val >> 16, val & 0xffff); + switch (pos[3]) { + case 'M': + cp = pos + sget4(pos+16); + type = sget4(cp); + ndim = sget4(cp+4); + dim[0] = dim[1] = dim[2] = 1; + printf ("%d-dimensonal array %s of type %d:\n Key: (", + ndim, pos+sget4(pos+12), sget4(cp)); + dp = pos + sget4(cp+8); + for (i=ndim; i--; ) { + cp += 12; + dim[i] = sget4(cp); + printf ("%s %d%s", pos+sget4(cp+4), dim[i], i ? ", ":")\n"); + } + for (i=0; i < dim[2]; i++) { + for (j=0; j < dim[1]; j++) { + printf (" "); + for (k=0; k < dim[0]; k++) + switch (type) { + case 0: + case 6: + printf ("%7d", sget2(dp)); + dp += 2; + break; + case 1: + case 2: + printf (" %d", sget4(dp)); + dp += 4; + break; + case 3: { + union { int ival; float fval; } __t; + __t.ival = sget4(dp); + printf (" %9f", __t.fval); + dp += 4; + } + } + printf ("\n"); + } + printf ("\n"); + } + break; + case 'P': + val = sget4(pos+16); + num = sget4(pos+val); + printf ("%s, %d parameters:\n", pos+sget4(pos+12), num); + cp = pos+val+8 + num*8; + for (i=0; i < num; i++) { + val += 8; + printf (" %s = %s\n", cp+sget4(pos+val), cp+sget4(pos+val+4)); + } + break; + case 'T': + cp = pos + sget4(pos+16); + printf ("%s = %.*s\n", pos+sget4(pos+12), sget4(cp), cp+4); + break; + default: + printf ("\n"); + } + } + break; + case 0x504f5250: /* PROP */ + printf ("entries %d, ", pent=get4()); + printf ("charset %d, ", get4()); + get4(); + printf ("nchars %d\n", get4()); + off += pent*8 + 24; + if (pent > 256) pent=256; + for (i=0; i < pent*2; i++) + poff[0][i] = off + get4()*2; + for (i=0; i < pent; i++) { + get_utf8 (poff[i][0], name, 128); + get_utf8 (poff[i][1], value, 128); + printf (" %s = %s\n", name, value); + if (!strcmp (name,"CAMMANUF")) + strncpy (make, value, sizeof(make)); + if (!strcmp (name,"CAMMODEL")) + strncpy (model, value, sizeof(value)); + } + } +next: + fseek (ifp, save, SEEK_SET); + } +} + +void foveon_tree (unsigned huff[1024], unsigned code) +{ + struct decode *cur; + int i, len; + + cur = free_decode++; + if (code) { + for (i=0; i < 1024; i++) + if (huff[i] == code) { + cur->leaf = i; + return; + } + } + if ((len = code >> 27) > 26) return; + code = (len+1) << 27 | (code & 0x3ffffff) << 1; + + cur->branch[0] = free_decode; + foveon_tree (huff, code); + cur->branch[1] = free_decode; + foveon_tree (huff, code+1); +} + +void foveon_decode (FILE *tfp) +{ + int bwide, row, col, bit=-1, c, i; + char *buf; + struct decode *dindex; + short pred[3]; + unsigned huff[1024], bitbuf=0; + + fseek (ifp, thumb_offset+16, SEEK_SET); + width = get4(); + height = get4(); + bwide = get4(); + fprintf (tfp, "P6\n%d %d\n255\n", width, height); + if (bwide > 0) { + buf = malloc(bwide); + for (row=0; row < height; row++) { + fread (buf, 1, bwide, ifp); + fwrite (buf, 3, width, tfp); + } + free (buf); + return; + } + for (i=0; i < 256; i++) + huff[i] = get4(); + memset (first_decode, 0, sizeof first_decode); + free_decode = first_decode; + foveon_tree (huff, 0); + + for (row=0; row < height; row++) { + memset (pred, 0, sizeof pred); + if (!bit) get4(); + for (col=bit=0; col < width; col++) { + for (c=0; c < 3; c++) { + for (dindex=first_decode; dindex->branch[0]; ) { + if ((bit = (bit-1) & 31) == 31) + for (i=0; i < 4; i++) + bitbuf = (bitbuf << 8) + fgetc(ifp); + dindex = dindex->branch[bitbuf >> bit & 1]; + } + pred[c] += dindex->leaf; + fputc (pred[c], tfp); + } + } + } +} + +void kodak_yuv_decode (FILE *tfp) +{ + uchar c, blen[384]; + unsigned row, col, len, bits=0; + INT64 bitbuf=0; + int i, li=0, si, diff, six[6], y[4], cb=0, cr=0, rgb[3]; + ushort *out, *op; + + fseek (ifp, thumb_offset, SEEK_SET); + width = (width+1) & -2; + height = (height+1) & -2; + fprintf (tfp, "P6\n%d %d\n65535\n", width, height); + out = malloc (width * 12); + if (!out) { + fprintf (stderr, "kodak_yuv_decode() malloc failed!\n"); + exit(1); + } + + for (row=0; row < height; row+=2) { + for (col=0; col < width; col+=2) { + if ((col & 127) == 0) { + len = (width - col + 1) * 3 & -4; + if (len > 384) len = 384; + for (i=0; i < len; ) { + c = fgetc(ifp); + blen[i++] = c & 15; + blen[i++] = c >> 4; + } + li = bitbuf = bits = y[1] = y[3] = cb = cr = 0; + if (len % 8 == 4) { + bitbuf = fgetc(ifp) << 8; + bitbuf += fgetc(ifp); + bits = 16; + } + } + for (si=0; si < 6; si++) { + len = blen[li++]; + if (bits < len) { + for (i=0; i < 32; i+=8) + bitbuf += (INT64) fgetc(ifp) << (bits+(i^8)); + bits += 32; + } + diff = bitbuf & (0xffff >> (16-len)); + bitbuf >>= len; + bits -= len; + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + six[si] = diff; + } + y[0] = six[0] + y[1]; + y[1] = six[1] + y[0]; + y[2] = six[2] + y[3]; + y[3] = six[3] + y[2]; + cb += six[4]; + cr += six[5]; + for (i=0; i < 4; i++) { + op = out + ((i >> 1)*width + col+(i & 1)) * 3; + rgb[0] = y[i] + 1.40200/2 * cr; + rgb[1] = y[i] - 0.34414/2 * cb - 0.71414/2 * cr; + rgb[2] = y[i] + 1.77200/2 * cb; + for (c=0; c < 3; c++) + if (rgb[c] > 0) op[c] = htons(rgb[c]); + } + } + fwrite (out, sizeof *out, width*6, tfp); + } + free(out); +} + +void parse_phase_one (int base) +{ + unsigned entries, tag, type, len, data, save; + char str[256]; + + fseek (ifp, base + 8, SEEK_SET); + fseek (ifp, base + get4(), SEEK_SET); + entries = get4(); + get4(); + while (entries--) { + tag = get4(); + type = get4(); + len = get4(); + data = get4(); + save = ftell(ifp); + printf ("Phase One tag=0x%x, type=%d, len=%2d, data = 0x%x\n", + tag, type, len, data); + if (type == 1 && len < 256) { + fseek (ifp, base + data, SEEK_SET); + fread (str, 256, 1, ifp); + puts (str); + } + if (tag == 0x110) { + thumb_offset = data + base; + thumb_length = len; + } + fseek (ifp, save, SEEK_SET); + } + strcpy (make, "Phase One"); + strcpy (model, "unknown"); +} + +void parse_jpeg (int offset) +{ + int len, save, hlen; + + fseek (ifp, offset, SEEK_SET); + if (fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) return; + + while (fgetc(ifp) == 0xff && fgetc(ifp) >> 4 != 0xd) { + order = 0x4d4d; + len = get2() - 2; + save = ftell(ifp); + order = get2(); + hlen = get4(); + if (get4() == 0x48454150) /* "HEAP" */ + parse_ciff (save+hlen, len-hlen, 0); + parse_tiff (save+6); + fseek (ifp, save+len, SEEK_SET); + } +} + +char *raw_memmem (char *haystack, size_t haystacklen, + char *needle, size_t needlelen) +{ + char *c; + for (c = haystack; c <= haystack + haystacklen - needlelen; c++) + if (!memcmp (c, needle, needlelen)) + return c; + return NULL; +} + +/* + Identify which camera created this file, and set global variables + accordingly. + Return nonzero if the file cannot be decoded or no thumbnail is found + */ +int identify(FILE* tfp) +{ + char head[32], *thumb, *rgb, *cp; + unsigned hlen, fsize, toff, tlen, lsize, i; + + make[0] = model[0] = model2[0] = is_dng = 0; + thumb_head[0] = thumb_offset = thumb_length = thumb_layers = 0; + order = get2(); + hlen = get4(); + fseek (ifp, 0, SEEK_SET); + fread (head, 1, 32, ifp); + fseek (ifp, 0, SEEK_END); + fsize = ftell(ifp); + if ((cp = raw_memmem (head, 32, "MMMMRawT", 8)) || + (cp = raw_memmem (head, 32, "IIIITwaR", 8))) + parse_phase_one (cp - head); + else if (order == 0x4949 || order == 0x4d4d) { + if (!memcmp(head+6,"HEAPCCDR",8)) { + parse_ciff (hlen, fsize - hlen, 0); + fseek (ifp, hlen, SEEK_SET); + } else + parse_tiff (0); + } else if (!memcmp (head, "\0MRM", 4)) + parse_minolta(); + else if (!memcmp (head, "\xff\xd8\xff\xe1", 4) && + !memcmp (head+6, "Exif", 4)) { + parse_tiff (12); + thumb_length = 0; + } else if (!memcmp (head, "FUJIFILM", 8)) { + fseek (ifp, 84, SEEK_SET); + toff = get4(); + tlen = get4(); + thumb_offset = toff; + thumb_length = tlen; + } else if (!memcmp (head, "DSC-Image", 9)) + parse_rollei(); + else if (!memcmp (head, "FOVb", 4)) + parse_foveon(); + fseek (ifp, 8, SEEK_SET); + parse_mos(0); + fseek (ifp, 3472, SEEK_SET); + parse_mos(0); + parse_jpeg(0); + + if (!thumb_length) { + fprintf (stderr, "Thumbnail image not found\n"); + return -1; + } + + if (is_dng) goto dng_skip; + if (!strncmp(model,"DCS Pro",7)) { + kodak_yuv_decode (tfp); + goto done; + } + if (!strcmp(make,"Rollei")) { + rollei_decode (tfp); + goto done; + } + if (!strcmp(make,"SIGMA")) { + foveon_decode (tfp); + goto done; + } +dng_skip: + thumb = (char *) malloc(thumb_length); + if (!thumb) { + fprintf (stderr, "Cannot allocate %d bytes!!\n", thumb_length); + exit(1); + } + fseek (ifp, thumb_offset, SEEK_SET); + fread (thumb, 1, thumb_length, ifp); + if (thumb_layers && !is_dng) { + rgb = (char *) malloc(thumb_length); + if (!rgb) { + fprintf (stderr, "Cannot allocate %d bytes!!\n", thumb_length); + return -1; + } + lsize = thumb_length/3; + for (i=0; i < thumb_length; i++) + rgb[(i%lsize)*3 + i/lsize] = thumb[i]; + free(thumb); + thumb = rgb; + } + fputs (thumb_head, tfp); + fwrite(thumb, 1, thumb_length, tfp); + free (thumb); +done: + fprintf (stderr, "Thumbnail image written, make=%s, model=%s\n",&(make[0]),&(model[0])); + return 0; +} + +int extract_thumbnail( FILE* input, FILE* output, int* orientation ) +{ + /* Coffin's code has different meaning for orientation + values than TIFF, so we map them to TIFF values */ + static const int flip_map[] = { 0,1,3,2,4,7,5,6 }; + int rc; + ifp = input; + rc = identify(output); + switch ((flip+3600) % 360) { + case 270: flip = 5; break; + case 180: flip = 3; break; + case 90: flip = 6; + } + if( orientation ) *orientation = flip_map[flip%7]; + return rc; +} diff --git a/kfile-plugins/rgb/Makefile.am b/kfile-plugins/rgb/Makefile.am new file mode 100644 index 00000000..8fc22e17 --- /dev/null +++ b/kfile-plugins/rgb/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for rgb file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_rgb.h + +kde_module_LTLIBRARIES = kfile_rgb.la + +kfile_rgb_la_SOURCES = kfile_rgb.cpp +kfile_rgb_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_rgb_la_LIBADD = $(LIB_KSYCOCA) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_rgb.cpp -o $(podir)/kfile_rgb.pot + +services_DATA = kfile_rgb.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/rgb/kfile_rgb.cpp b/kfile-plugins/rgb/kfile_rgb.cpp new file mode 100644 index 00000000..b7b55035 --- /dev/null +++ b/kfile-plugins/rgb/kfile_rgb.cpp @@ -0,0 +1,208 @@ +/* This file is part of the KDE project + * Copyright (C) 2004 Melchior FRANZ <mfranz@kde.org> + * + * 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 <config.h> +#include "kfile_rgb.h" + +#include <qfile.h> +#include <qvalidator.h> + +#include <kdebug.h> +#include <kgenericfactory.h> + + +typedef KGenericFactory<KRgbPlugin> RgbFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_rgb, RgbFactory("kfile_rgb")) + + +KRgbPlugin::KRgbPlugin(QObject *parent, const char *name, const QStringList &args) : + KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo("image/x-rgb"); + + KFileMimeTypeInfo::GroupInfo* group = 0; + KFileMimeTypeInfo::ItemInfo* item; + + + group = addGroupInfo(info, "Comment", i18n("Comment")); + + item = addItemInfo(group, "ImageName", i18n("Name"), QVariant::String); + setAttributes(item, KFileMimeTypeInfo::Modifiable); + setHint(item, KFileMimeTypeInfo::Description); + + + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size); + setHint(item, KFileMimeTypeInfo::Size); + setUnit(item, KFileMimeTypeInfo::Pixels); + + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); + + item = addItemInfo(group, "ColorMode", i18n("Color Mode"), QVariant::String); + item = addItemInfo(group, "Compression", i18n("Compression"), QVariant::String); + item = addItemInfo(group, "SharedRows", + i18n("percentage of avoided vertical redundancy (the higher the better)", + "Shared Rows"), QVariant::String); + +} + + +bool KRgbPlugin::readInfo(KFileMetaInfo& info, uint /*what*/) +{ + QFile file(info.path()); + + if (!file.open(IO_ReadOnly)) { + kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + QDataStream dstream(&file); + + Q_UINT16 magic; + Q_UINT8 storage; + Q_UINT8 bpc; + Q_UINT16 dimension; + Q_UINT16 xsize; + Q_UINT16 ysize; + Q_UINT16 zsize; + Q_UINT32 pixmin; + Q_UINT32 pixmax; + Q_UINT32 dummy; + char imagename[80]; + Q_UINT32 colormap; + + dstream >> magic; + dstream >> storage; + dstream >> bpc; + dstream >> dimension; + dstream >> xsize; + dstream >> ysize; + dstream >> zsize; + dstream >> pixmin; + dstream >> pixmax; + dstream >> dummy; + dstream.readRawBytes(imagename, 80); + imagename[79] = '\0'; + dstream >> colormap; + Q_UINT8 u8; + for (uint i = 0; i < 404; i++) + dstream >> u8; + + if (magic != 474) + return false; + + KFileMetaInfoGroup group; + + group = appendGroup(info, "Technical"); + + if (dimension == 1) + ysize = 1; + appendItem(group, "Dimensions", QSize(xsize, ysize)); + appendItem(group, "BitDepth", zsize * 8 * bpc); + + if (zsize == 1) + appendItem(group, "ColorMode", i18n("Grayscale")); + else if (zsize == 2) + appendItem(group, "ColorMode", i18n("Grayscale/Alpha")); + else if (zsize == 3) + appendItem(group, "ColorMode", i18n("RGB")); + else if (zsize == 4) + appendItem(group, "ColorMode", i18n("RGB/Alpha")); + + if (!storage) + appendItem(group, "Compression", i18n("Uncompressed")); + else if (storage == 1) { + long compressed = file.size() - 512; + long verbatim = xsize * ysize * zsize; + appendItem(group, "Compression", i18n("Runlength Encoded") + + QString(", %1%").arg(compressed * 100.0 / verbatim, 0, 'f', 1)); + + long k; + Q_UINT32 offs; + QMap<Q_UINT32, uint> map; + QMap<Q_UINT32, uint>::Iterator it; + QMap<Q_UINT32, uint>::Iterator end = map.end(); + for (k = 0; k < (ysize * zsize); k++) { + dstream >> offs; + if ((it = map.find(offs)) != end) + map.replace(offs, it.data() + 1); + else + map[offs] = 0; + } + for (k = 0, it = map.begin(); it != end; ++it) + k += it.data(); + + if (k) + appendItem(group, "SharedRows", QString("%1%").arg(k * 100.0 + / (ysize * zsize), 0, 'f', 1)); + else + appendItem(group, "SharedRows", i18n("None")); + } else + appendItem(group, "Compression", i18n("Unknown")); + + + group = appendGroup(info, "Comment"); + appendItem(group, "ImageName", imagename); + + file.close(); + return true; +} + + +bool KRgbPlugin::writeInfo(const KFileMetaInfo& info) const +{ + QFile file(info.path()); + + if (!file.open(IO_WriteOnly|IO_Raw)) { + kdDebug(7034) << "couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + if (!file.at(24)) { + kdDebug(7034) << "couldn't set offset" << endl; + return false; + } + + QDataStream dstream(&file); + QString s = info["Comment"]["ImageName"].value().toString(); + s.truncate(79); + + unsigned i; + for (i = 0; i < s.length(); i++) + dstream << Q_UINT8(s.latin1()[i]); + for (; i < 80; i++) + dstream << Q_UINT8(0); + + file.close(); + return true; +} + + +// restrict to 79 ASCII characters +QValidator* KRgbPlugin::createValidator(const QString&, const QString &, + const QString &, QObject* parent, const char* name) const +{ + return new QRegExpValidator(QRegExp("[\x0020-\x007E]{79}"), parent, name); +} + + +#include "kfile_rgb.moc" diff --git a/kfile-plugins/rgb/kfile_rgb.desktop b/kfile-plugins/rgb/kfile_rgb.desktop new file mode 100644 index 00000000..3a02989d --- /dev/null +++ b/kfile-plugins/rgb/kfile_rgb.desktop @@ -0,0 +1,61 @@ +[Desktop Entry] +Type=Service +Name=SGI Image (RGB) +Name[br]=Skeudenn SGI (RGB) +Name[bs]=SGI slika (RGB) +Name[ca]=Imatge SGI (RGB) +Name[cs]=SGI obrázek (RGB) +Name[cy]=Delwedd SGI (RGB) +Name[da]=SGI-billede (RGB) +Name[de]=SGI-Bild (RGB) +Name[el]=Εικόνα SGI (RGB) +Name[es]=Imagen SGI (RGB) +Name[et]=SGI pildifail (RGB) +Name[eu]=SGI irudia RGB) +Name[fa]=تصویر SGI (RGB) +Name[fi]=SGI-kuva (RGB) +Name[fr]=Image SGI (RVB) +Name[ga]=Íomhá SGI (RGB) +Name[gl]=Imaxe SGI (RGB) +Name[he]=תמונת SGI (RGB) +Name[hr]=SGI slika (RGB) +Name[hu]=SGI-kép (RGB) +Name[is]=SGI mynd (TGB) +Name[it]=Immagine SGI (RGB) +Name[ja]=SGI 画像 (RGB) +Name[kk]=SGI кескіні (RGB) +Name[km]=រូបភាព SGI (RGB) +Name[lt]=SGI paveiksliukas (RGB) +Name[ms]=Imej SGI (RGB) +Name[nb]=Bildeindeks +Name[nds]=SGI-Bild (RGB) +Name[ne]=SGI छवि (RGB) +Name[nl]=SGI-afbeelding (RGB) +Name[nn]=SGI-bilete (RGB) +Name[pl]=Obrazek SGI (RGB) +Name[pt]=Imagem SGI (RGB) +Name[pt_BR]=Imagem SGI (RGB) +Name[ro]=Imagine SGI (RGB) +Name[ru]=Изображение SGI (RGB) +Name[rw]=SGI Ishusho (RGB) +Name[se]=SGI-govva (RGB) +Name[sk]=SGI obrázok (RGB) +Name[sl]=Slika SGI (RGB) +Name[sr]=SGI слика (RGB) +Name[sr@Latn]=SGI slika (RGB) +Name[sv]=SGI-bild (RGB) +Name[ta]=எஸ்ஜிஐ படிமம் (RGB) +Name[tg]=Тасвироти SGI (RGB) +Name[th]=ภาพ SGI (RGB) +Name[tr]=SGI Resmi(KYM) +Name[uk]=Зображення SGI (RGB) +Name[uz]=SGI-rasm (RGB) +Name[uz@cyrillic]=SGI-расм (RGB) +Name[zh_CN]=SGI 图像(RGB) +Name[zh_HK]=SGI 圖像 (RGB) +Name[zh_TW]=SGI 影像(RGB) +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_rgb +MimeType=image/x-rgb +PreferredGroups=Comment,Technical +PreferredItems=Dimensions,BitDepth,ColorMode,Compression,SharedRows,ImageName diff --git a/kfile-plugins/rgb/kfile_rgb.h b/kfile-plugins/rgb/kfile_rgb.h new file mode 100644 index 00000000..dbbfef0e --- /dev/null +++ b/kfile-plugins/rgb/kfile_rgb.h @@ -0,0 +1,41 @@ +/* This file is part of the KDE project + * Copyright (C) 2004 Melcrhio FRANZ <mfranz@kde.org> + * + * 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_RGB_H__ +#define __KFILE_RGB_H__ + +#include <kfilemetainfo.h> + +class QStringList; + +class KRgbPlugin : public KFilePlugin +{ + Q_OBJECT + +public: + KRgbPlugin(QObject *parent, const char *name, const QStringList& args); + virtual bool readInfo(KFileMetaInfo& info, uint what); + virtual bool writeInfo(const KFileMetaInfo& info) const; + virtual QValidator* createValidator(const QString& mimetype, + const QString &group, const QString &key, + QObject* parent, const char* name) const; + +}; + +#endif diff --git a/kfile-plugins/tga/Makefile.am b/kfile-plugins/tga/Makefile.am new file mode 100644 index 00000000..3856c26f --- /dev/null +++ b/kfile-plugins/tga/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for tga file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_tga.h + +kde_module_LTLIBRARIES = kfile_tga.la + +kfile_tga_la_SOURCES = kfile_tga.cpp +kfile_tga_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_tga_la_LIBADD = $(LIB_KSYCOCA) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_tga.cpp -o $(podir)/kfile_tga.pot + +services_DATA = kfile_tga.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/tga/kfile_tga.cpp b/kfile-plugins/tga/kfile_tga.cpp new file mode 100644 index 00000000..9c2c24dc --- /dev/null +++ b/kfile-plugins/tga/kfile_tga.cpp @@ -0,0 +1,165 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk> + * + * 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 <config.h> +#include "kfile_tga.h" + +#include <kprocess.h> +#include <klocale.h> +#include <kgenericfactory.h> +#include <kstringvalidator.h> +#include <kdebug.h> + +#include <qdict.h> +#include <qvalidator.h> +#include <qcstring.h> +#include <qfile.h> +#include <qdatetime.h> + +#if !defined(__osf__) +#include <inttypes.h> +#else +typedef unsigned long uint32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; +#endif + +typedef KGenericFactory<KTgaPlugin> TgaFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_tga, TgaFactory( "kfile_tga" )) + +KTgaPlugin::KTgaPlugin(QObject *parent, const char *name, + const QStringList &args) + + : KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-targa" ); + + KFileMimeTypeInfo::GroupInfo* group = 0L; + + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit(item, KFileMimeTypeInfo::Pixels); + + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); + + item = addItemInfo(group, "ColorMode", i18n("Color Mode"), QVariant::String); + item = addItemInfo(group, "Compression", i18n("Compression"), QVariant::String); + +} + +bool KTgaPlugin::readInfo( KFileMetaInfo& info, uint what) +{ + + + QFile file(info.path()); + + if (!file.open(IO_ReadOnly)) + { + kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + QDataStream dstream(&file); + + // TGA files are little-endian + dstream.setByteOrder(QDataStream::LittleEndian); + + // the vars for the image data + uint8_t tga_idlength; + uint8_t tga_colormaptype; + uint8_t tga_imagetype; + uint16_t tga_colormap_fei; + uint16_t tga_colormap_length; + uint8_t tga_colormap_entrysize; + uint16_t tga_imagespec_origin_x; + uint16_t tga_imagespec_origin_y; + uint16_t tga_imagespec_width; + uint16_t tga_imagespec_height; + uint8_t tga_imagespec_depth; + uint8_t tga_imagespec_descriptor; + + // read the image data + dstream >> tga_idlength; + dstream >> tga_colormaptype; + dstream >> tga_imagetype; + dstream >> tga_colormap_fei; + dstream >> tga_colormap_length; + dstream >> tga_colormap_entrysize; + dstream >> tga_imagespec_origin_x; + dstream >> tga_imagespec_origin_y; + dstream >> tga_imagespec_width; + dstream >> tga_imagespec_height; + dstream >> tga_imagespec_depth; + dstream >> tga_imagespec_descriptor; + + // output the useful bits + KFileMetaInfoGroup group = appendGroup(info, "Technical"); + appendItem(group, "Dimensions", QSize(tga_imagespec_width, tga_imagespec_height)); + appendItem(group, "BitDepth", tga_imagespec_depth); + + switch (tga_imagetype) { + case 1 : + case 9 : + case 32 : + appendItem(group, "ColorMode", i18n("Color-Mapped")); + break; + case 2 : + case 10 : + case 33 : + appendItem(group, "ColorMode", i18n("RGB")); + break; + case 3 : + case 11 : + appendItem(group, "ColorMode", i18n("Black and White")); + break; + default : + appendItem(group, "ColorMode", i18n("Unknown")); + } + + switch (tga_imagetype) { + case 1 : + case 2 : + case 3 : + appendItem(group, "Compression", i18n("Uncompressed")); + break; + case 9 : + case 10 : + case 11 : + appendItem(group, "Compression", i18n("Runlength Encoded")); + break; + case 32 : + appendItem(group, "Compression", i18n("Huffman, Delta & RLE")); + break; + case 33 : + appendItem(group, "Compression", i18n("Huffman, Delta, RLE (4-pass quadtree)")); + break; + default : + appendItem(group, "Compression", i18n("Unknown")); + }; + + return true; +} + +#include "kfile_tga.moc" diff --git a/kfile-plugins/tga/kfile_tga.desktop b/kfile-plugins/tga/kfile_tga.desktop new file mode 100644 index 00000000..a4578368 --- /dev/null +++ b/kfile-plugins/tga/kfile_tga.desktop @@ -0,0 +1,64 @@ +[Desktop Entry] +Type=Service +Name=Truevision Targa Info +Name[ar]=معلومات Truevision Targa +Name[br]=Gorretaol Truevision Targa +Name[ca]=Informació de Targa Truevision +Name[cs]=Truevision Targa info +Name[cy]=Gwybodaeth Truevision Targa +Name[da]=Truevision Targa-info +Name[de]=Truevision Targa-Info +Name[el]=Πληροφορίες Truevision Targa +Name[eo]=TARGA-informo +Name[es]=Info de Targa visión verdadera +Name[et]=Truevision Targa info +Name[fa]=اطلاعات Truevision Targa +Name[fi]=Truevision Targa -tiedot +Name[fr]=Informations Truevision +Name[gl]=Inf. Truevision Targa +Name[he]=מידע Truevision Targa +Name[hi]=ट्रू-विज़न टाग्रा जानकारी +Name[hr]=Truevision Targa Infomacije +Name[hu]=Truevision/Targa-jellemzők +Name[is]=Truevision Targa upplýsingar +Name[it]=Informazioni Truevision Targa +Name[ja]=TGA (Truevision Targa) 情報 +Name[kk]=Truevision Targa мәліметі +Name[km]=ព័ត៌មាន Truevision Targa +Name[lt]=Truevision Targa informacija +Name[ms]=Maklumat Targa Truevision +Name[nb]=Truevision Targa-info +Name[nds]="Truevision Targa"-Info +Name[ne]=ट्रुभिजन टार्गा सूचना +Name[nl]=Truevision Targa-info +Name[nn]=Truevision Targa-info +Name[nso]=Tshedimoso ya Targa ya pono ya Nnete +Name[pl]=Informacja o pliku Truevision Targa +Name[pt]=Informação do Targa da Truevision +Name[pt_BR]=Informação sobre Truevision Targa +Name[ro]=Informaţii Targa Truevision +Name[ru]=Информация о Truevision Targa +Name[se]=Truevision Targa-dieđut +Name[sl]=Podatki o Truevision Targa +Name[sr]=Truevision Targa информације +Name[sr@Latn]=Truevision Targa informacije +Name[sv]=Information om Truevision Targa +Name[ta]=சரியான பார்வை தார்கா தகவல் +Name[tg]=Иттилоот оиди Truevision Targa +Name[th]=ข้อมูลแฟ้ม Truevision Targa +Name[tr]=Truevision Targa Bilgisi +Name[uk]=Інформація по Truevision Targa +Name[uz]=TGA haqida maʼlumot +Name[uz@cyrillic]=TGA ҳақида маълумот +Name[ven]=Mafhungo a Targa ya mbonalelo ya vhukuma +Name[wa]=Informåcion sol imådje Truevision Targa +Name[xh]=Ulwazi lwe Truevision Targa +Name[zh_CN]=Truevision Targa 信息 +Name[zh_HK]=Truevision Targa 資訊 +Name[zh_TW]=Truevision Targa 資訊 +Name[zu]=Ulwazi lwe-Truevision Targa +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_tga +MimeType=image/x-targa +PreferredGroups=Technical +PreferredItems=Dimensions,BitDepth,ColorMode,Compression diff --git a/kfile-plugins/tga/kfile_tga.h b/kfile-plugins/tga/kfile_tga.h new file mode 100644 index 00000000..cd224fdf --- /dev/null +++ b/kfile-plugins/tga/kfile_tga.h @@ -0,0 +1,37 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk> + * + * 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_TGA_H__ +#define __KFILE_TGA_H__ + +#include <kfilemetainfo.h> + +class QStringList; + +class KTgaPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KTgaPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); +}; + +#endif diff --git a/kfile-plugins/tiff/Makefile.am b/kfile-plugins/tiff/Makefile.am new file mode 100644 index 00000000..e1e74cde --- /dev/null +++ b/kfile-plugins/tiff/Makefile.am @@ -0,0 +1,21 @@ +## Makefile.am for Tiff file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +noinst_HEADERS = kfile_tiff.h + +kde_module_LTLIBRARIES = kfile_tiff.la + +kfile_tiff_la_SOURCES = kfile_tiff.cpp +kfile_tiff_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_tiff_la_LIBADD = $(LIB_KIO) $(LIBTIFF) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_tiff.pot + +services_DATA = kfile_tiff.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/tiff/configure.in.in b/kfile-plugins/tiff/configure.in.in new file mode 100644 index 00000000..e1a9730a --- /dev/null +++ b/kfile-plugins/tiff/configure.in.in @@ -0,0 +1,3 @@ +# Compile the tiff meta info plugin only if libtiff was detected +AC_FIND_TIFF +AM_CONDITIONAL(include_TIFF, test -n "$LIBTIFF") diff --git a/kfile-plugins/tiff/kfile_tiff.cpp b/kfile-plugins/tiff/kfile_tiff.cpp new file mode 100644 index 00000000..1e844d0d --- /dev/null +++ b/kfile-plugins/tiff/kfile_tiff.cpp @@ -0,0 +1,299 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Nadeem Hasan <nhasan@kde.org> + * + * 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 "kfile_tiff.h" + +#include <kgenericfactory.h> +#include <kdebug.h> + +#include <qstringlist.h> +#include <qfile.h> +#include <qdatetime.h> +#include <qregexp.h> + +#include <tiff.h> +#include <tiffio.h> + +typedef KGenericFactory<KTiffPlugin> TiffFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_tiff, TiffFactory("kfile_tiff")) + +KTiffPlugin::KTiffPlugin(QObject *parent, const char *name, + const QStringList &args) : KFilePlugin(parent, name, args) +{ + kdDebug(7034) << "TIFF file meta info plugin" << endl; + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/tiff" ); + + KFileMimeTypeInfo::GroupInfo* group = + addGroupInfo(info, "General", i18n("General")); + + KFileMimeTypeInfo::ItemInfo* item; + item = addItemInfo(group, "Description", i18n("Description"), + QVariant::String); + setHint(item, KFileMimeTypeInfo::Description); + item = addItemInfo(group, "Copyright", i18n("Copyright"), + QVariant::String); + item = addItemInfo(group, "ColorMode", i18n("Color Mode"), + QVariant::String); + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), + QVariant::Size); + setHint(item, KFileMimeTypeInfo::Size); + setUnit(item, KFileMimeTypeInfo::Pixels); + item = addItemInfo(group, "Resolution", i18n("Resolution"), + QVariant::Size); + setUnit(item, KFileMimeTypeInfo::DotsPerInch); + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), + QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); + item = addItemInfo(group, "Compression", i18n("Compression"), + QVariant::String); + item = addItemInfo(group, "Software", i18n("Software"), + QVariant::String); + item = addItemInfo(group, "DateTime", i18n("Date/Time"), + QVariant::DateTime); + item = addItemInfo(group, "Artist", i18n("Artist"), + QVariant::String); + setHint(item, KFileMimeTypeInfo::Author); + item = addItemInfo(group, "FaxPages", i18n("Fax Pages"), + QVariant::Int); + + group = addGroupInfo(info, "Scanner", i18n("Scanner")); + + item = addItemInfo(group, "Make", i18n("Make"), QVariant::String); + item = addItemInfo(group, "Model", i18n("Model"), QVariant::String); + + m_colorMode.setAutoDelete(true); + m_imageCompression.setAutoDelete(true); + + m_colorMode.insert(PHOTOMETRIC_MINISWHITE, + new QString(I18N_NOOP("Monochrome"))); + m_colorMode.insert(PHOTOMETRIC_MINISBLACK, + new QString(I18N_NOOP("Monochrome"))); + m_colorMode.insert(PHOTOMETRIC_RGB, + new QString(I18N_NOOP("RGB"))); + m_colorMode.insert(PHOTOMETRIC_PALETTE, + new QString(I18N_NOOP("Palette color"))); + m_colorMode.insert(PHOTOMETRIC_MASK, + new QString(I18N_NOOP("Transparency mask"))); + m_colorMode.insert(PHOTOMETRIC_SEPARATED, + new QString(I18N_NOOP("Color separations"))); + m_colorMode.insert(PHOTOMETRIC_YCBCR, + new QString(I18N_NOOP("YCbCr"))); + m_colorMode.insert(PHOTOMETRIC_CIELAB, + new QString(I18N_NOOP("CIE Lab"))); +#ifdef PHOTOMETRIC_ITULAB + m_colorMode.insert(PHOTOMETRIC_ITULAB, + new QString(I18N_NOOP("ITU Lab"))); +#endif + m_colorMode.insert(PHOTOMETRIC_LOGL, + new QString(I18N_NOOP("LOGL"))); + m_colorMode.insert(PHOTOMETRIC_LOGLUV, + new QString(I18N_NOOP("LOGLUV"))); + + m_imageCompression.insert(COMPRESSION_NONE, + new QString(I18N_NOOP("None"))); + m_imageCompression.insert(COMPRESSION_CCITTRLE, + new QString(I18N_NOOP("RLE"))); + m_imageCompression.insert(COMPRESSION_CCITTFAX3, + new QString(I18N_NOOP("G3 Fax"))); + m_imageCompression.insert(COMPRESSION_CCITTFAX4, + new QString(I18N_NOOP("G4 Fax"))); + m_imageCompression.insert(COMPRESSION_LZW, + new QString(I18N_NOOP("LZW"))); + m_imageCompression.insert(COMPRESSION_OJPEG, + new QString(I18N_NOOP("JPEG"))); + m_imageCompression.insert(COMPRESSION_JPEG, + new QString(I18N_NOOP("JPEG DCT"))); +#ifdef COMPRESSION_ADOBE_DEFLATE + m_imageCompression.insert(COMPRESSION_ADOBE_DEFLATE, + new QString(I18N_NOOP("Adobe Deflate"))); +#endif + m_imageCompression.insert(COMPRESSION_NEXT, + new QString(I18N_NOOP("NeXT 2-bit RLE"))); + m_imageCompression.insert(COMPRESSION_CCITTRLEW, + new QString(I18N_NOOP("RLE Word"))); + m_imageCompression.insert(COMPRESSION_PACKBITS, + new QString(I18N_NOOP("Packbits"))); + m_imageCompression.insert(COMPRESSION_THUNDERSCAN, + new QString(I18N_NOOP("Thunderscan RLE"))); + m_imageCompression.insert(COMPRESSION_IT8CTPAD, + new QString(I18N_NOOP("IT8 CT w/padding"))); + m_imageCompression.insert(COMPRESSION_IT8LW, + new QString(I18N_NOOP("IT8 linework RLE"))); + m_imageCompression.insert(COMPRESSION_IT8MP, + new QString(I18N_NOOP("IT8 monochrome"))); + m_imageCompression.insert(COMPRESSION_IT8BL, + new QString(I18N_NOOP("IT8 binary lineart"))); + m_imageCompression.insert(COMPRESSION_PIXARFILM, + new QString(I18N_NOOP("Pixar 10-bit LZW"))); + m_imageCompression.insert(COMPRESSION_PIXARLOG, + new QString(I18N_NOOP("Pixar 11-bit ZIP"))); + m_imageCompression.insert(COMPRESSION_DEFLATE, + new QString(I18N_NOOP("Pixar deflate"))); + m_imageCompression.insert(COMPRESSION_DCS, + new QString(I18N_NOOP("Kodak DCS"))); + m_imageCompression.insert(COMPRESSION_JBIG, + new QString(I18N_NOOP("ISO JBIG"))); + m_imageCompression.insert(COMPRESSION_SGILOG, + new QString(I18N_NOOP("SGI log luminance RLE"))); + m_imageCompression.insert(COMPRESSION_SGILOG24, + new QString(I18N_NOOP("SGI log 24-bit packed"))); +} + +QDateTime KTiffPlugin::tiffDate(const QString& s) const +{ + QDateTime dt; + QRegExp rxDate("^([0-9]{4}):([0-9]{2}):([0-9]{2})\\s" + "([0-9]{2}):([0-9]{2}):([0-9]{2})$"); + + if (rxDate.search(s) != -1) + { + int year = rxDate.cap(1).toInt(); + int month = rxDate.cap(2).toInt(); + int day = rxDate.cap(3).toInt(); + int hour = rxDate.cap(4).toInt(); + int min = rxDate.cap(5).toInt(); + int sec = rxDate.cap(6).toInt(); + + QDate d = QDate(year, month, day); + QTime t = QTime(hour, min, sec); + + if (d.isValid() && t.isValid()) + { + dt.setDate(d); + dt.setTime(t); + } + } + + return dt; +} + +bool KTiffPlugin::readInfo(KFileMetaInfo& info, uint) +{ + TIFF *tiff = TIFFOpen(QFile::encodeName(info.path()), "r"); + if (!tiff) + return false; + + uint32 imageLength=0, imageWidth=0; + uint16 bitsPerSample=0, imageCompression=0, colorMode=0, samplesPerPixel=0, + imageAlpha=0, imageResUnit=0, dummy=0, faxPages=0; + float imageXResolution=0, imageYResolution=0; + char *description=0, *copyright=0, *software=0, *datetime=0, *artist=0, + *scannerMake=0, *scannerModel=0; + + TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &imageLength); + TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &imageWidth); + TIFFGetFieldDefaulted(tiff, TIFFTAG_BITSPERSAMPLE, &bitsPerSample); + TIFFGetFieldDefaulted(tiff, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel); + TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &colorMode); + TIFFGetFieldDefaulted(tiff, TIFFTAG_COMPRESSION, &imageCompression); + TIFFGetField(tiff, TIFFTAG_MATTEING, &imageAlpha); + TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &imageXResolution); + TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &imageYResolution); + TIFFGetFieldDefaulted(tiff, TIFFTAG_RESOLUTIONUNIT, &imageResUnit); + TIFFGetField(tiff, TIFFTAG_IMAGEDESCRIPTION, &description); + TIFFGetField(tiff, TIFFTAG_SOFTWARE, &software); + TIFFGetField(tiff, TIFFTAG_COPYRIGHT, ©right); + TIFFGetField(tiff, TIFFTAG_DATETIME, &datetime); + TIFFGetField(tiff, TIFFTAG_ARTIST, &artist); + TIFFGetField(tiff, TIFFTAG_PAGENUMBER, &dummy, &faxPages); + TIFFGetField(tiff, TIFFTAG_MAKE, &scannerMake); + TIFFGetField(tiff, TIFFTAG_MODEL, &scannerModel); + + kdDebug(7034) << "Description: " << description << endl; + kdDebug(7034) << "Width: " << imageWidth << endl; + kdDebug(7034) << "Height: " << imageLength << endl; + kdDebug(7034) << "BitDepth: " << bitsPerSample << endl; + kdDebug(7034) << "ColorMode: " << colorMode << endl; + kdDebug(7034) << "Compression: " << imageCompression << endl; + kdDebug(7034) << "SamplesPerPixel: " << samplesPerPixel << endl; + kdDebug(7034) << "ImageAlpha: " << imageAlpha << endl; + kdDebug(7034) << "XResolution: " << imageXResolution << endl; + kdDebug(7034) << "YResolution: " << imageYResolution << endl; + kdDebug(7034) << "ResolutionUnit: " << imageResUnit << endl; + kdDebug(7034) << "FaxPages: " << faxPages << endl; + kdDebug(7034) << "DateTime: " << datetime << endl; + kdDebug(7034) << "Copyright: " << copyright << endl; + kdDebug(7034) << "Software: " << software << endl; + kdDebug(7034) << "Artist: " << artist << endl; + kdDebug(7034) << "Make: " << scannerMake << endl; + kdDebug(7034) << "Model: " << scannerModel << endl; + + if (imageResUnit == RESUNIT_CENTIMETER) + { + imageXResolution *= 2.54; + imageYResolution *= 2.54; + } + else if (imageResUnit == RESUNIT_NONE) + { + imageXResolution = 0; + imageYResolution = 0; + } + + int imageBpp = bitsPerSample*samplesPerPixel; + if (imageAlpha && colorMode==PHOTOMETRIC_RGB) + m_colorMode.replace(PHOTOMETRIC_RGB, new QString(I18N_NOOP("RGBA"))); + + KFileMetaInfoGroup group = appendGroup(info, "General"); + if (description) + appendItem(group, "Description", QString(description)); + appendItem(group, "Dimensions", QSize(imageWidth, imageLength)); + appendItem(group, "BitDepth", imageBpp); + if (imageXResolution>0 && imageYResolution>0) + appendItem(group, "Resolution", QSize( + static_cast<int>(imageXResolution), + static_cast<int>(imageYResolution))); + if (m_colorMode[colorMode]) + appendItem(group, "ColorMode", *m_colorMode[colorMode]); + if (m_imageCompression[imageCompression]) + appendItem(group, "Compression", *m_imageCompression[imageCompression]); + if (datetime) + { + QDateTime dt = tiffDate(QString(datetime)); + if (dt.isValid()) + appendItem(group, "DateTime", dt); + } + if (copyright) + appendItem(group, "Copyright", QString(copyright)); + if (software) + appendItem(group, "Software", QString(software)); + if (artist) + appendItem(group, "Artist", QString(artist)); + + if (faxPages>0 && (imageCompression==COMPRESSION_CCITTFAX3 || + imageCompression==COMPRESSION_CCITTFAX4)) + { + appendItem(group, "FaxPages", faxPages); + } + + if (scannerMake || scannerModel) + { + group = appendGroup(info, "Scanner"); + if (scannerMake) + appendItem(group, "Make", QString(scannerMake)); + if (scannerModel) + appendItem(group, "Model", QString(scannerModel)); + } + + TIFFClose(tiff); + + return true; +} + +#include "kfile_tiff.moc" diff --git a/kfile-plugins/tiff/kfile_tiff.desktop b/kfile-plugins/tiff/kfile_tiff.desktop new file mode 100644 index 00000000..c7c7441e --- /dev/null +++ b/kfile-plugins/tiff/kfile_tiff.desktop @@ -0,0 +1,67 @@ +[Desktop Entry] +Type=Service +Name=TIFF File Meta Info +Name[af]=Tiff Lêer Meta Inligting +Name[ar]=معلومات ملف TIFF +Name[br]=Meta-titouroù ar restr TIFF +Name[ca]=Metainformació de fitxer TIFF +Name[cs]=Metainformace obrázku typu TIFF +Name[cy]=Meta-wybodaeth Ffeil TIFF +Name[da]=TIFF Fil-meta-info +Name[de]=TIFF-Metainformation +Name[el]=Μετα-πληροφορίες αρχείου TIFF +Name[eo]=TIFF-informo +Name[es]=Info meta de archivos TIFF +Name[et]=TIFF faili metainfo +Name[eu]=TIFF fitxategi meta info +Name[fa]=فرااطلاعات پروندۀ TIFF +Name[fi]=TIFF-metatiedot +Name[fr]=Méta Informations sur les fichiers TIFF +Name[gl]=Inf. metaficheiro TIFF +Name[he]=מידע TIFF +Name[hi]=TIFF फ़ाइल मेटा जानकारी +Name[hr]=TIFF meta informacije +Name[hu]=TIFF-metajellemzők +Name[is]=TIFF File Meta upplýsingar +Name[it]=Informazioni TIFF +Name[ja]=TIFF ファイルメタ情報 +Name[kk]=TIFF файлдың мета деректері +Name[km]=ព័ត៌មានមេតារបស់ឯកសារ TIFF +Name[lt]=TIFF bylos meta informacija +Name[ms]=TIFF Maklumat Meta Fail TIFF +Name[nb]=TIFF-filmetainfo +Name[nds]=TIFF-Metainfo +Name[ne]=TIFF फाइल मेटा सूचना +Name[nl]=TIFF File Meta-info +Name[nn]=TIFF-filmetainfo +Name[nso]=Tshedimoso ya Meta wa Faele ya TIFF +Name[pl]=Informacja o pliku TIFF +Name[pt]=Meta-Informação do Ficheiro TIFF +Name[pt_BR]=Informação sobre Meta Arquivo TIFF +Name[ro]=Metainformaţii TIFF +Name[ru]=Информация о метафайле TIFF +Name[se]=TIFF-filla metadieđut +Name[sk]=Meta-info o súbore TIFF +Name[sl]=Meta podatki o TIFF +Name[sr]=Мета информације TIFF фајла +Name[sr@Latn]=Meta informacije TIFF fajla +Name[sv]=Metainformation om TIFF-fil +Name[ta]=TIFF மீக்கோப்பு தகவல் +Name[tg]=Иттилоот оиди метафайли TIFF +Name[th]=ข้อมูลเมตาแฟ้ม TIFF +Name[tr]=TIFF Dosya Bilgisi +Name[uk]=Метаінформація про файл TIFF +Name[uz]=TIFF-faylining meta-maʼlumoti +Name[uz@cyrillic]=TIFF-файлининг мета-маълумоти +Name[ven]=Mafhungo a Meta faela ya TIFF +Name[wa]=Informåcion sol imådje TIFF +Name[xh]=Ulwazi lwe TIFF Ifayile Esembindini +Name[zh_CN]=TIFF 文件元信息 +Name[zh_HK]=TIFF 檔案 Meta 資訊 +Name[zh_TW]=TIFF 檔案 Meta 資訊 +Name[zu]=Ulwazi Lwefayela yemeta ye-TIFF +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_tiff +MimeType=image/tiff +PreferredGroups=General,Scanner +PreferredItems=Description,Copyright,Type,Dimensions,Resolution,BitDepth,Compression,Software,DateTime,Artist,FaxPages,Make,Model diff --git a/kfile-plugins/tiff/kfile_tiff.h b/kfile-plugins/tiff/kfile_tiff.h new file mode 100644 index 00000000..8985288d --- /dev/null +++ b/kfile-plugins/tiff/kfile_tiff.h @@ -0,0 +1,42 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Nadeem Hasan <nhasan@kde.org> + * + * 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_TIFF_H_ +#define __KFILE_TIFF_H_ + +#include <kfilemetainfo.h> + +#include <qintdict.h> + +class KTiffPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KTiffPlugin(QObject *parent, const char *name, const QStringList& args); + virtual bool readInfo(KFileMetaInfo& info, uint what); + +private: + QDateTime tiffDate(const QString&) const; + + QIntDict<QString> m_colorMode; + QIntDict<QString> m_imageCompression; +}; + +#endif diff --git a/kfile-plugins/xbm/Makefile.am b/kfile-plugins/xbm/Makefile.am new file mode 100644 index 00000000..1b9d7ff9 --- /dev/null +++ b/kfile-plugins/xbm/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for xbm file meta info plugin + +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_xbm.h + +kde_module_LTLIBRARIES = kfile_xbm.la + +kfile_xbm_la_SOURCES = kfile_xbm.cpp +kfile_xbm_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_xbm_la_LIBADD = $(LIB_KSYCOCA) + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) kfile_xbm.cpp -o $(podir)/kfile_xbm.pot + +services_DATA = kfile_xbm.desktop +servicesdir = $(kde_servicesdir) diff --git a/kfile-plugins/xbm/kfile_xbm.cpp b/kfile-plugins/xbm/kfile_xbm.cpp new file mode 100644 index 00000000..d62471f5 --- /dev/null +++ b/kfile-plugins/xbm/kfile_xbm.cpp @@ -0,0 +1,128 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk> + * + * 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 <config.h> +#include "kfile_xbm.h" + +#include <kprocess.h> +#include <klocale.h> +#include <kgenericfactory.h> +#include <kstringvalidator.h> +#include <kdebug.h> + +#include <qdict.h> +#include <qvalidator.h> +#include <qcstring.h> +#include <qfile.h> +#include <qdatetime.h> + +#if !defined(__osf__) +#include <inttypes.h> +#else +typedef unsigned short uint32_t; +#endif + +typedef KGenericFactory<KXbmPlugin> XbmFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_xbm, XbmFactory( "kfile_xbm" )) + +KXbmPlugin::KXbmPlugin(QObject *parent, const char *name, + const QStringList &args) + + : KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-xbm" ); + + KFileMimeTypeInfo::GroupInfo* group = 0L; + + group = addGroupInfo(info, "Technical", i18n("Technical Details")); + + KFileMimeTypeInfo::ItemInfo* item; + + item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size); + setHint( item, KFileMimeTypeInfo::Size ); + setUnit(item, KFileMimeTypeInfo::Pixels); +} + + +unsigned long KXbmPlugin::xbm_processLine(char * linebuf) +{ + const char * fsig = "#define "; + + // check it starts with #define + if (memcmp(linebuf, fsig, 8)) + return 0; + + // scan for the 2nd space and set up a pointer + uint32_t slen = strlen(linebuf); + bool done = false; + uint32_t spos = 0; + unsigned char spacecount = 0; + do { + + if (linebuf[spos] == 0x00) + return 0; + + if (linebuf[spos] == ' ') + ++spacecount; + + if (spacecount == 2) + done = true; + else + ++spos; + + } while (!done); + + return atoi(linebuf + spos); +} + + +bool KXbmPlugin::readInfo( KFileMetaInfo& info, uint what) +{ + + QFile file(info.path()); + + if (!file.open(IO_ReadOnly)) + { + kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl; + return false; + } + + // we need a buffer for lines + char linebuf[1000]; + + // read the first line + file.readLine(linebuf, sizeof( linebuf )); + uint32_t width = xbm_processLine(linebuf); + + // read the 2nd line + file.readLine(linebuf, sizeof( linebuf )); + uint32_t height = xbm_processLine(linebuf); + + if ((width > 0) && (height > 0)) { + // we have valid looking data + KFileMetaInfoGroup group = appendGroup(info, "Technical"); + appendItem(group, "Dimensions", QSize(width, height)); + return true; + } + + return false; +} + +#include "kfile_xbm.moc" diff --git a/kfile-plugins/xbm/kfile_xbm.desktop b/kfile-plugins/xbm/kfile_xbm.desktop new file mode 100644 index 00000000..c33407ac --- /dev/null +++ b/kfile-plugins/xbm/kfile_xbm.desktop @@ -0,0 +1,65 @@ +[Desktop Entry] +Type=Service +Name=XBM Info +Name[af]=Xbm Inligting +Name[ar]=معلومات XBM +Name[br]=Titouroù XBM +Name[ca]=Informació d'XBM +Name[cs]=XBM info +Name[cy]=Gwybodaeth XBM +Name[da]=XBM-info +Name[de]=XBM-Info +Name[el]=Πληροφορίες XBM +Name[eo]=XBM-informo +Name[es]=Info XBM +Name[et]=XBM info +Name[fa]=اطلاعات XBM +Name[fi]=XBM-tiedot +Name[fr]=Informations sur XBM +Name[gl]=Inf. XBM +Name[he]=מידע XBM +Name[hi]=XBM जानकारी +Name[hr]=XBM Infoformacije +Name[hu]=XBM-jellemzők +Name[is]=XBM upplýsingar +Name[it]=Informazioni XBM +Name[ja]=XBM 情報 +Name[kk]=XBM мәліметі +Name[km]=ព័ត៌មាន XBM +Name[lt]=XBM informacija +Name[ms]=Maklumat XBM +Name[nds]=XBM-Info +Name[ne]=XBM सूचना +Name[nl]=XBM-info +Name[nn]=XBM-info +Name[nso]=Tshedimoso ya XBM +Name[pa]=XBM ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku XBM +Name[pt]=Informação do XBM +Name[pt_BR]=Informação sobre XBM +Name[ro]=Informaţii XBM +Name[ru]=Информация о XBM +Name[se]=XBM-dieđut +Name[sl]=Podatki o XBM +Name[sr]=XBM информације +Name[sr@Latn]=XBM informacije +Name[sv]=XBM-information +Name[ta]=XBM தகவல் +Name[tg]=Иттилоот оиди XBM +Name[th]=ข้อมูลแฟ้ม XBM +Name[tr]=XBM Bilgisi +Name[uk]=Інформація по XBM +Name[uz]=XBM haqida maʼlumot +Name[uz@cyrillic]=XBM ҳақида маълумот +Name[ven]=Mafhungo a XBM +Name[wa]=Informåcion sol imådje XBM +Name[xh]=Ulwazi lwe XBM +Name[zh_CN]=XBM 信息 +Name[zh_HK]=XBM 資訊 +Name[zh_TW]=XBM 資訊 +Name[zu]=Ulwazi lwe-XBM +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_xbm +MimeType=image/x-xbm +PreferredGroups=Technical +PreferredItems=Resolution diff --git a/kfile-plugins/xbm/kfile_xbm.h b/kfile-plugins/xbm/kfile_xbm.h new file mode 100644 index 00000000..8cc571e1 --- /dev/null +++ b/kfile-plugins/xbm/kfile_xbm.h @@ -0,0 +1,42 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk> + * + * 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_XBM_H__ +#define __KFILE_XBM_H__ + +#include <kfilemetainfo.h> + +class QStringList; + +class KXbmPlugin: public KFilePlugin +{ + Q_OBJECT + +public: + KXbmPlugin( QObject *parent, const char *name, const QStringList& args ); + + virtual bool readInfo( KFileMetaInfo& info, uint what); + +private: + + unsigned long xbm_processLine(char * linebuf); + +}; + +#endif diff --git a/kfile-plugins/xpm/Makefile.am b/kfile-plugins/xpm/Makefile.am new file mode 100644 index 00000000..5a1254b1 --- /dev/null +++ b/kfile-plugins/xpm/Makefile.am @@ -0,0 +1,21 @@ +## Makefile.am for xpm file meta info plugin + +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = kfile_xpm.h + +kde_module_LTLIBRARIES = kfile_xpm.la + +kfile_xpm_la_SOURCES = kfile_xpm.cpp +kfile_xpm_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kfile_xpm_la_LIBADD = $(LIB_KIO) +kfile_xpm_la_METASOURCES = kfile_xpm.moc + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +kde_services_DATA = kfile_xpm.desktop + +messages: + $(XGETTEXT) *.cpp -o $(podir)/kfile_xpm.pot diff --git a/kfile-plugins/xpm/kfile_xpm.cpp b/kfile-plugins/xpm/kfile_xpm.cpp new file mode 100644 index 00000000..3fd188b7 --- /dev/null +++ b/kfile-plugins/xpm/kfile_xpm.cpp @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2004 by Martin Koller * + * m.koller@surfeu.at * + * * + * 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; either version 2 of the License, or * + * (at your option) any later version. * + * * + * 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; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include <config.h> +#include <qimage.h> +#include "kfile_xpm.h" + +#include <kgenericfactory.h> + +//-------------------------------------------------------------------------------- + +typedef KGenericFactory<xpmPlugin> xpmFactory; + +K_EXPORT_COMPONENT_FACTORY(kfile_xpm, xpmFactory( "kfile_xpm" )) + +//-------------------------------------------------------------------------------- + +xpmPlugin::xpmPlugin(QObject *parent, const char *name, const QStringList &args) + : KFilePlugin(parent, name, args) +{ + KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-xpm" ); + + // our new group + KFileMimeTypeInfo::GroupInfo* group = 0; + group = addGroupInfo(info, "xpmInfo", i18n("X PixMap File Information")); + + KFileMimeTypeInfo::ItemInfo* item; + + // our new items in the group + item = addItemInfo(group, "Dimension", i18n("Dimension"), QVariant::Size); + setHint(item, KFileMimeTypeInfo::Size); + setUnit(item, KFileMimeTypeInfo::Pixels); + + item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int); + setUnit(item, KFileMimeTypeInfo::BitsPerPixel); +} + +//-------------------------------------------------------------------------------- + +bool xpmPlugin::readInfo(KFileMetaInfo& info, uint /*what*/) +{ + QImage pix; + + if ( ! pix.load(info.path(), "XPM") ) return false; + + KFileMetaInfoGroup group = appendGroup(info, "xpmInfo"); + + appendItem(group, "Dimension", pix.size()); + appendItem(group, "BitDepth", pix.depth()); + + return true; +} + +#include "kfile_xpm.moc" diff --git a/kfile-plugins/xpm/kfile_xpm.desktop b/kfile-plugins/xpm/kfile_xpm.desktop new file mode 100644 index 00000000..612fb82e --- /dev/null +++ b/kfile-plugins/xpm/kfile_xpm.desktop @@ -0,0 +1,53 @@ +[Desktop Entry] +Type=Service +Name=XPM Info +Name[br]=Titouroù XPM +Name[ca]=Informació de XPM +Name[cs]=XPM info +Name[de]=XPM-Info +Name[el]=Πληροφορίες XPM +Name[eo]=XPM-informo +Name[es]=Información XPM +Name[et]=XPM info +Name[fa]=اطلاعات XPM +Name[fi]=XPM-tiedot +Name[fr]=Informations XPM +Name[gl]=Información XPM +Name[he]=מידע XPM +Name[hu]=XPM-jellemzők +Name[is]=XPM upplýsingar +Name[it]=Informazioni XPM +Name[ja]=XPM 情報 +Name[kk]=XPM мәліметі +Name[km]=ព័ត៌មាន XPM +Name[lt]=XPM informacija +Name[ms]=Maklumat XPM +Name[nb]=XPM-info +Name[nds]=XPM-Info +Name[ne]=XPM सूचना +Name[nl]=XPM-info +Name[nn]=XPM-info +Name[pa]=XPM ਜਾਣਕਾਰੀ +Name[pl]=Informacja o pliku XPM +Name[pt]=Informação do XPM +Name[pt_BR]=Informações Sobre XPM +Name[ro]=Informaţii XPM +Name[ru]=Информация о XPM +Name[sl]=Podatki o XPM +Name[sr]=XPM информације +Name[sr@Latn]=XPM informacije +Name[sv]=XPM-information +Name[ta]=XPM தகவல் +Name[th]=ข้อมูลแฟ้ม XPM +Name[tr]=XPM Bilgisi +Name[uk]=Інформація про XPM +Name[uz]=XPM haqida maʼlumot +Name[uz@cyrillic]=XPM ҳақида маълумот +Name[zh_CN]=XPM 信息 +Name[zh_HK]=XPM 資訊 +Name[zh_TW]=XPM 資訊 +ServiceTypes=KFilePlugin +X-KDE-Library=kfile_xpm +MimeType=image/x-xpm +PreferredGroups=xpmInfo +PreferredItems=Dimension diff --git a/kfile-plugins/xpm/kfile_xpm.h b/kfile-plugins/xpm/kfile_xpm.h new file mode 100644 index 00000000..c68ad4eb --- /dev/null +++ b/kfile-plugins/xpm/kfile_xpm.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2004 by Martin Koller * + * m.koller@surfeu.at * + * * + * This plugin provides information about the content of a * + * XPM image file. * + * * + * 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; either version 2 of the License, or * + * (at your option) any later version. * + * * + * 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; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef KFILE_XPM_H +#define KFILE_XPM_H + +/** + * Note: For further information look into <$KDEDIR/include/kfilemetainfo.h> + */ +#include <kfilemetainfo.h> + +class QStringList; + +class xpmPlugin: public KFilePlugin +{ + Q_OBJECT + + public: + xpmPlugin(QObject *parent, const char *name, const QStringList& args); + + virtual bool readInfo(KFileMetaInfo& info, uint what); +}; + +#endif + |