summaryrefslogtreecommitdiff
Side-by-side diff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--noncore/graphics/opie-eye/DESIGN22
-rw-r--r--noncore/graphics/opie-eye/gui/filesystem.cpp52
-rw-r--r--noncore/graphics/opie-eye/gui/filesystem.h34
-rw-r--r--noncore/graphics/opie-eye/gui/iconview.cpp296
-rw-r--r--noncore/graphics/opie-eye/gui/iconview.h59
-rw-r--r--noncore/graphics/opie-eye/gui/mainwindow.cpp114
-rw-r--r--noncore/graphics/opie-eye/gui/mainwindow.h29
-rw-r--r--noncore/graphics/opie-eye/gui/viewmap.cpp9
-rw-r--r--noncore/graphics/opie-eye/iface/dirlister.cpp9
-rw-r--r--noncore/graphics/opie-eye/iface/dirlister.h47
-rw-r--r--noncore/graphics/opie-eye/iface/dirview.cpp9
-rw-r--r--noncore/graphics/opie-eye/iface/dirview.h40
-rw-r--r--noncore/graphics/opie-eye/iface/ifaceinfo.h19
-rw-r--r--noncore/graphics/opie-eye/iface/slaveiface.h47
-rw-r--r--noncore/graphics/opie-eye/impl/dir/dir_dirview.cpp29
-rw-r--r--noncore/graphics/opie-eye/impl/dir/dir_dirview.h24
-rw-r--r--noncore/graphics/opie-eye/impl/dir/dir_ifacceinfo.h21
-rw-r--r--noncore/graphics/opie-eye/impl/dir/dir_ifaceinfo.cpp47
-rw-r--r--noncore/graphics/opie-eye/impl/dir/dir_ifaceinfo.h21
-rw-r--r--noncore/graphics/opie-eye/impl/dir/dir_lister.cpp94
-rw-r--r--noncore/graphics/opie-eye/impl/dir/dir_lister.h34
-rw-r--r--noncore/graphics/opie-eye/lib/imagecache.cpp87
-rw-r--r--noncore/graphics/opie-eye/lib/imagecache.h46
-rw-r--r--noncore/graphics/opie-eye/lib/slavemaster.cpp145
-rw-r--r--noncore/graphics/opie-eye/lib/slavemaster.h43
-rw-r--r--noncore/graphics/opie-eye/lib/viewmap.cpp25
-rw-r--r--noncore/graphics/opie-eye/phunk_view.pro34
-rw-r--r--noncore/graphics/opie-eye/slave/gif_slave.cpp305
-rw-r--r--noncore/graphics/opie-eye/slave/gif_slave.h22
-rw-r--r--noncore/graphics/opie-eye/slave/jpeg_slave.cpp1426
-rw-r--r--noncore/graphics/opie-eye/slave/jpeg_slave.h19
-rw-r--r--noncore/graphics/opie-eye/slave/main.cpp59
-rw-r--r--noncore/graphics/opie-eye/slave/png_slave.cpp210
-rw-r--r--noncore/graphics/opie-eye/slave/png_slave.h21
-rw-r--r--noncore/graphics/opie-eye/slave/slave.pro18
-rw-r--r--noncore/graphics/opie-eye/slave/slaveiface.cpp26
-rw-r--r--noncore/graphics/opie-eye/slave/slaveiface.h53
-rw-r--r--noncore/graphics/opie-eye/slave/slavereciever.cpp214
-rw-r--r--noncore/graphics/opie-eye/slave/slavereciever.h58
-rw-r--r--noncore/graphics/opie-eye/slave/thumbnailtool.cpp61
-rw-r--r--noncore/graphics/opie-eye/slave/thumbnailtool.h19
41 files changed, 3947 insertions, 0 deletions
diff --git a/noncore/graphics/opie-eye/DESIGN b/noncore/graphics/opie-eye/DESIGN
new file mode 100644
index 0000000..b3943df
--- a/dev/null
+++ b/noncore/graphics/opie-eye/DESIGN
@@ -0,0 +1,22 @@
+The Design of the Eye Caramba Opie Image Viewer.
+
+It consists out of several Parts:
+
+1.) A interface for Getting Information, Files and Requesting Pixmap and the Full Image
+2.) A ImageCache which uses the current Interface to request the Pixmap in the given side
+ (the gui will listen to the slot and insert the image )
+3.) A small library which gives the Image Info and Pixmap. Internally it'll have a forked slave
+ to do the actual work. It'll also write thumbnails.
+4.) The Interface parts are designed for stuff like FileSystem View or Digi Cam support which would
+ read thumbnail from different locations
+
+
+
+TODO:
+ - Special QIconListViewItem painting routines to include BEAM,Rename,Delete,Rotate buttons
+ - Create SlideShows
+ -Add from View. Will ask to add to a slide show
+ -And special slideshow widget for the order
+ -Save in Config within AppDir of eyecaramba
+
+
diff --git a/noncore/graphics/opie-eye/gui/filesystem.cpp b/noncore/graphics/opie-eye/gui/filesystem.cpp
new file mode 100644
index 0000000..91bcf67
--- a/dev/null
+++ b/noncore/graphics/opie-eye/gui/filesystem.cpp
@@ -0,0 +1,52 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ * No WArranty...
+ */
+
+#include <qpopupmenu.h>
+#include <qtoolbar.h>
+
+#include <qpe/resource.h>
+#include <qpe/storage.h>
+
+
+#include "filesystem.h"
+
+PFileSystem::PFileSystem( QToolBar* bar)
+ : QToolButton( bar )
+{
+ setIconSet( Resource::loadIconSet( "cardmon/pcmcia" ) );
+
+ m_pop = new QPopupMenu( this );
+ connect( m_pop, SIGNAL( activated( int ) ),
+ this, SLOT(slotSelectDir( int ) ) );
+
+ m_storage = new StorageInfo();
+ connect(m_storage, SIGNAL(disksChanged() ),
+ this, SLOT( changed() ) );
+ changed();
+
+ setPopup( m_pop );
+}
+
+PFileSystem::~PFileSystem() {
+ delete m_storage;
+}
+
+
+void PFileSystem::changed() {
+ m_pop->clear();
+ m_dev.clear();
+ const QList<FileSystem> &fs = m_storage->fileSystems();
+ QListIterator<FileSystem> it(fs );
+ for ( ; it.current(); ++it ) {
+ const QString disk = (*it)->name();
+ const QString path = (*it)->path();
+ m_dev.insert( disk, path );
+ m_pop->insertItem( disk );
+ }
+}
+
+void PFileSystem::slotSelectDir( int id ) {
+ emit changeDir( m_dev[m_pop->text(id )] );
+}
diff --git a/noncore/graphics/opie-eye/gui/filesystem.h b/noncore/graphics/opie-eye/gui/filesystem.h
new file mode 100644
index 0000000..a29ad87
--- a/dev/null
+++ b/noncore/graphics/opie-eye/gui/filesystem.h
@@ -0,0 +1,34 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ * No WArranty...
+ */
+
+#ifndef PHUNK_FILE_SYSTEM_H
+#define PHUNK_FILE_SYSTEM_H
+
+#include <qtoolbutton.h>
+#include <qmap.h>
+
+class QPopupMenu;
+class StorageInfo;
+class PFileSystem : public QToolButton {
+ Q_OBJECT
+public:
+ PFileSystem( QToolBar* );
+ ~PFileSystem();
+
+signals:
+ void changeDir( const QString& );
+
+private slots:
+ void slotSelectDir( int );
+ void changed();
+
+private:
+ QPopupMenu* m_pop;
+ StorageInfo *m_storage;
+ QMap<QString, QString> m_dev;
+};
+
+
+#endif
diff --git a/noncore/graphics/opie-eye/gui/iconview.cpp b/noncore/graphics/opie-eye/gui/iconview.cpp
new file mode 100644
index 0000000..0b80012
--- a/dev/null
+++ b/noncore/graphics/opie-eye/gui/iconview.cpp
@@ -0,0 +1,296 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ * No WArranty...
+ */
+
+#include "iconview.h"
+
+#include <lib/imagecache.h>
+
+#include <iface/dirview.h>
+#include <iface/dirlister.h>
+
+#include <qpe/config.h>
+#include <qpe/resource.h>
+#include <qpe/qpemessagebox.h>
+#include <qpe/ir.h>
+#include <qpe/qcopenvelope_qws.h>
+
+#include <qiconview.h>
+#include <qlabel.h>
+#include <qhbox.h>
+#include <qcombobox.h>
+#include <qdir.h>
+#include <qapplication.h>
+#include <qmainwindow.h>
+#include <qtimer.h>
+#include <qstyle.h>
+
+
+
+namespace {
+ QPixmap* _dirPix = 0;
+ QPixmap* _unkPix = 0;
+ class IconViewItem : public QIconViewItem {
+ public:
+ IconViewItem( QIconView*, const QString& path, const QString& name, bool isDir = false);
+ QPixmap* pixmap()const;
+ QString path()const { return m_path; }
+ bool isDir()const { return m_isDir; }
+ void setText( const QString& );
+ private:
+ mutable QPixmap* m_pix;
+ QString m_path;
+ bool m_isDir : 1;
+ bool m_noInfo :1;
+ };
+
+
+/*
+ * If we request an Image or String
+ * we add it to the map
+ */
+ QMap<QString, IconViewItem*> g_stringInf;
+ QMap<QString, IconViewItem*> g_stringPix;
+
+ IconViewItem::IconViewItem( QIconView* view,const QString& path,
+ const QString& name, bool isDir )
+ : QIconViewItem( view ), m_path( path ), m_isDir( isDir ),
+ m_noInfo( false )
+ {
+ QIconViewItem::setText( name );
+ if ( isDir && !_dirPix )
+ _dirPix = new QPixmap( Resource::loadPixmap("advancedfm/FileBrowser"));
+ else if ( !isDir && !_unkPix )
+ _unkPix = new QPixmap( Resource::loadPixmap( "UnknownDocument" ) );
+ }
+ inline QPixmap* IconViewItem::pixmap()const {
+ if ( m_isDir )
+ return _dirPix;
+ else{
+ if (!m_noInfo && !g_stringInf.contains( m_path ) ) {
+ currentView()->dirLister()->imageInfo( m_path );
+ g_stringInf.insert( m_path, const_cast<IconViewItem*>(this));
+ }
+
+ m_pix = PPixmapCache::self()->cachedImage( m_path, 64, 64 );
+ if ( !m_pix && !g_stringPix.contains( m_path )) {
+ currentView()->dirLister()->thumbNail( m_path, 64, 64 );
+ g_stringPix.insert( m_path, const_cast<IconViewItem*>(this));
+ }
+ return m_pix ? m_pix : _unkPix;
+ }
+ }
+ inline void IconViewItem::setText( const QString& str ) {
+ QString text = QIconViewItem::text()+"\n"+str;
+ m_noInfo = true;
+ QIconViewItem::setText( text );
+ }
+}
+
+
+PIconView::PIconView( QWidget* wid, Config* cfg )
+ : QVBox( wid ), m_cfg( cfg )
+{
+ {
+ QCopEnvelope( "QPE/Application/opie-eye_slave", "foo()" );
+ }
+ m_path = QDir::homeDirPath();
+
+ QHBox *hbox = new QHBox( this );
+ QLabel* lbl = new QLabel( hbox );
+ lbl->setText( tr("View as" ) );
+
+ m_views = new QComboBox( hbox, "View As" );
+ connect( m_views, SIGNAL(activated(int)),
+ this, SLOT(slotViewChanged(int)) );
+
+ m_view= new QIconView( this );
+ connect(m_view, SIGNAL(clicked(QIconViewItem*) ),
+ this, SLOT(slotClicked(QIconViewItem*)) );
+
+ m_view->setArrangement( QIconView::LeftToRight );
+ m_view->setItemTextPos( QIconView::Right );
+
+
+ int dw = QApplication::desktop()->width();
+ int viewerWidth = dw-style().scrollBarExtent().width();
+ m_view->setGridX( viewerWidth-2*m_view->spacing() );
+ m_view->setGridY( fontMetrics().height()*2+40 );
+ loadViews();
+ slotViewChanged( m_views->currentItem() );
+}
+
+PIconView::~PIconView() {
+}
+
+void PIconView::slotDirUp() {
+ QDir dir( m_path );
+ dir.cdUp();
+ slotChangeDir( dir.absPath() );
+
+}
+
+void PIconView::slotChangeDir(const QString& path) {
+ if ( !currentView() )
+ return;
+
+ PDirLister *lister = currentView()->dirLister();
+ if (!lister )
+ return;
+
+ lister->setStartPath( path );
+ m_path = lister->currentPath();
+
+ m_view->clear();
+ addFolders( lister->folders() );
+ addFiles( lister->files() );
+
+ // looks ugly
+ static_cast<QMainWindow*>(parent())->setCaption( QObject::tr("%1 - O View", "Name of the dir").arg( m_path ) );
+}
+
+QString PIconView::currentFileName(bool &isDir)const {
+ isDir = false;
+ QIconViewItem* _it = m_view->currentItem();
+ if ( !_it )
+ return QString::null;
+
+ IconViewItem* it = static_cast<IconViewItem*>( _it );
+ isDir = it->isDir();
+ return it->path();
+}
+
+void PIconView::slotTrash() {
+ bool isDir;
+ QString pa = currentFileName( isDir );
+ if ( isDir && pa.isEmpty() )
+ return;
+
+ if (!QPEMessageBox::confirmDelete( this,
+ tr("Delete Image" ),
+ tr("the Image %1" ).arg(pa)))
+ return
+
+
+ currentView()->dirLister()->deleteImage( pa );
+ delete m_view->currentItem();
+}
+void PIconView::loadViews() {
+ ViewMap::Iterator it;
+ ViewMap* map = viewMap();
+ for ( it = map->begin(); it != map->end(); ++it )
+ m_views->insertItem( QObject::tr(it.key() ) );
+}
+
+void PIconView::resetView() {
+ slotViewChanged(m_views->currentItem());
+}
+
+void PIconView::slotViewChanged( int i) {
+ if (!m_views->count() ) {
+ setCurrentView( 0l);
+ return;
+ }
+
+ PDirView* cur = currentView();
+ delete cur;
+ QString str = m_views->text(i);
+ cur = (*(*viewMap())[str])(*m_cfg);
+ setCurrentView( cur );
+
+ /* connect to the signals of the lister */
+ PDirLister* lis = cur->dirLister();
+ connect(lis, SIGNAL(sig_thumbInfo(const QString&, const QString& )),
+ this, SLOT( slotThumbInfo(const QString&, const QString&)));
+ connect(lis, SIGNAL( sig_thumbNail(const QString&, const QPixmap&)),
+ this, SLOT(slotThumbNail(const QString&, const QPixmap&)));
+ connect(lis, SIGNAL(sig_start()),
+ this, SLOT(slotStart()));
+ connect(lis, SIGNAL(sig_end()) ,
+ this, SLOT(slotEnd()) );
+
+
+ /* reload now */
+ QTimer::singleShot( 0, this, SLOT(slotReloadDir()));
+}
+
+
+void PIconView::slotReloadDir() {
+ slotChangeDir( m_path );
+}
+
+
+void PIconView::addFolders( const QStringList& lst) {
+ QStringList::ConstIterator it;
+
+ for(it=lst.begin(); it != lst.end(); ++it ) {
+ (void)new IconViewItem( m_view, m_path+"/"+(*it), (*it), true );
+ }
+
+}
+
+void PIconView::addFiles( const QStringList& lst) {
+ QStringList::ConstIterator it;
+ for (it=lst.begin(); it!= lst.end(); ++it )
+ (void)new IconViewItem( m_view, m_path+"/"+(*it), (*it) );
+
+}
+
+void PIconView::slotClicked(QIconViewItem* _it) {
+ if(!_it )
+ return;
+
+ IconViewItem* it = static_cast<IconViewItem*>(_it);
+ if( it->isDir() )
+ slotChangeDir( it->path() );
+ else // view image
+ ;
+}
+
+void PIconView::slotThumbInfo( const QString& _path, const QString& str ) {
+ if ( g_stringInf.contains( _path ) ) {
+ IconViewItem* item = g_stringInf[_path];
+ item->setText( str );
+ item->repaint();
+ g_stringInf.remove( _path );
+ }
+}
+void PIconView::slotThumbNail(const QString& _path, const QPixmap &pix) {
+ if ( g_stringPix.contains( _path ) ) {
+ IconViewItem* item = g_stringPix[_path];
+ PPixmapCache::self()->insertImage( _path, pix, 64, 64 );
+ item->repaint();
+ g_stringPix.remove( _path );
+ }
+}
+
+
+void PIconView::slotRename() {
+
+}
+
+void PIconView::slotBeam() {
+ bool isDir;
+ QString pa = currentFileName( isDir );
+ if ( isDir && pa.isEmpty() )
+ return;
+
+ Ir* ir = new Ir( this );
+ connect( ir, SIGNAL(done(Ir*)),
+ this, SLOT(slotBeamDone(Ir*)));
+ ir->send(pa, tr( "Image" ) );
+
+}
+
+void PIconView::slotBeamDone( Ir* ir) {
+ delete ir;
+}
+
+void PIconView::slotStart() {
+ m_view->setUpdatesEnabled( false );
+}
+
+void PIconView::slotEnd() {
+ m_view->setUpdatesEnabled( true );
+}
diff --git a/noncore/graphics/opie-eye/gui/iconview.h b/noncore/graphics/opie-eye/gui/iconview.h
new file mode 100644
index 0000000..439833a
--- a/dev/null
+++ b/noncore/graphics/opie-eye/gui/iconview.h
@@ -0,0 +1,59 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ * No WArranty...
+ */
+
+#ifndef PHUNK_ICON_VIEW_H
+#define PHUNK_ICON_VIEW_H
+
+#include <qvbox.h>
+
+#include <qpe/config.h>
+
+class QIconView;
+class QIconViewItem;
+class QComboBox;
+class PIconViewItem;
+class PDirLister;
+class Ir;
+class PIconView : public QVBox {
+ Q_OBJECT
+ friend class PIconViewItem;
+public:
+ PIconView( QWidget* wid, Config *cfg );
+ ~PIconView();
+ void resetView();
+
+private:
+ QString currentFileName(bool &isDir)const;
+ void loadViews();
+
+private slots:
+ void slotDirUp();
+ void slotChangeDir(const QString&);
+ void slotTrash();
+ void slotViewChanged( int );
+ void slotReloadDir();
+ void slotRename();
+ void slotBeam();
+ void slotBeamDone( Ir* );
+
+ void slotStart();
+ void slotEnd();
+
+/* for performance reasons make it inline in the future */
+ void addFolders( const QStringList& );
+ void addFiles( const QStringList& );
+ void slotClicked(QIconViewItem* );
+
+/**/
+ void slotThumbInfo(const QString&, const QString&);
+ void slotThumbNail(const QString&, const QPixmap&);
+private:
+ Config *m_cfg;
+ QComboBox* m_views;
+ QIconView* m_view;
+ QString m_path;
+};
+
+#endif
diff --git a/noncore/graphics/opie-eye/gui/mainwindow.cpp b/noncore/graphics/opie-eye/gui/mainwindow.cpp
new file mode 100644
index 0000000..0a2fcab
--- a/dev/null
+++ b/noncore/graphics/opie-eye/gui/mainwindow.cpp
@@ -0,0 +1,114 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ * No WArranty...
+ */
+
+#include <qtoolbar.h>
+#include <qtoolbutton.h>
+#include <qlayout.h>
+#include <qdialog.h>
+#include <qmap.h>
+
+#include <qpe/resource.h>
+#include <qpe/config.h>
+#include <qpe/ir.h>
+
+#include <opie/oapplicationfactory.h>
+#include <opie/otabwidget.h>
+
+#include <iface/ifaceinfo.h>
+#include <iface/dirview.h>
+
+#include "iconview.h"
+#include "filesystem.h"
+
+#include "mainwindow.h"
+
+OPIE_EXPORT_APP( OApplicationFactory<PMainWindow> )
+
+PMainWindow::PMainWindow(QWidget* wid, const char* name, WFlags style)
+ : QMainWindow( wid, name, style ), m_cfg("phunkview")
+{
+ setCaption( QObject::tr("Opie Eye Caramba" ) );
+ m_cfg.setGroup("Zecke_view" );
+ /*
+ * Initialize ToolBar and IconView
+ * And Connect Them
+ */
+ QToolBar *bar = new QToolBar( this );
+ bar->setHorizontalStretchable( true );
+ setToolBarsMovable( false );
+
+ m_view = new PIconView( this, &m_cfg );
+ setCentralWidget( m_view );
+
+ QToolButton *btn = new QToolButton( bar );
+ btn->setIconSet( Resource::loadIconSet( "up" ) );
+ connect( btn, SIGNAL(clicked()),
+ m_view, SLOT(slotDirUp()) );
+
+ btn = new PFileSystem( bar );
+ connect( btn, SIGNAL( changeDir( const QString& ) ),
+ m_view, SLOT(slotChangeDir( const QString& ) ) );
+
+ btn = new QToolButton( bar );
+ btn->setIconSet( Resource::loadIconSet( "edit" ) );
+ connect( btn, SIGNAL(clicked()),
+ m_view, SLOT(slotRename()) );
+
+ if ( Ir::supported() ) {
+ btn = new QToolButton( bar );
+ btn->setIconSet( Resource::loadIconSet( "beam" ) );
+ connect( btn, SIGNAL(clicked()),
+ m_view, SLOT(slotBeam()) );
+ }
+
+ btn = new QToolButton( bar );
+ btn->setIconSet( Resource::loadIconSet( "trash" ) );
+ connect( btn, SIGNAL(clicked() ),
+ m_view, SLOT(slotTrash() ) );
+
+ btn = new QToolButton( bar );
+ btn->setIconSet( Resource::loadIconSet( "SettingsIcon" ) );
+ connect( btn, SIGNAL(clicked() ),
+ this, SLOT(slotConfig() ) );
+
+}
+
+PMainWindow::~PMainWindow() {
+}
+
+
+void PMainWindow::slotConfig() {
+ QDialog dlg(this, 0, true);
+ dlg.setCaption( tr("Phunk View - Config" ) );
+
+ QHBoxLayout *lay = new QHBoxLayout(&dlg);
+ OTabWidget *wid = new OTabWidget(&dlg );
+ lay->addWidget( wid );
+ ViewMap *vM = viewMap();
+ ViewMap::Iterator _it = vM->begin();
+ QMap<PDirView*, QWidget*> lst;
+
+ for( ; _it != vM->end(); ++_it ) {
+ PDirView *view = (_it.data())(m_cfg);
+ PInterfaceInfo *inf = view->interfaceInfo();
+ QWidget *_wid = inf->configWidget( m_cfg );
+ _wid->reparent(wid, QPoint() );
+ lst.insert( view, _wid );
+ wid->addTab( _wid, QString::null, inf->name() );
+ }
+
+ dlg.showMaximized();
+ bool act = ( dlg.exec() == QDialog::Accepted );
+
+ QMap<PDirView*, QWidget*>::Iterator it;
+ for ( it = lst.begin(); it != lst.end(); ++it ) {
+ if ( act )
+ it.key()->interfaceInfo()->writeConfig(it.data(), m_cfg);
+ delete it.key();
+ }
+
+ if ( act )
+ m_view->resetView();
+}
diff --git a/noncore/graphics/opie-eye/gui/mainwindow.h b/noncore/graphics/opie-eye/gui/mainwindow.h
new file mode 100644
index 0000000..408fe32
--- a/dev/null
+++ b/noncore/graphics/opie-eye/gui/mainwindow.h
@@ -0,0 +1,29 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ * No WArranty...
+ */
+
+#ifndef PHUNK_MAIN_WINDOW_H
+#define PHUNK_MAIN_WINDOW_H
+
+#include <qmainwindow.h>
+
+#include <qpe/config.h>
+
+class PIconView;
+class PMainWindow : public QMainWindow {
+ Q_OBJECT
+public:
+ static QString appName() { return QString::fromLatin1("opie-eye" ); }
+ PMainWindow(QWidget*, const char*, WFlags );
+ ~PMainWindow();
+
+private:
+ Config m_cfg;
+ PIconView* m_view;
+
+private slots:
+ void slotConfig();
+};
+
+#endif
diff --git a/noncore/graphics/opie-eye/gui/viewmap.cpp b/noncore/graphics/opie-eye/gui/viewmap.cpp
new file mode 100644
index 0000000..2dffb38
--- a/dev/null
+++ b/noncore/graphics/opie-eye/gui/viewmap.cpp
@@ -0,0 +1,9 @@
+#include <iface/dirview.h>
+
+namespace {
+ ViewMap m_view;
+}
+
+ViewMap* viewMap() {
+ return m_view;
+}
diff --git a/noncore/graphics/opie-eye/iface/dirlister.cpp b/noncore/graphics/opie-eye/iface/dirlister.cpp
new file mode 100644
index 0000000..7cf4361
--- a/dev/null
+++ b/noncore/graphics/opie-eye/iface/dirlister.cpp
@@ -0,0 +1,9 @@
+#include "dirlister.h"
+
+
+PDirLister::PDirLister( const char* name )
+ : QObject( 0, name )
+{}
+
+PDirLister::~PDirLister()
+{}
diff --git a/noncore/graphics/opie-eye/iface/dirlister.h b/noncore/graphics/opie-eye/iface/dirlister.h
new file mode 100644
index 0000000..fcc55ec
--- a/dev/null
+++ b/noncore/graphics/opie-eye/iface/dirlister.h
@@ -0,0 +1,47 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ * No WArranty...
+ */
+
+#ifndef PHUNK_DIR_LISTER_H
+#define PHUNK_DIR_LISTER_H
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+
+class PDirLister : public QObject {
+ Q_OBJECT
+public:
+ enum Factor { Width, Height, None };
+
+ PDirLister( const char* name );
+
+ virtual QString defaultPath()const = 0;
+ virtual QString setStartPath( const QString& ) = 0;
+ virtual QString currentPath()const = 0;
+ virtual QStringList folders()const = 0;
+ virtual QStringList files()const = 0;
+public slots:
+ virtual void deleteImage( const QString& ) = 0;
+ virtual void imageInfo( const QString&) = 0;
+ virtual void fullImageInfo( const QString& ) = 0;
+ virtual void thumbNail( const QString&, int max_wid, int max_h ) = 0;
+ virtual QImage image( const QString&, Factor, int max = 0) = 0;
+
+signals:
+ void sig_dirchanged();
+ void sig_filechanged();
+ void sig_start();
+ void sig_end();
+// If this app ever happens to get multithreaded...
+ void sig_thumbInfo( const QString&, const QString& );
+ void sig_fullInfo( const QString&, const QString& );
+ void sig_thumbNail( const QString&, const QPixmap& );
+
+protected:
+ ~PDirLister();
+};
+
+#endif
diff --git a/noncore/graphics/opie-eye/iface/dirview.cpp b/noncore/graphics/opie-eye/iface/dirview.cpp
new file mode 100644
index 0000000..c3d1e86
--- a/dev/null
+++ b/noncore/graphics/opie-eye/iface/dirview.cpp
@@ -0,0 +1,9 @@
+#include "dirview.h"
+
+PDirView::PDirView( const Config& ) {
+
+}
+
+PDirView::~PDirView() {
+
+}
diff --git a/noncore/graphics/opie-eye/iface/dirview.h b/noncore/graphics/opie-eye/iface/dirview.h
new file mode 100644
index 0000000..20d9062
--- a/dev/null
+++ b/noncore/graphics/opie-eye/iface/dirview.h
@@ -0,0 +1,40 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ * No WArranty...
+ */
+
+#ifndef PHUNK_DIR_VIEW_H
+#define PHUNK_DIR_VIEW_H
+
+#include <qmap.h>
+
+#include <qpe/config.h>
+
+class PInterfaceInfo;
+class PDirLister;
+
+struct PDirView {
+ PDirView( const Config& );
+ virtual ~PDirView();
+ virtual PInterfaceInfo* interfaceInfo()const = 0;
+ virtual PDirLister* dirLister()const = 0;
+};
+
+typedef PDirView* (*phunkViewCreateFunc )(const Config& );
+typedef QMap<QString,phunkViewCreateFunc> ViewMap;
+
+ViewMap* viewMap();
+PDirView* currentView();
+void setCurrentView( PDirView* );
+
+
+
+#define PHUNK_VIEW_INTERFACE( NAME, IMPL ) \
+ static PDirView *create_ ## IMPL( const Config& cfg ) { \
+ return new IMPL( cfg ); \
+ } \
+ static ViewMap::Iterator dummy_ ## IMPL = viewMap()->insert( NAME, create_ ## IMPL );
+
+
+
+#endif
diff --git a/noncore/graphics/opie-eye/iface/ifaceinfo.h b/noncore/graphics/opie-eye/iface/ifaceinfo.h
new file mode 100644
index 0000000..74e0db6
--- a/dev/null
+++ b/noncore/graphics/opie-eye/iface/ifaceinfo.h
@@ -0,0 +1,19 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ * No WArranty...
+ */
+
+#ifndef PHUNK_INTERFACE_INFO_H
+#define PHUNK_INTERFACE_INFO_H
+
+#include <qstring.h>
+
+class QWidget;
+class Config;
+struct PInterfaceInfo {
+ virtual QString name()const = 0;
+ virtual QWidget* configWidget( const Config& ) = 0;
+ virtual void writeConfig( QWidget* wid, Config& ) = 0;
+};
+
+#endif
diff --git a/noncore/graphics/opie-eye/iface/slaveiface.h b/noncore/graphics/opie-eye/iface/slaveiface.h
new file mode 100644
index 0000000..e1ecf1f
--- a/dev/null
+++ b/noncore/graphics/opie-eye/iface/slaveiface.h
@@ -0,0 +1,47 @@
+/*
+ *GPLv2
+ */
+
+#ifndef SLAVE_INTERFACE_H
+#define SLAVE_INTERFACE_H
+
+#include <qpixmap.h>
+#include <qstring.h>
+
+/**
+ * The Data Packets we use
+ */
+
+struct ImageInfo {
+ ImageInfo() : kind(false){}
+ bool operator==( const ImageInfo other ) {
+ if ( kind != other.kind ) return false;
+ if ( file != other.file ) return false;
+ return true;
+ }
+ bool kind;
+ QString file;
+ QString info;
+};
+
+struct PixmapInfo {
+ PixmapInfo() : width( -1 ), height( -1 ) {}
+ bool operator==( const PixmapInfo& r ) {
+ if ( width != r.width ) return false;
+ if ( height != r.height ) return false;
+ if ( file != r.file ) return false;
+ return true;
+ }
+ int width, height;
+ QString file;
+ QPixmap pixmap;
+};
+
+
+/*
+ * Image Infos
+ */
+
+
+
+#endif
diff --git a/noncore/graphics/opie-eye/impl/dir/dir_dirview.cpp b/noncore/graphics/opie-eye/impl/dir/dir_dirview.cpp
new file mode 100644
index 0000000..97e3dcb
--- a/dev/null
+++ b/noncore/graphics/opie-eye/impl/dir/dir_dirview.cpp
@@ -0,0 +1,29 @@
+#include "dir_lister.h"
+#include "dir_ifaceinfo.h"
+#include "dir_dirview.h"
+
+PHUNK_VIEW_INTERFACE("Dir View", Dir_DirView );
+
+
+Dir_DirView::Dir_DirView( const Config& cfg)
+ : PDirView(cfg)
+{
+ m_cfg = cfg.readBoolEntry( "Dir_Check_All_Files", true);
+ m_lister = 0;
+ m_info = 0;
+}
+
+Dir_DirView::~Dir_DirView() {
+}
+
+PInterfaceInfo* Dir_DirView::interfaceInfo()const{
+ if (!m_info )
+ m_info =new DirInterfaceInfo;
+ return m_info;
+}
+
+PDirLister* Dir_DirView::dirLister()const{
+ if (!m_lister )
+ m_lister = new Dir_DirLister(m_cfg);
+ return m_lister;
+}
diff --git a/noncore/graphics/opie-eye/impl/dir/dir_dirview.h b/noncore/graphics/opie-eye/impl/dir/dir_dirview.h
new file mode 100644
index 0000000..3b9b7a6
--- a/dev/null
+++ b/noncore/graphics/opie-eye/impl/dir/dir_dirview.h
@@ -0,0 +1,24 @@
+/*
+ * GPLv2 only zecke@handhelds.org
+ */
+
+#ifndef DIR_DIR_VIEW_H
+#define DIR_DIR_VIEW_H
+
+#include <iface/dirview.h>
+
+
+struct Dir_DirView : public PDirView {
+ Dir_DirView( const Config& );
+ ~Dir_DirView();
+
+ PInterfaceInfo* interfaceInfo()const;
+ PDirLister* dirLister()const;
+private:
+ bool m_cfg : 1;
+ mutable PDirLister* m_lister;
+ mutable PInterfaceInfo *m_info;
+};
+
+
+#endif
diff --git a/noncore/graphics/opie-eye/impl/dir/dir_ifacceinfo.h b/noncore/graphics/opie-eye/impl/dir/dir_ifacceinfo.h
new file mode 100644
index 0000000..8c6262f
--- a/dev/null
+++ b/noncore/graphics/opie-eye/impl/dir/dir_ifacceinfo.h
@@ -0,0 +1,21 @@
+/*
+ * GPLv2
+ * zecke@handhelds.org
+ */
+
+#ifndef DIR_IFACE_INFO_H
+#define DIR_IFACE_INFO_H
+
+#include <iface/ifaceinfo.h>s
+
+class DirInterfaceInfo : public PInterfaceInfo {
+public:
+ DirInterfaceInfo();
+ ~DirInterfaceInfo();
+
+ QString name()const;
+ QWidget* configWidget(const Config&);
+ void writeConfig( QWidget* wid, Config& );
+};
+
+#endif
diff --git a/noncore/graphics/opie-eye/impl/dir/dir_ifaceinfo.cpp b/noncore/graphics/opie-eye/impl/dir/dir_ifaceinfo.cpp
new file mode 100644
index 0000000..79f4510
--- a/dev/null
+++ b/noncore/graphics/opie-eye/impl/dir/dir_ifaceinfo.cpp
@@ -0,0 +1,47 @@
+/*
+ * GPLv2
+ * zecke@handhelds.org
+ */
+
+#include <qwidget.h>
+#include <qcheckbox.h>
+#include <qhbox.h>
+#include <qlabel.h>
+
+#include <qpe/config.h>
+
+#include "dir_ifaceinfo.h"
+
+namespace {
+ class DirImageWidget : public QHBox {
+ public:
+ DirImageWidget() {
+ chkbox = new QCheckBox( QObject::tr("Show all files"), this );
+ }
+ ~DirImageWidget() {}
+ QCheckBox* chkbox;
+ };
+}
+
+
+DirInterfaceInfo::DirInterfaceInfo() {
+}
+DirInterfaceInfo::~DirInterfaceInfo() {
+}
+
+QString DirInterfaceInfo::name()const {
+ return QString::fromLatin1(QObject::tr("DirView" ));
+}
+
+QWidget* DirInterfaceInfo::configWidget(const Config& cfg) {
+ DirImageWidget* wid = new DirImageWidget();
+ wid->chkbox->setChecked( cfg.readBoolEntry("Dir_Check_All_Files", true) );
+
+ return wid;
+}
+
+void DirInterfaceInfo::writeConfig( QWidget* _wid, Config& cfg) {
+ qWarning( "Write Config" );
+ DirImageWidget* wid = static_cast<DirImageWidget*>(_wid);
+ cfg.writeEntry("Dir_Check_All_Files", wid->chkbox->isChecked() );
+}
diff --git a/noncore/graphics/opie-eye/impl/dir/dir_ifaceinfo.h b/noncore/graphics/opie-eye/impl/dir/dir_ifaceinfo.h
new file mode 100644
index 0000000..c919dde
--- a/dev/null
+++ b/noncore/graphics/opie-eye/impl/dir/dir_ifaceinfo.h
@@ -0,0 +1,21 @@
+/*
+ * GPLv2
+ * zecke@handhelds.org
+ */
+
+#ifndef DIR_IFACE_INFO_H
+#define DIR_IFACE_INFO_H
+
+#include <iface/ifaceinfo.h>
+
+class DirInterfaceInfo : public PInterfaceInfo {
+public:
+ DirInterfaceInfo();
+ virtual ~DirInterfaceInfo();
+
+ QString name()const;
+ QWidget* configWidget(const Config&);
+ void writeConfig( QWidget* wid, Config& );
+};
+
+#endif
diff --git a/noncore/graphics/opie-eye/impl/dir/dir_lister.cpp b/noncore/graphics/opie-eye/impl/dir/dir_lister.cpp
new file mode 100644
index 0000000..ffea29e
--- a/dev/null
+++ b/noncore/graphics/opie-eye/impl/dir/dir_lister.cpp
@@ -0,0 +1,94 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ */
+
+#include "dir_lister.h"
+
+#include <lib/slavemaster.h>
+
+
+#include <qpe/config.h>
+#include <qpe/qpeapplication.h>
+
+#include <qdir.h>
+#include <qfileinfo.h>
+
+
+Dir_DirLister::Dir_DirLister( bool list )
+ : PDirLister( "dir_dir_lister" )
+{
+ m_allFiles = list;
+ qWarning("All Files %d", m_allFiles );
+
+ SlaveMaster* master = SlaveMaster::self();
+ connect( master, SIGNAL(sig_start()), this, SIGNAL(sig_start()) );
+ connect( master, SIGNAL(sig_end()), this, SIGNAL(sig_end()) );
+ connect( master, SIGNAL(sig_thumbInfo(const QString&, const QString&)),
+ this, SIGNAL(sig_thumbInfo(const QString&, const QString&)) );
+ connect( master, SIGNAL(sig_fullInfo(const QString&, const QString&)),
+ this, SIGNAL(sig_fullInfo(const QString&, const QString&)) );
+ connect( master, SIGNAL(sig_thumbNail(const QString&, const QPixmap&)),
+ this, SIGNAL(sig_thumbNail(const QString&, const QPixmap&)) );
+
+}
+
+QString Dir_DirLister::defaultPath()const {
+ return QPEApplication::documentDir();
+}
+
+QString Dir_DirLister::setStartPath( const QString& path ) {
+ m_currentDir.cd( path );
+ if (!m_currentDir.exists() )
+ m_currentDir.cd(defaultPath());
+
+
+ return m_currentDir.absPath();
+}
+
+QString Dir_DirLister::currentPath()const {
+ return m_currentDir.absPath();
+}
+
+
+QStringList Dir_DirLister::folders()const {
+ return m_currentDir.entryList( QDir::Dirs );
+}
+
+QStringList Dir_DirLister::files()const {
+ if ( m_allFiles )
+ return m_currentDir.entryList( QDir::Files );
+ else {
+ QStringList out;
+ QStringList list = m_currentDir.entryList( QDir::Files | QDir::Readable );
+ for (QStringList::Iterator it = list.begin(); it != list.end();++it ) {
+ QFileInfo inf( *it );
+ QString ext = inf.extension(false).lower();
+ if( ext == QString::fromLatin1("jpg") ||
+ ext == QString::fromLatin1("jpeg" ) ||
+ ext == QString::fromLatin1("png" ) ||
+ ext == QString::fromLatin1("gif" ) )
+ out.append( *it );
+ }
+ return out;
+ }
+}
+
+void Dir_DirLister::deleteImage( const QString& fl) {
+ QFile::remove( fl );
+}
+
+void Dir_DirLister::thumbNail( const QString& str, int w, int h) {
+ SlaveMaster::self()->thumbNail( str, w, h );
+}
+
+QImage Dir_DirLister::image( const QString& str, Factor f, int m) {
+ return SlaveMaster::self()->image( str, f, m );
+}
+
+void Dir_DirLister::imageInfo( const QString& str) {
+ SlaveMaster::self()->thumbInfo( str );
+}
+
+void Dir_DirLister::fullImageInfo( const QString& str) {
+ SlaveMaster::self()->imageInfo( str );
+}
diff --git a/noncore/graphics/opie-eye/impl/dir/dir_lister.h b/noncore/graphics/opie-eye/impl/dir/dir_lister.h
new file mode 100644
index 0000000..fc63bb0
--- a/dev/null
+++ b/noncore/graphics/opie-eye/impl/dir/dir_lister.h
@@ -0,0 +1,34 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ */
+
+#ifndef DIR_LISTER_INTERFACE_LISTER_H
+#define DIR_LISTER_INTERFACE_LISTER_H
+
+#include <qdir.h>
+
+#include <iface/dirlister.h>
+
+class Config;
+class Dir_DirLister : public PDirLister {
+public:
+ Dir_DirLister( bool );
+
+ QString defaultPath()const;
+ QString setStartPath( const QString& );
+ QString currentPath()const;
+ QStringList folders()const;
+ QStringList files()const;
+
+ void deleteImage( const QString& );
+ void thumbNail( const QString&, int, int );
+ QImage image( const QString&, Factor, int );
+ void imageInfo( const QString& );
+ void fullImageInfo( const QString& );
+
+private:
+ bool m_allFiles;
+ QDir m_currentDir;
+};
+
+#endif
diff --git a/noncore/graphics/opie-eye/lib/imagecache.cpp b/noncore/graphics/opie-eye/lib/imagecache.cpp
new file mode 100644
index 0000000..3b74a83
--- a/dev/null
+++ b/noncore/graphics/opie-eye/lib/imagecache.cpp
@@ -0,0 +1,87 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ * No WArranty...
+ */
+
+#include <iface/dirview.h>
+#include <iface/dirlister.h>
+
+#include "imagecache.h"
+
+namespace {
+ PImageCache * _imgCache = 0;
+ PPixmapCache* _pxmCache = 0;
+}
+
+
+PImageCache::PImageCache()
+ : QCache<QImage>()
+{
+ /* just to set an initial value.. 4 big images */
+ setMaxCost( (1024*1024*16)/8*4 );
+}
+
+PImageCache::~PImageCache() {
+}
+
+PImageCache* PImageCache::self() {
+ if ( !_imgCache )
+ _imgCache = new PImageCache;
+ return _imgCache;
+}
+
+QImage* PImageCache::cachedImage( const QString& _path, int ori, int max ) {
+ QString path = QString( "%1_%2:" ).arg( ori ).arg( max );
+ path += _path;
+
+ QImage* img = find( path );
+ if ( !img ) {
+// img = currentView()->dirLister()->image( _path, PDirLister::Factor(ori), max);
+// insertImage( _path, img, ori, max );
+ currentView()->dirLister()->image( _path, PDirLister::Factor( ori ), max );
+ }
+
+
+ return img;
+}
+
+void PImageCache::insertImage( const QString& _path, const QImage* img, int ori, int max ) {
+ QString path = QString("%1_%2:" ).arg( ori ).arg( max );
+ path += _path;
+ insert( path, img, (img->height()*img->width()*img->depth())/8 );
+}
+
+
+PPixmapCache::PPixmapCache() {
+ /*
+ * 20 64x64 16 bit images
+ */
+ setMaxCost( 64*64*QPixmap::defaultDepth()/8*20 );
+}
+
+PPixmapCache::~PPixmapCache() {
+}
+
+PPixmapCache* PPixmapCache::self() {
+ if ( !_pxmCache )
+ _pxmCache = new PPixmapCache;
+
+ return _pxmCache;
+}
+
+QPixmap* PPixmapCache::cachedImage( const QString& _path, int width, int height ) {
+ QString path = QString( "%1_%2:" ).arg( width ).arg( height );
+ path += _path;
+
+ QPixmap* pxm = find( path );
+
+
+
+ return pxm;
+}
+
+void PPixmapCache::insertImage( const QString& _path, const QPixmap* pix, int width, int height ) {
+ QString path = QString("%1_%2:" ).arg( width ).arg( height );
+ path += _path;
+ insert( path, pix, (pix->height()*pix->width()*pix->depth())/8 );
+}
diff --git a/noncore/graphics/opie-eye/lib/imagecache.h b/noncore/graphics/opie-eye/lib/imagecache.h
new file mode 100644
index 0000000..076ecd3
--- a/dev/null
+++ b/noncore/graphics/opie-eye/lib/imagecache.h
@@ -0,0 +1,46 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ * No WArranty...
+ */
+
+#ifndef PHUNK_IMAGE_CACHE_H
+#define PHUNK_IMAGE_CACHE_H
+
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qcache.h>
+
+
+class PImageCache : public QCache<QImage> {
+private:
+ PImageCache();
+ ~PImageCache();
+
+public:
+ static PImageCache *self();
+ QImage* cachedImage( const QString& path, int orientation = 3, int max = 0); //const;
+ void insertImage( const QString& path, const QImage &, int orien = 3, int max = 0);
+ void insertImage( const QString& path, const QImage *, int orien=3, int max = 0 );
+};
+
+
+class PPixmapCache : public QCache<QPixmap> {
+private:
+ PPixmapCache();
+ ~PPixmapCache();
+public:
+ static PPixmapCache *self();
+ QPixmap* cachedImage( const QString& path, int width, int height );
+ void insertImage( const QString& path, const QPixmap &, int width, int height );
+ void insertImage( const QString& path, const QPixmap *, int width, int height );
+};
+
+inline void PPixmapCache::insertImage( const QString& path, const QPixmap& p, int width, int height ) {
+ insertImage( path, new QPixmap( p ), width, height );
+}
+
+inline void PImageCache::insertImage( const QString& path, const QImage& p, int width, int height ) {
+ insertImage( path, new QImage( p ), width, height );
+}
+
+#endif
diff --git a/noncore/graphics/opie-eye/lib/slavemaster.cpp b/noncore/graphics/opie-eye/lib/slavemaster.cpp
new file mode 100644
index 0000000..18dc883
--- a/dev/null
+++ b/noncore/graphics/opie-eye/lib/slavemaster.cpp
@@ -0,0 +1,145 @@
+#include "slavemaster.h"
+
+#include <qpe/qpeapplication.h>
+#include <qpe/qcopenvelope_qws.h>
+
+#include <qcopchannel_qws.h>
+#include <qtimer.h>
+
+QDataStream & operator << (QDataStream & str, bool b)
+{
+ str << Q_INT8(b);
+ return str;
+}
+QDataStream & operator >> (QDataStream & str, bool & b)
+{
+ Q_INT8 l;
+ str >> l;
+ b = bool(l);
+ return str;
+}
+QDataStream &operator<<( QDataStream& s, const PixmapInfo& inf) {
+ return s << inf.file << inf.pixmap << inf.width << inf.height;
+}
+QDataStream &operator>>( QDataStream& s, PixmapInfo& inf ) {
+ s >> inf.file >> inf.pixmap >> inf.width >> inf.height;
+ return s;
+}
+QDataStream &operator<<( QDataStream& s, const ImageInfo& i) {
+ return s << i.kind << i.file << i.info;
+}
+QDataStream &operator>>( QDataStream& s, ImageInfo& i ) {
+ s >> i.kind >> i.file >> i.info;
+ return s;
+}
+
+
+
+SlaveMaster* SlaveMaster::m_master = 0;
+
+SlaveMaster::SlaveMaster()
+ : m_started( false )
+{
+ QCopChannel *chan= new QCopChannel( "QPE/opie-eye",this );
+ connect(chan, SIGNAL(received(const QCString&,const QByteArray&)),
+ this, SLOT(recieve(const QCString&,const QByteArray&)) );
+}
+
+SlaveMaster::~SlaveMaster() {
+}
+
+SlaveMaster* SlaveMaster::self() {
+ if ( !m_master )
+ m_master = new SlaveMaster;
+ return m_master;
+}
+
+void SlaveMaster::thumbInfo( const QString& str) {
+ m_inThumbInfo.append( str );
+
+ if ( !m_started ) {
+ QTimer::singleShot( 0, this, SLOT(slotTimerStart()));
+ m_started = true;
+ }
+}
+
+void SlaveMaster::imageInfo( const QString& str ) {
+ m_inImageInfo.append( str );
+ if ( !m_started ) {
+ QTimer::singleShot( 0, this, SLOT(slotTimerStart()));
+ m_started = true;
+ }
+}
+
+void SlaveMaster::thumbNail( const QString& str, int w, int h ) {
+ if ( str.isEmpty() ) {
+ qWarning( "Asking for empty nail" );
+ return;
+ }
+ qWarning( "Asking for thumbNail in size %d %d" + str, w,h );
+ PixmapInfo item;
+ item.file = str; item.width = w; item.height = h;
+ item.pixmap = QPixmap();
+ m_inThumbNail.append( item );
+
+ if ( !m_started ) {
+ QTimer::singleShot( 0, this, SLOT(slotTimerStart()));
+ m_started = true;
+ }
+}
+
+
+void SlaveMaster::recieve( const QCString& str, const QByteArray& at) {
+
+ ImageInfos infos;
+ PixmapInfos pixinfos;
+
+ QDataStream stream( at, IO_ReadOnly );
+ if ( str == "pixmapsHandled(PixmapList)" )
+ stream >> pixinfos;
+ else if ( str == "pixmapsHandled(StringList)" )
+ stream >> infos;
+
+ qWarning( "PixInfos %d", pixinfos.count() );
+
+ bool got_data = ( !infos.isEmpty() || !pixinfos.isEmpty() );
+ if ( got_data ) {
+ emit sig_start();
+ for ( ImageInfos::Iterator _it = infos.begin(); _it != infos.end(); ++_it ) {
+ if ( (*_it).kind )
+ emit sig_fullInfo( (*_it).file, (*_it).info );
+ else
+ emit sig_thumbInfo( (*_it).file, (*_it).info );
+ }
+
+ for ( PixmapInfos::Iterator it = pixinfos.begin(); it != pixinfos.end(); ++it )
+ emit sig_thumbNail( (*it).file, (*it).pixmap );
+ emit sig_end();
+ }
+}
+
+void SlaveMaster::slotTimerStart() {
+ m_started = false;
+
+ if ( !m_inThumbInfo.isEmpty() ) {
+ QCopEnvelope env("QPE/opie-eye_slave", "thumbInfos(QStringList)" );
+ env << m_inThumbInfo;
+ }
+ if ( !m_inImageInfo.isEmpty() ) {
+ QCopEnvelope env("QPE/opie-eye_slave", "fullInfos(QStringList)" );
+ env << m_inImageInfo;
+ }
+ if ( !m_inThumbNail.isEmpty() ) {
+ QCopEnvelope env("QPE/opie-eye_slave", "pixmapInfos(PixmapInfos)" );
+ env << m_inThumbNail;
+ }
+
+
+ m_inThumbInfo.clear();
+ m_inImageInfo.clear();
+ m_inThumbNail.clear();
+}
+
+QImage SlaveMaster::image( const QString& str, PDirLister::Factor, int ) {
+ return QImage();
+}
diff --git a/noncore/graphics/opie-eye/lib/slavemaster.h b/noncore/graphics/opie-eye/lib/slavemaster.h
new file mode 100644
index 0000000..f5284a6
--- a/dev/null
+++ b/noncore/graphics/opie-eye/lib/slavemaster.h
@@ -0,0 +1,43 @@
+#ifndef OPIE_EYE_SLAVE_MASTER_H
+#define OPIE_EYE_SLAVE_MASTER_H
+
+#include <iface/dirlister.h>
+#include <iface/slaveiface.h>
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qsize.h>
+
+class SlaveMaster : public QObject {
+ Q_OBJECT
+ typedef QValueList<ImageInfo> ImageInfos;
+ typedef QValueList<PixmapInfo> PixmapInfos;
+public:
+ static SlaveMaster *self();
+
+ void thumbInfo( const QString& );
+ void imageInfo( const QString& );
+ void thumbNail( const QString&, int w, int h );
+ QImage image( const QString&, PDirLister::Factor, int );
+signals:
+ void sig_start();
+ void sig_end();
+
+ void sig_thumbInfo( const QString&, const QString& );
+ void sig_fullInfo( const QString&, const QString& );
+ void sig_thumbNail( const QString&, const QPixmap& );
+private slots:
+ void recieve( const QCString&, const QByteArray& );
+ void slotTimerStart();
+private:
+ SlaveMaster();
+ ~SlaveMaster();
+ static SlaveMaster *m_master;
+ bool m_started : 1;
+ QStringList m_inThumbInfo;
+ QStringList m_inImageInfo;
+ PixmapInfos m_inThumbNail;
+};
+
+
+#endif
diff --git a/noncore/graphics/opie-eye/lib/viewmap.cpp b/noncore/graphics/opie-eye/lib/viewmap.cpp
new file mode 100644
index 0000000..ca242b7
--- a/dev/null
+++ b/noncore/graphics/opie-eye/lib/viewmap.cpp
@@ -0,0 +1,25 @@
+#include <iface/dirview.h>
+
+
+namespace {
+ ViewMap *_viewMap = 0;
+ PDirView *_dirView = 0;
+}
+
+
+ViewMap *viewMap() {
+ if ( !_viewMap )
+ _viewMap = new ViewMap;
+
+ return _viewMap;
+}
+
+
+PDirView* currentView(){
+ return _dirView;
+}
+
+
+void setCurrentView( PDirView* view ) {
+ _dirView = view;
+}
diff --git a/noncore/graphics/opie-eye/phunk_view.pro b/noncore/graphics/opie-eye/phunk_view.pro
new file mode 100644
index 0000000..21178ee
--- a/dev/null
+++ b/noncore/graphics/opie-eye/phunk_view.pro
@@ -0,0 +1,34 @@
+CONFIG += qt warn_on #quick-app
+DESTDIR = $(OPIEDIR)/bin
+TEMPLATE = app
+TARGET = opie-eye
+# the name of the resulting object
+
+HEADERS = gui/iconview.h gui/filesystem.h gui/mainwindow.h \
+ lib/imagecache.h impl/dir/dir_dirview.h \
+ iface/dirview.h iface/dirlister.h iface/ifaceinfo.h \
+ impl/dir/dir_lister.h impl/dir/dir_ifaceinfo.h \
+ lib/slavemaster.h \
+ iface/slaveiface.h
+
+# A list header files
+
+
+SOURCES = gui/iconview.cpp gui/filesystem.cpp gui/mainwindow.cpp \
+ lib/imagecache.cpp lib/viewmap.cpp \
+ impl/dir/dir_dirview.cpp iface/dirlister.cpp \
+ iface/dirview.cpp impl/dir/dir_lister.cpp \
+ impl/dir/dir_ifaceinfo.cpp lib/slavemaster.cpp
+# A list of source files
+
+INTERFACES =
+# list of ui files
+
+INCLUDEPATH += . $(OPIEDIR)/include
+DEPENDPATH += $(OPIEDIR)/include
+
+
+
+LIBS += -lqpe -lopie
+
+include ( $(OPIEDIR)/include.pro )
diff --git a/noncore/graphics/opie-eye/slave/gif_slave.cpp b/noncore/graphics/opie-eye/slave/gif_slave.cpp
new file mode 100644
index 0000000..feb69b6
--- a/dev/null
+++ b/noncore/graphics/opie-eye/slave/gif_slave.cpp
@@ -0,0 +1,305 @@
+#include "gif_slave.h"
+
+#include "thumbnailtool.h"
+
+#include <qimage.h>
+#include <qobject.h>
+#include <qfile.h>
+#include <qpixmap.h>
+
+
+PHUNK_VIEW_INTERFACE( "Gif", GifSlave );
+
+
+namespace {
+/*
+** $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+*/
+#define SUCCESS (0)
+#define FAILURE (1)
+
+#define READ_BINARY "r"
+#define WRITE_BINARY "w"
+
+
+static long int pos;
+static char skipcomment,verbose;
+char *global_comment;
+
+#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')
+
+static bool debug = false;
+static bool output= false;
+
+void dump(long int, unsigned char *, size_t) {
+}
+
+void skipdata(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 transdata(FILE *src, FILE *dest)
+{
+ unsigned char size,buffer[256];
+
+ do {
+ pos=ftell(src);
+ (void)fread((void *)&size,1,1,src);
+ 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);
+}
+
+void transblock(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(FILE *src, QCString& str)
+{
+ unsigned char size;
+
+ pos=ftell(src);
+ (void)fread((void *)&size,1,1,src);
+ if (debug)
+ dump(pos,&size,1);
+ str.resize( size+1 );
+ (void)fread((void *)str.data(),size,1,src);
+ (void)fseek(src,(long int)pos,SEEK_SET);
+}
+
+
+
+
+int giftrans(FILE *src, FILE* dest, QString& str, bool full)
+{
+ unsigned char buffer[3*256],lsd[7],gct[3*256];
+ unsigned int size,gct_size;
+
+ /* Header */
+ pos=ftell(src);
+ (void)fread((void *)buffer,6,1,src);
+ if (strncmp((char *)buffer,"GIF",3)) {
+ str = QObject::tr("Not a GIF file");
+ (void)fprintf(stderr,"Not GIF file!\n");
+ return(1);
+ }
+
+ /* Logical Screen Descriptor */
+ pos=ftell(src);
+ (void)fread((void *)lsd,7,1,src);
+ //(void)fprintf(stderr,"Logical Screen Descriptor:\n");
+ str += QObject::tr("Dimensions: %1x%2\n").arg( readword(lsd) ).arg( readword(lsd+2 ) );
+ //(void)fprintf(stderr,"Global Color Table Flag: %s\n",readflag(lsd[4]&0x80));
+ str += QObject::tr("Depth: %1 bits\n").arg( (lsd[4]&0x70>>4 )+1);
+ //(void)fprintf(stderr,"Depth : %d bits\n",(lsd[4]&0x70>>4)+1);
+ if (lsd[4]&0x80 && full) {
+ str += QObject::tr("Sort Flag: %1\n" ).arg(readflag(lsd[4]&0x8) );
+ str += QObject::tr("Size of Global Color Table: %1 colors\n" ).arg( 2<<(lsd[4]&0x7));
+ str += QObject::tr("Background Color Index: %1\n" ).arg(lsd[5]);
+ }
+ if (lsd[6] && full)
+ str += QObject::tr("Pixel Aspect Ratio: %1 (Aspect Ratio %2)\n" ).arg( lsd[6] ).
+ arg( ((double)lsd[6]+15)/64 );
+
+ /* Global Color Table */
+ if (lsd[4]&0x80) {
+ gct_size=2<<(lsd[4]&0x7);
+ pos=ftell(src);
+ (void)fread((void *)gct,gct_size,3,src);
+ }
+
+ do {
+ pos=ftell(src);
+ (void)fread((void *)buffer,1,1,src);
+ switch (buffer[0]) {
+ case 0x2c: /* Image Descriptor */
+ (void)fread((void *)(buffer+1),9,1,src);
+ /* Local Color Table */
+ if (buffer[8]&0x80) {
+ size=2<<(buffer[8]&0x7);
+ pos=ftell(src);
+ (void)fread((void *)buffer,size,3,src);
+ }
+ /* Table Based Image Data */
+ pos=ftell(src);
+ (void)fread((void *)buffer,1,1,src);
+ transdata(src,dest);
+ break;
+ case 0x21: /* Extension */
+ (void)fread((void *)(buffer+1),1,1,src);
+ switch (buffer[1]) {
+ case 0xfe: /* Comment Extension */
+ if (true)
+ {
+ QCString st;
+ dumpcomment(src, st);
+ str += QObject::tr("Comment: %1\n" ).arg( st );
+ }
+ if (skipcomment)
+ skipdata(src);
+ else {
+ transdata(src,dest);
+ }
+ break;
+ case 0x01: /* Plain Text Extension */
+ case 0xf9: /* Graphic Control Extension */
+ case 0xff: /* Application Extension */
+ default:
+ transblock(src,dest);
+ transdata(src,dest);
+ break;
+ }
+ break;
+ case 0x3b: /* Trailer (write comment just before here) */
+ break;
+ default:
+ (void)fprintf(stderr,"0x%08lx: Error, unknown block 0x%02x!\n",ftell(src)-1,buffer[0]);
+ return(1);
+ }
+ } while (buffer[0]!=0x3b&&!feof(src));
+ return(buffer[0]==0x3b?SUCCESS:FAILURE);
+}
+
+
+/****************************************************************************/
+extern void get_gif_info( const char * original_filename, QString& str,
+ bool full =false)
+{
+FILE * infile;
+
+ if ((infile = fopen(original_filename, READ_BINARY)) == NULL) {
+ fprintf(stderr, "can't open gif image '%s'\n", original_filename);
+ return ;
+ }
+
+ output = FALSE;
+ verbose = TRUE;
+ debug = FALSE;
+ skipcomment = FALSE;
+ giftrans( infile, NULL, str, full );
+ fclose( infile );
+}
+
+}
+
+
+GifSlave::GifSlave()
+ : SlaveInterface(QStringList("gif"))
+{}
+
+GifSlave::~GifSlave() {
+
+}
+
+QString GifSlave::iconViewName(const QString& str) {
+ QString st;
+ get_gif_info(QFile::encodeName( str ).data(), st );
+ return st;
+}
+
+QString GifSlave::fullImageInfo( const QString& str) {
+ QString st;
+ get_gif_info(QFile::encodeName( str ).data(), st, true );
+ return st;
+}
+
+QPixmap GifSlave::pixmap(const QString& path, int width, int height ) {
+ static QImage img;
+ img.load( path );
+ if ( img.isNull() ) {
+ QPixmap pix;
+ return pix;
+ }
+
+ return ThumbNailTool::scaleImage( img, width,height );
+}
+
+
diff --git a/noncore/graphics/opie-eye/slave/gif_slave.h b/noncore/graphics/opie-eye/slave/gif_slave.h
new file mode 100644
index 0000000..cb8522d
--- a/dev/null
+++ b/noncore/graphics/opie-eye/slave/gif_slave.h
@@ -0,0 +1,22 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ */
+
+
+#ifndef SLAVE_GIF_IMPL_H
+#define SLAVE_GIF_IMPL_H
+
+#include "slaveiface.h"
+
+class GifSlave : public SlaveInterface {
+public:
+ GifSlave();
+ ~GifSlave();
+
+ QString iconViewName( const QString& );
+ QString fullImageInfo( const QString& );
+ QPixmap pixmap( const QString&, int width, int height );
+};
+
+
+#endif
diff --git a/noncore/graphics/opie-eye/slave/jpeg_slave.cpp b/noncore/graphics/opie-eye/slave/jpeg_slave.cpp
new file mode 100644
index 0000000..95055fd
--- a/dev/null
+++ b/noncore/graphics/opie-eye/slave/jpeg_slave.cpp
@@ -0,0 +1,1426 @@
+#include "jpeg_slave.h"
+
+#include "thumbnailtool.h"
+
+PHUNK_VIEW_INTERFACE( "JPEG", JpegSlave )
+
+#include <qtopia/timestring.h>
+#include <qobject.h>
+#include <qimage.h>
+
+/**
+ exif.h
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+
+#include <qstring.h>
+#include <qfile.h>
+#include <qimage.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);
+ 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 { qWarning("exception: %s", ex ); }
+};
+
+
+
+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
+
+
+
+
+//--------------------------------------------------------------------------
+// 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){
+
+ qWarning( "too many padding bytes" );
+ return false;
+
+ }
+ }
+
+ if (marker == 0xff){
+ // 0xff is legal padding, but if we get that many, something's wrong.
+ return false;
+ }
+
+ 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) {
+ return false;;
+ }
+
+ 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){
+ return false;
+ }
+ 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 = QMAX( 0ul, infile.size()-infile.at() );
+ Data = (uchar *)malloc(size);
+ if (Data == NULL){
+ return false;
+ }
+
+ got = infile.readBlock((char*)Data, size);
+ if (( unsigned ) got != size){
+ return false;
+ }
+
+ 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
+ qWarning( "No image in jpeg!" );
+ 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);
+ }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);
+ default:
+ break;
+ 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)
+{
+ int de;
+ int a;
+ int NumDirEntries;
+ unsigned ThumbnailOffset = 0;
+ unsigned ThumbnailSize = 0;
+
+ 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.
+ return;
+ }
+ }
+ if (DirEnd < LastExifRefd) LastExifRefd = DirEnd;
+ }
+
+ for (de=0;de<NumDirEntries;de++){
+ int Tag, Format, Components;
+ unsigned char * ValuePtr;
+ int 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.
+ return;
+ }
+
+ 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);
+
+ return;
+ }
+ 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((char*)ValuePtr);
+ break;
+
+ case TAG_MODEL:
+ ExifData::CameraModel = QString((char*)ValuePtr);
+ break;
+
+ case TAG_ORIENTATION:
+ Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_DATETIME_ORIGINAL:
+ DateTime = QString((char*)ValuePtr);
+ 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 != ' '){
+ //strncpy(ImageInfo.Comments, (const char*)(a+ValuePtr), 199);
+ UserComment.sprintf("%s", (const char*)(a+ValuePtr));
+ break;
+ }
+ }
+ }else{
+ //strncpy(ImageInfo.Comments, (const char*)ValuePtr, 199);
+ UserComment.sprintf("%s", (const char*)ValuePtr);
+ }
+ 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.5);
+ }
+ break;
+
+ case TAG_FOCALLENGTH:
+ // Nice digital cameras actually save the focal length as a function
+ // of how farthey 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)));
+ }
+ break;
+
+ case TAG_FLASH:
+ if (ConvertAnyFormat(ValuePtr, Format)){
+ ExifData::FlashUsed = 1;
+ }
+ 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){
+ return;
+ }
+ ProcessExifDir(SubdirStart, OffsetBase, ExifLength);
+ 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
+ qWarning( "Thumbnail removed with Jhead 1.3 or earlier" );
+ }else{
+ return;
+ }
+ }else{
+ if (SubdirStart <= OffsetBase+ExifLength){
+ ProcessExifDir(SubdirStart, OffsetBase, ExifLength);
+ }
+ }
+ }
+ }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)
+{
+ QChar ch;
+ int a;
+
+ for (a=2;a<length;a++){
+ ch = Data[a];
+ if (ch == '\000') continue; // Remove nulls
+ Comment.append(ch);
+ }
+}
+
+
+//--------------------------------------------------------------------------
+// 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)){
+ return;
+ }
+ }
+
+ 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{
+ return;
+ }
+ }
+
+ // Check the next two values for correctness.
+ if (Get16u(CharBuf+10) != 0x2a
+ || Get32u(CharBuf+12) != 0x08){
+ return;
+ }
+
+ LastExifRefd = CharBuf;
+
+ // First directory starts 16 bytes in. Offsets start at 8 bytes in.
+ ProcessExifDir(CharBuf+16, CharBuf+8, length-6);
+
+ // 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){
+ 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 = -1;
+ 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);
+ f.open(IO_ReadOnly);
+
+ // Scan the JPEG headers.
+ ret = ReadJpegSections(f, READ_EXIF);
+
+ if (ret == false){
+ qWarning( "Not JPEG file!" );
+ 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);
+}
+
+
+
+static QImage flip_image( const QImage& img );
+static QImage rotate_90( const QImage& img );
+static QImage rotate_180( const QImage& );
+static QImage rotate_270( const QImage& );
+
+//--------------------------------------------------------------------------
+// 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
+
+ QImage dest = Thumbnail;
+ switch (Orientation) { // notice intentional fallthroughs
+ case 2: dest = flip_image( dest ); break;
+ case 4: dest = flip_image( dest );
+ case 3: dest =rotate_180( dest ); break;
+ case 5: dest = flip_image( dest );
+ case 6: dest = rotate_90( dest ); break;
+ case 7: dest = flip_image( dest );
+ case 8: dest = rotate_270( dest ); break;
+ default: break; // should never happen
+ }
+ return dest;
+}
+
+
+/*
+ *
+ */
+static QImage flip_image( const QImage& img ) {
+ return img.mirror( TRUE, FALSE );
+}
+
+
+static QImage dest;
+static int x, y;
+static unsigned int *srcData, *destData; // we're not threaded anyway
+static unsigned char *srcData8, *destData8; // 8 bit is char
+static unsigned int *srcTable, *destTable; // destination table
+
+
+static QImage rotate_90_8( const QImage &img ) {
+ dest.create(img.height(), img.width(), img.depth());
+ dest.setNumColors(img.numColors());
+ srcTable = (unsigned int *)img.colorTable();
+ destTable = (unsigned int *)dest.colorTable();
+ for ( x=0; x < img.numColors(); ++x )
+ destTable[x] = srcTable[x];
+ for ( y=0; y < img.height(); ++y ){
+ srcData8 = (unsigned char *)img.scanLine(y);
+ for ( x=0; x < img.width(); ++x ){
+ destData8 = (unsigned char *)dest.scanLine(x);
+ destData8[img.height()-y-1] = srcData8[x];
+ }
+ }
+ return dest;
+}
+
+static QImage rotate_90_all( const QImage& img ) {
+ dest.create(img.height(), img.width(), img.depth());
+ for ( y=0; y < img.height(); ++y ) {
+ srcData = (unsigned int *)img.scanLine(y);
+ for ( x=0; x < img.width(); ++x ) {
+ destData = (unsigned int *)dest.scanLine(x);
+ destData[img.height()-y-1] = srcData[x];
+ }
+ }
+
+ return dest;
+}
+
+
+static QImage rotate_90( const QImage & img ) {
+ if ( img.depth() > 8)
+ return rotate_90_all( img );
+ else
+ return rotate_90_8( img );
+}
+
+static QImage rotate_180_all( const QImage& img ) {
+ dest.create(img.width(), img.height(), img.depth());
+ for ( y=0; y < img.height(); ++y ){
+ srcData = (unsigned int *)img.scanLine(y);
+ destData = (unsigned int *)dest.scanLine(img.height()-y-1);
+ for ( x=0; x < img.width(); ++x )
+ destData[img.width()-x-1] = srcData[x];
+ }
+ return dest;
+}
+
+static QImage rotate_180_8( const QImage& img ) {
+ dest.create(img.width(), img.height(), img.depth());
+ dest.setNumColors(img.numColors());
+ srcTable = (unsigned int *)img.colorTable();
+ destTable = (unsigned int *)dest.colorTable();
+ for ( x=0; x < img.numColors(); ++x )
+ destTable[x] = srcTable[x];
+ for ( y=0; y < img.height(); ++y ){
+ srcData8 = (unsigned char *)img.scanLine(y);
+ destData8 = (unsigned char *)dest.scanLine(img.height()-y-1);
+ for ( x=0; x < img.width(); ++x )
+ destData8[img.width()-x-1] = srcData8[x];
+ }
+ return dest;
+}
+
+static QImage rotate_180( const QImage& img ) {
+ if ( img.depth() > 8 )
+ return rotate_180_all( img );
+ else
+ return rotate_180_8( img );
+}
+
+
+static QImage rotate_270_8( const QImage& img ) {
+ dest.create(img.height(), img.width(), img.depth());
+ dest.setNumColors(img.numColors());
+ srcTable = (unsigned int *)img.colorTable();
+ destTable = (unsigned int *)dest.colorTable();
+ for ( x=0; x < img.numColors(); ++x )
+ destTable[x] = srcTable[x];
+ for ( y=0; y < img.height(); ++y ){
+ srcData8 = (unsigned char *)img.scanLine(y);
+ for ( x=0; x < img.width(); ++x ){
+ destData8 = (unsigned char *)dest.scanLine(img.width()-x-1);
+ destData8[y] = srcData8[x];
+ }
+ }
+
+ return dest;
+}
+
+static QImage rotate_270_all( const QImage& img ) {
+ dest.create(img.height(), img.width(), img.depth());
+ for ( y=0; y < img.height(); ++y ){
+ srcData = (unsigned int *)img.scanLine(y);
+ for ( x=0; x < img.width(); ++x ){
+ destData = (unsigned int *)dest.scanLine(img.width()-x-1);
+ destData[y] = srcData[x];
+ }
+ }
+ return dest;
+}
+
+static QImage rotate_270( const QImage& img ) {
+ if ( img.depth() > 8 )
+ return rotate_270_all( img );
+ else
+ return rotate_270_8( img );
+}
+
+
+static QString color_mode_to_string( bool b ) {
+ return b ? QObject::tr( "Colormode: Color\n" ) : QObject::tr( "Colormode: Black and white\n" );
+}
+
+static QString compression_to_string( int level ) {
+ QString str;
+ switch( level ) {
+ case 1:
+ str = QObject::tr( "Basic" );
+ break;
+ case 2:
+ str = QObject::tr( "Normal" );
+ break;
+ case 4:
+ str = QObject::tr( "Fine" );
+ break;
+ default:
+ str = QObject::tr( "Unknown" );
+
+ }
+ return QObject::tr("Quality: %1\n").arg(str);
+}
+
+
+static QDateTime 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( 18, 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;
+}
+
+static QString white_balance_string( int i ) {
+ QString balance;
+ switch ( i ) {
+ case 0:
+ balance = QObject::tr( "Unknown" );
+ break;
+ case 1:
+ balance = QObject::tr( "Daylight" );
+ break;
+ case 2:
+ balance = QObject::tr( "Fluorescent" );
+ break;
+ case 3:
+ balance = QObject::tr( "Tungsten" );
+ break;
+ case 17:
+ balance = QObject::tr( "Standard light A" );
+ break;
+ case 18:
+ balance = QObject::tr( "Standard light B" );
+ break;
+ case 19:
+ balance = QObject::tr( "Standard light C" );
+ break;
+ case 20:
+ balance = QObject::tr( "D55" );
+ break;
+ case 21:
+ balance = QObject::tr( "D65" );
+ break;
+ case 22:
+ balance = QObject::tr( "D75" );
+ break;
+ case 255:
+ balance = QObject::tr( "Other" );
+ break;
+ default:
+ balance = QObject::tr( "Unknown" );
+ }
+ return QObject::tr( "White Balance: %1\n" ).arg( balance );
+
+}
+
+
+static QString metering_mode( int i) {
+ QString meter;
+ switch( i ) {
+ case 0:
+ meter = QObject::tr( "Unknown" );
+ break;
+ case 1:
+ meter = QObject::tr( "Average" );
+ break;
+ case 2:
+ meter = QObject::tr( "Center weighted average" );
+ break;
+ case 3:
+ meter = QObject::tr( "Spot" );
+ break;
+ case 4:
+ meter = QObject::tr( "MultiSpot" );
+ break;
+ case 5:
+ meter = QObject::tr( "Pattern" );
+ break;
+ case 6:
+ meter = QObject::tr( "Partial" );
+ break;
+ case 255:
+ meter = QObject::tr( "Other" );
+ break;
+ default:
+ meter = QObject::tr( "Unknown" );
+ }
+
+ return QObject::tr( "Metering Mode: %1\n" ).arg( meter );
+}
+
+
+static QString exposure_program( int i ) {
+ QString exp;
+ switch( i ) {
+ case 0:
+ exp = QObject::tr( "Not defined" );
+ break;
+ case 1:
+ exp = QObject::tr( "Manual" );
+ break;
+ case 2:
+ exp = QObject::tr( "Normal progam" );
+ break;
+ case 3:
+ exp = QObject::tr( "Aperture priority" );
+ break;
+ case 4:
+ exp = QObject::tr( "Shutter priority" );
+ break;
+ case 5:
+ exp = QObject::tr( "Creative progam\n(biased toward fast shutter speed" );
+ break;
+ case 6:
+ exp = QObject::tr( "Action progam\n(biased toward fast shutter speed)" );
+ break;
+ case 7:
+ exp = QObject::tr( "Portrait mode\n(for closeup photos with the background out of focus)" );
+ break;
+ case 8:
+ exp = QObject::tr( "Landscape mode\n(for landscape photos with the background in focus)" );
+ break;
+ default:
+ exp = QObject::tr( "Unknown" );
+ }
+
+ return QObject::tr( "Exposure Program: %1\n" ).arg( exp );
+}
+
+JpegSlave::JpegSlave()
+ : SlaveInterface( QStringList::split( " ", "jpeg jpg" ) )
+{}
+
+JpegSlave::~JpegSlave() {}
+
+QString JpegSlave::iconViewName( const QString& path) {
+ ExifData ImageInfo;
+ if ( !ImageInfo.scan( path ) )
+ return QString::null;
+
+ QString tag;
+ tag = QObject::tr( "<qt>Comment: %1\n" ).arg( ImageInfo.getComment() );
+ {
+// ODP fixme
+ QString timestring = TimeString::dateString( parseDateTime( ImageInfo.getDateTime() ), FALSE );
+ tag += QObject::tr( "Date/Time: %1\n" ).arg( timestring );
+ }
+ tag += QObject::tr( "Dimensions: %1x%2\n" ).arg(ImageInfo.getWidth())
+ .arg(ImageInfo.getHeight() );
+
+ tag += color_mode_to_string( ImageInfo.getIsColor() );
+
+ tag += compression_to_string( ImageInfo.getCompressionLevel() );
+ tag += QObject::tr( "</qt>" );
+
+ return tag;
+}
+
+
+/*
+ * messy messy string creation
+ */
+QString JpegSlave::fullImageInfo( const QString& path) {
+ ExifData ImageInfo;
+ if ( !ImageInfo.scan( path ) )
+ return QString::null;
+
+ QString tag, tmp;
+ tag = QObject::tr( "Comment: %1\n" ).arg( ImageInfo.getComment() );
+
+ tmp = ImageInfo.getCameraMake();
+ if ( tmp.length() )
+ tag += QObject::tr( "Manufacturer: %1\n" ).arg( tmp );
+ tmp = ImageInfo.getCameraModel();
+ if ( tmp.length() )
+ tag += QObject::tr( "Model: %1\n" ).arg( tmp );
+ {
+// ODP fixme
+ tmp = TimeString::dateString( parseDateTime( ImageInfo.getDateTime() ), FALSE );
+ tag += QObject::tr( "Date/Time: %1\n" ).arg( tmp );
+ }
+ tag += QObject::tr( "Dimensions: %1x%2\n" ).arg(ImageInfo.getWidth())
+ .arg(ImageInfo.getHeight() );
+
+ tag += color_mode_to_string( ImageInfo.getIsColor() );
+
+ tag += compression_to_string( ImageInfo.getCompressionLevel() );
+ if ( ImageInfo.getOrientation() )
+ tag += QObject::tr( "Orientation: %1\n" ).arg(ImageInfo.getOrientation() );
+
+
+ {
+ int flash_used = ImageInfo.getFlashUsed();
+ if ( flash_used >= 0 )
+ tag += QObject::tr( "Flash used\n" );
+ }
+
+ if ( ImageInfo.getFocalLength() ) {
+ tag += QObject::tr( "Focal length: %1\n" ).arg( QString().sprintf( "%4.1f", ImageInfo.getFocalLength() ) );
+ if ( ImageInfo.getCCDWidth() )
+ tag += QObject::tr( "35mm equivalent: %1\n" ).arg( (int)(ImageInfo.getFocalLength()/ImageInfo.getCCDWidth()*35 + 0.5) );
+
+ }
+
+ if ( ImageInfo.getCCDWidth() )
+ tag += QObject::tr( "CCD width: %1" ).arg( ImageInfo.getCCDWidth() );
+ if ( ImageInfo.getExposureTime() ) {
+ tmp = QString().sprintf("%4.2f", ImageInfo.getExposureTime() );
+ float exposureTime = ImageInfo.getExposureTime();
+ if ( exposureTime > 0 && exposureTime <= 0.5 )
+ tmp += QString().sprintf(" (1/%d)", (int)(0.5 +1/exposureTime) );
+ tag += QObject::tr( "Exposure time: %1\n" ).arg( tmp );
+ }
+
+ if ( ImageInfo.getApertureFNumber() )
+ tag += QObject::tr( "Aperture: %1\n" ).arg( QString().sprintf("f/%3.1f", (double)ImageInfo.getApertureFNumber() ) );
+
+ if ( ImageInfo.getDistance() ) {
+ if ( ImageInfo.getDistance() < 0 )
+ tag += QObject::tr( "Distance: %1\n" ).arg( QObject::tr( "Infinite" ) );
+ else
+ tag += QObject::tr( "Distance: %1\n" ).arg( QString().sprintf( "%5.2fm", (double)ImageInfo.getDistance() ) );
+ }
+
+ if ( ImageInfo.getExposureBias() ) {
+ tag += QObject::tr( "Exposure bias: %1\n", QString().sprintf("%4.2f", (double)ImageInfo.getExposureBias() ) );
+ }
+
+ if ( ImageInfo.getWhitebalance() != -1 )
+ tag += white_balance_string( ImageInfo.getWhitebalance() );
+
+
+ if( ImageInfo.getMeteringMode() != -1 )
+ tag += metering_mode( ImageInfo.getMeteringMode() );
+
+ if ( ImageInfo.getExposureProgram() )
+ tag += exposure_program( ImageInfo.getExposureProgram() );
+ if ( ImageInfo.getISOequivalent() )
+ tag += QObject::tr( "ISO equivalent: %1\n" ).arg( QString().sprintf("%2d", ImageInfo.getISOequivalent() ) );
+
+ tmp = ImageInfo.getUserComment();
+ if ( tmp.length() )
+ tag += QObject::tr( "EXIF comment: %1" ).arg( tmp );
+
+ tag += QObject::tr( "</qt>" );
+
+
+
+ return tag;
+}
+
+QPixmap JpegSlave::pixmap( const QString& path, int wid, int hei) {
+ ExifData ImageInfo;
+ if ( !ImageInfo.scan( path ) || ImageInfo.isNullThumbnail() ) {
+ QImage img;
+ QImageIO iio( path, 0l );
+ QString str = QString( "Fast Shrink( 4 ) Scale( %1, %2, ScaleFree)" ).arg( wid ).arg( hei );
+ iio.setParameters( str.latin1() );// will be strdupped anyway
+ img = iio.read() ? iio.image() : QImage();
+ return ThumbNailTool::scaleImage( img, wid,hei );
+ }else{
+ QImage img = ImageInfo.getThumbnail();
+ return ThumbNailTool::scaleImage( img, wid,hei );
+ }
+}
diff --git a/noncore/graphics/opie-eye/slave/jpeg_slave.h b/noncore/graphics/opie-eye/slave/jpeg_slave.h
new file mode 100644
index 0000000..e800dbd
--- a/dev/null
+++ b/noncore/graphics/opie-eye/slave/jpeg_slave.h
@@ -0,0 +1,19 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ */
+#ifndef JPEG_SLAVE_IMPL_H
+#define JPEG_SLAVE_IMPL_H
+
+#include "slaveiface.h"
+
+class JpegSlave : public SlaveInterface {
+public:
+ JpegSlave();
+ ~JpegSlave();
+
+ QString iconViewName( const QString& );
+ QString fullImageInfo( const QString& );
+ QPixmap pixmap( const QString&, int, int );
+};
+
+#endif
diff --git a/noncore/graphics/opie-eye/slave/main.cpp b/noncore/graphics/opie-eye/slave/main.cpp
new file mode 100644
index 0000000..37020e6
--- a/dev/null
+++ b/noncore/graphics/opie-eye/slave/main.cpp
@@ -0,0 +1,59 @@
+/*
+ * GPLv2 Slave Main
+ */
+
+#include "gif_slave.h"
+#include "png_slave.h"
+#include "jpeg_slave.h"
+#include "thumbnailtool.h"
+#include "slavereciever.h"
+
+#include <qpixmap.h>
+#include <qcopchannel_qws.h>
+
+#include <qtopia/qpeapplication.h>
+
+int main( int argc, char* argv[] ) {
+ QPEApplication app( argc, argv );
+ SlaveReciever rec( 0 );
+
+ QCopChannel chan( "QPE/opie-eye_slave" );
+ QObject::connect(&chan,SIGNAL(received(const QCString&, const QByteArray&)),
+ &rec, SLOT(recieveAnswer(const QCString&,const QByteArray&)));
+ QObject::connect(qApp,SIGNAL(appMessage(const QCString&, const QByteArray&)),
+ &rec, SLOT(recieveAnswer(const QCString&,const QByteArray&)));
+
+ return app.exec();
+}
+
+#ifdef DEBUG_IT
+int main( int argc, char* argv[] ) {
+ QString str = QString::fromLatin1(argv[2] );
+ QApplication app( argc, argv );
+ GifSlave slave;
+ qWarning( str +" "+slave.iconViewName(str ) );
+ qWarning( str+" "+slave.fullImageInfo( str ) );
+
+ PNGSlave pngslave;
+ qWarning( str + " " + pngslave.iconViewName(str) );
+ qWarning( str + " " + pngslave.fullImageInfo(str));
+
+
+ JpegSlave jpgslave;
+ qWarning( str + " " + jpgslave.iconViewName(str ) );
+ qWarning( str + " " + jpgslave.fullImageInfo( str ) );
+//return app.exec();
+ QPixmap pix = ThumbNailTool::getThumb( str, 24, 24 );
+ if ( pix.isNull() ) {
+ qWarning( "No Thumbnail" );
+ pix = slave.pixmap(str, 24, 24);
+ }
+
+ if (!pix.isNull() ) {
+ qWarning( "Saving Thumbnail" );
+ ThumbNailTool::putThumb( str, pix, 24, 24 );
+ }
+
+}
+
+#endif
diff --git a/noncore/graphics/opie-eye/slave/png_slave.cpp b/noncore/graphics/opie-eye/slave/png_slave.cpp
new file mode 100644
index 0000000..72b93cc
--- a/dev/null
+++ b/noncore/graphics/opie-eye/slave/png_slave.cpp
@@ -0,0 +1,210 @@
+#include "png_slave.h"
+
+#include "thumbnailtool.h"
+
+#include <qobject.h>
+#include <qfile.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qstring.h>
+
+/*
+ * GPLv2 from kfile plugin
+ */
+PHUNK_VIEW_INTERFACE( "PNG", PNGSlave );
+
+#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]
+
+/* TRANSLATOR QObject */
+
+// known translations for common png keys
+static const char* knownTranslations[]
+#ifdef __GNUC__
+__attribute__((unused))
+#endif
+ = {
+ QT_TR_NOOP("Title"),
+ QT_TR_NOOP("Author"),
+ QT_TR_NOOP("Description"),
+ QT_TR_NOOP("Copyright"),
+ QT_TR_NOOP("Creation Time"),
+ QT_TR_NOOP("Software"),
+ QT_TR_NOOP("Disclaimer"),
+ QT_TR_NOOP("Warning"),
+ QT_TR_NOOP("Source"),
+ QT_TR_NOOP("Comment")
+};
+
+// and for the colors
+static const char* colors[] = {
+ QT_TR_NOOP("Grayscale"),
+ QT_TR_NOOP("Unknown"),
+ QT_TR_NOOP("RGB"),
+ QT_TR_NOOP("Palette"),
+ QT_TR_NOOP("Grayscale/Alpha"),
+ QT_TR_NOOP("Unknown"),
+ QT_TR_NOOP("RGB/Alpha")
+};
+
+ // and compressions
+static const char* compressions[] =
+{
+ QT_TR_NOOP("Deflate")
+};
+
+ // interlaced modes
+static const char* interlaceModes[] = {
+ QT_TR_NOOP("None"),
+ QT_TR_NOOP("Adam7")
+};
+
+
+static void read_comment( const QString& inf,
+ bool readComments, QString& str ) {
+ QFile f(inf);
+ f.open(IO_ReadOnly);
+
+ if (f.size() < 26) return;
+ // the technical group will be read from the first 26 bytes. If the file
+ // is smaller, we can't even read this.
+
+ uchar *data = new uchar[f.size()+1];
+ f.readBlock(reinterpret_cast<char*>(data), f.size());
+ data[f.size()]='\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];
+
+ // 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;
+ }
+
+
+ str = QObject::tr("Dimensions: %1x%2\n" ).arg(x).arg(y);
+ str += QObject::tr("Depth: %1\n" ).arg(bpp);
+ str += QObject::tr("ColorMode: %1\n").arg(
+ (type < sizeof(colors)/sizeof(colors[0]))
+ ? QObject::tr(colors[data[25]]) : QObject::tr("Unknown") );
+
+ str += QObject::tr("Compression: %1\n").arg(
+ (data[26] < sizeof(compressions)/sizeof(compressions[0]))
+ ? QObject::tr(compressions[data[26]]) : QObject::tr("Unknown") );
+
+ str += QObject::tr("InterlaceMode: %1\n" ).arg(
+ (data[28] < sizeof(interlaceModes)/sizeof(interlaceModes[0]))
+ ? QObject::tr(interlaceModes[data[28]]) : QObject::tr("Unknown"));
+ }
+
+ if ( readComments ) {
+ uint index = 8;
+ index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE;
+
+ while(index<f.size()-12)
+ {
+ while (index < f.size() - 12 &&
+ strncmp((char*)CHUNK_TYPE(data,index), "tEXt", 4))
+ {
+ if (!strncmp((char*)CHUNK_TYPE(data,index), "IEND", 4))
+ goto end;
+
+ index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE;
+ }
+
+ if (index < f.size() - 12)
+ {
+ // we found a tEXt 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>=f.size())
+ goto end;
+
+ // 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 > f.size() || onePastLastIndex <= firstIndex)
+ goto end;
+
+ QByteArray arr(textsize);
+ arr = QByteArray(textsize).duplicate((const char*)text,
+ textsize);
+ str += QObject::tr(
+ QString(reinterpret_cast<char*>(key)),
+ QString(arr) );
+
+ index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE;
+ }
+ }
+ }
+ }
+end:
+ delete[] data;
+
+}
+
+
+PNGSlave::PNGSlave()
+ : SlaveInterface("png")
+{
+}
+PNGSlave::~PNGSlave() {
+}
+QString PNGSlave::iconViewName( const QString& path) {
+ QString str;
+ read_comment( path, false, str );
+ return str;
+}
+
+QString PNGSlave::fullImageInfo( const QString& path) {
+ QString str;
+ read_comment( path, true, str );
+ return str;
+}
+
+
+QPixmap PNGSlave::pixmap( const QString& path, int width, int height) {
+ QImage img; img.load( path );
+ if ( img.isNull() )
+ return QPixmap();
+ else
+ return ThumbNailTool::scaleImage( img, width,height );
+}
diff --git a/noncore/graphics/opie-eye/slave/png_slave.h b/noncore/graphics/opie-eye/slave/png_slave.h
new file mode 100644
index 0000000..408bfc4
--- a/dev/null
+++ b/noncore/graphics/opie-eye/slave/png_slave.h
@@ -0,0 +1,21 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ */
+#ifndef PNG_SLAVE_IMPL_H
+#define PNG_SLAVE_IMPL_H
+
+#include "slaveiface.h"
+
+class QString;
+class QPixmap;
+class PNGSlave : public SlaveInterface {
+public:
+ PNGSlave();
+ ~PNGSlave();
+
+ QString iconViewName( const QString& );
+ QString fullImageInfo( const QString& );
+ QPixmap pixmap( const QString&, int, int );
+};
+
+#endif
diff --git a/noncore/graphics/opie-eye/slave/slave.pro b/noncore/graphics/opie-eye/slave/slave.pro
new file mode 100644
index 0000000..3f42495
--- a/dev/null
+++ b/noncore/graphics/opie-eye/slave/slave.pro
@@ -0,0 +1,18 @@
+CONFIG += qte
+TEMPLATE = app
+TARGET = opie-eye_slave
+DESTDIR = $(OPIEDIR)/bin
+
+HEADERS = gif_slave.h slaveiface.h slavereciever.h \
+ thumbnailtool.h png_slave.h jpeg_slave.h \
+ ../iface/slaveiface.h
+SOURCES = main.cpp gif_slave.cpp slavereciever.cpp \
+ slaveiface.cpp thumbnailtool.cpp png_slave.cpp \
+ jpeg_slave.cpp
+
+INCLUDEPATH += $(OPIEDIR)/include ../
+DEPENDSPATH += $(OPIEDIR)/include
+
+LIBS += -lqpe
+
+include ( $(OPIEDIR)/include.pro ) \ No newline at end of file
diff --git a/noncore/graphics/opie-eye/slave/slaveiface.cpp b/noncore/graphics/opie-eye/slave/slaveiface.cpp
new file mode 100644
index 0000000..170f7d5
--- a/dev/null
+++ b/noncore/graphics/opie-eye/slave/slaveiface.cpp
@@ -0,0 +1,26 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ */
+
+#include "slaveiface.h"
+
+static SlaveMap* _slaveMap = 0;
+SlaveMap* slaveMap() {
+ if ( !_slaveMap )
+ _slaveMap = new SlaveMap;
+ return _slaveMap;
+}
+
+SlaveInterface::SlaveInterface( const QStringList& image )
+ : m_list( image )
+{
+
+}
+
+SlaveInterface::~SlaveInterface() {
+
+}
+
+QStringList SlaveInterface::imageFormats()const {
+ return m_list;
+}
diff --git a/noncore/graphics/opie-eye/slave/slaveiface.h b/noncore/graphics/opie-eye/slave/slaveiface.h
new file mode 100644
index 0000000..18656c5
--- a/dev/null
+++ b/noncore/graphics/opie-eye/slave/slaveiface.h
@@ -0,0 +1,53 @@
+/*
+ * GPLv2
+ */
+
+#ifndef P_SLAVE_INTER_FACE_H
+#define P_SLAVE_INTER_FACE_H
+
+#include <qfileinfo.h>
+#include <qstringlist.h>
+#include <qmap.h>
+
+/**
+ * @short The slave worker Interface for generating Preview + Image Info + Full
+ * IMage Info
+ */
+class QPixmap;
+class SlaveInterface {
+public:
+ SlaveInterface(const QStringList& imageformats);
+ virtual ~SlaveInterface();
+
+ QStringList imageFormats()const;
+ bool supports( const QString& )const;
+ virtual QString iconViewName(const QString&) = 0;
+ virtual QString fullImageInfo(const QString& )= 0;
+ virtual QPixmap pixmap( const QString&, int width, int height ) = 0;
+private:
+ QStringList m_list;
+};
+
+inline bool SlaveInterface::supports( const QString& str)const {
+ return m_list.contains( QFileInfo( str ).extension(false) );
+}
+
+typedef SlaveInterface* (*phunkSlaveCreateFunc )();
+typedef QMap<QString,phunkSlaveCreateFunc> SlaveMap;
+
+typedef QMap<QString, SlaveInterface*> SlaveObjects;
+
+SlaveMap* slaveMap();
+SlaveObjects* slaveObjects();
+
+
+
+#define PHUNK_VIEW_INTERFACE( NAME, IMPL ) \
+ static SlaveInterface *create_ ## IMPL() { \
+ return new IMPL(); \
+ } \
+ static SlaveMap::Iterator dummy_ ## IMPL = slaveMap()->insert( NAME, create_ ## IMPL );
+
+
+
+#endif
diff --git a/noncore/graphics/opie-eye/slave/slavereciever.cpp b/noncore/graphics/opie-eye/slave/slavereciever.cpp
new file mode 100644
index 0000000..951f3df
--- a/dev/null
+++ b/noncore/graphics/opie-eye/slave/slavereciever.cpp
@@ -0,0 +1,214 @@
+/*
+ * GPLv2 zecke@handhelds.org
+ */
+
+#include "slavereciever.h"
+#include "slaveiface.h"
+
+#include <qpe/qcopenvelope_qws.h>
+#include <qpe/qpeapplication.h>
+
+#include <qtimer.h>
+
+static SlaveObjects* _slaveObj = 0;
+
+QDataStream & operator << (QDataStream & str, bool b)
+{
+ str << Q_INT8(b);
+ return str;
+}
+
+QDataStream & operator >> (QDataStream & str, bool & b)
+{
+ Q_INT8 l;
+ str >> l;
+ b = bool(l);
+ return str;
+}
+
+
+
+QDataStream &operator<<( QDataStream& s, const PixmapInfo& inf) {
+ return s << inf.file << inf.pixmap << inf.width << inf.height;
+}
+QDataStream &operator>>( QDataStream& s, PixmapInfo& inf ) {
+ s >> inf.file >> inf.pixmap >> inf.width >> inf.height;
+ return s;
+}
+QDataStream &operator<<( QDataStream& s, const ImageInfo& i) {
+ return s << i.kind << i.file << i.info;
+}
+QDataStream &operator>>( QDataStream& s, ImageInfo& i ) {
+ s >> i.kind >> i.file >> i.info;
+ return s;
+}
+
+
+
+SlaveObjects* slaveObjects() {
+ if ( !_slaveObj )
+ _slaveObj = new SlaveObjects;
+ return _slaveObj;
+}
+
+SlaveReciever::SlaveReciever( QObject* par)
+ : QObject( par )
+{
+ m_inf = new QTimer(this);
+ connect(m_inf,SIGNAL(timeout()),
+ this, SLOT(slotImageInfo()));
+ m_pix = new QTimer(this);
+ connect(m_pix,SIGNAL(timeout()),
+ this, SLOT(slotThumbNail()));
+
+ m_out = new QTimer(this);
+ connect(m_out,SIGNAL(timeout()),
+ this, SLOT(slotSend()));
+
+ SlaveObjects *obj = slaveObjects(); // won't be changed
+ SlaveMap::Iterator it;
+ SlaveMap* map = slaveMap(); // SlaveMap won't be changed during execution!!!
+ for(it = map->begin(); it != map->end(); ++it ) {
+ obj->insert( it.key(), (*it.data())() );
+ }
+}
+
+SlaveReciever::~SlaveReciever() {
+}
+
+void SlaveReciever::recieveAnswer( const QCString& string, const QByteArray& ar) {
+ qWarning( "String is %s", string.data() );
+ QDataStream stream(ar, IO_ReadOnly );
+ QStringList lst;
+ static ImageInfo inf;
+ static PixmapInfo pix;
+
+ if ( string == "thumbInfo(QString)" ) {
+ stream >> inf.file;
+ m_inList.append(inf);
+ }else if ( string == "thumbInfos(QStringList)" ) {
+ stream >> lst;
+ for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) {
+ qWarning( "Adding thumbinfo for file "+ *it );
+ inf.file = (*it);
+ m_inList.append(inf);
+ }
+ }else if ( string == "fullInfo(QString)" ) {
+ inf.kind = true;
+ stream >> inf.file;
+ m_inList.append(inf);
+ }else if ( string == "fullInfos(QStringList)" ) {
+ stream >> lst;
+ for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) {
+ qWarning( "Adding fullInfo for"+ *it );
+ inf.file = (*it);
+ inf.kind = true;
+ m_inList.append(inf);
+ }
+ }else if ( string == "pixmapInfo(QString,int,int)" ) {
+ stream >> pix.file >> pix.width >> pix.height;
+ m_inPix.append(pix);
+ }else if ( string == "pixmapInfos(PixmapInfos)" ) {
+ PixmapList list;
+ stream >> list;
+ for(PixmapList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ qWarning( "Got %d %d " + (*it).file, (*it).width , (*it).height );
+ m_inPix.append(*it);
+ }
+ }
+
+ if (!m_inf->isActive() && !m_inList.isEmpty() )
+ m_inf->start(5);
+
+ if (!m_pix->isActive() && !m_inPix.isEmpty() )
+ m_pix->start(5);
+
+ QPEApplication::setKeepRunning();
+
+}
+
+PixmapList SlaveReciever::outPix()const {
+ return m_outPix;
+}
+
+StringList SlaveReciever::outInf()const{
+ return m_outList;
+}
+
+void SlaveReciever::slotImageInfo() {
+ ImageInfo inf = m_inList.first();
+ m_inList.remove( inf );
+
+ static SlaveObjects::Iterator it;
+ static SlaveObjects* map = slaveObjects(); // SlaveMap won't be changed during execution!!!
+ for(it = map->begin(); it != map->end(); ++it ) {
+ if( (*it)->supports(inf.file ) ) {
+ /* full image info */
+ if (inf.kind )
+ inf.info = (*it)->fullImageInfo( inf.file );
+ else
+ inf.info = (*it)->iconViewName( inf.file );
+ m_outList.append( inf );
+ break;
+ }
+ }
+
+ if (m_inList.isEmpty() )
+ m_inf->stop();
+ if (!m_out->isActive() && !m_outList.isEmpty() )
+ m_out->start( 100 );
+}
+
+void SlaveReciever::slotThumbNail() {
+ PixmapInfo inf = m_inPix.first();
+ m_inPix.remove( inf );
+
+ static SlaveObjects::Iterator it;
+ static SlaveObjects* map = slaveObjects(); // SlaveMap won't be changed during execution!!!
+ for(it = map->begin(); it != map->end(); ++it ) {
+ SlaveInterface* iface = it.data();
+ if( iface->supports(inf.file ) ) {
+ /* pixmap */
+ qWarning( "Asking for thumbNail in size %d %d for "+inf.file, inf.width, inf.height );
+ inf.pixmap = iface->pixmap(inf.file, 64, 64);
+ m_outPix.append( inf );
+ break;
+ }
+ }
+
+
+
+ if(m_inPix.isEmpty() )
+ m_pix->stop();
+ if(!m_out->isActive() && !m_outPix.isEmpty() )
+ m_out->start(100);
+}
+
+void SlaveReciever::slotSend() {
+
+ m_out->stop();
+
+ qWarning( "Sending %d %d", outPix().count(), outInf().count() );
+ /* queue it and send */
+ /* if this ever gets a service introduce request queues
+ * so we can differinatate between different clients
+ */
+ if (! m_outPix.isEmpty() ) {
+ QCopEnvelope answer("QPE/opie-eye", "pixmapsHandled(PixmapList)" );
+ answer << outPix();
+ for ( PixmapList::Iterator it = m_outPix.begin();it!=m_outPix.end();++it ) {
+ qWarning( "Sending out %s %d %d", (*it).file.latin1(), (*it).width, (*it).height );
+ }
+ }
+ if ( !m_outList.isEmpty() ) {
+ QCopEnvelope answer("QPE/opie-eye", "pixmapsHandled(StringList)" );
+ answer << outInf();
+ for ( StringList::Iterator it = m_outList.begin();it!=m_outList.end();++it ) {
+ qWarning( "Sending out2 " + (*it).file );
+ }
+ }
+
+ m_outList.clear();
+ m_outPix.clear();
+}
+
diff --git a/noncore/graphics/opie-eye/slave/slavereciever.h b/noncore/graphics/opie-eye/slave/slavereciever.h
new file mode 100644
index 0000000..214bfc6
--- a/dev/null
+++ b/noncore/graphics/opie-eye/slave/slavereciever.h
@@ -0,0 +1,58 @@
+/*
+ * GPLv2
+ */
+
+
+#ifndef SLAVE_RECEIVER_H
+#define SLAVE_RECEIVER_H
+
+/**
+ * Receive Requests
+ */
+
+#include <iface/slaveiface.h>
+
+#include <qobject.h>
+#include <qdatastream.h>
+#include <qstringlist.h>
+#include <qvaluelist.h>
+#include <qpixmap.h>
+
+
+
+typedef QValueList<PixmapInfo> PixmapList;
+typedef QValueList<ImageInfo> StringList;
+
+class QTimer;
+class QSocket;
+class SlaveReciever : public QObject {
+ Q_OBJECT
+
+ friend QDataStream &operator<<( QDataStream&, const PixmapInfo& );
+ friend QDataStream &operator>>( QDataStream&, PixmapInfo& );
+ friend QDataStream &operator<<( QDataStream&, const ImageInfo& );
+ friend QDataStream &operator>>( QDataStream&, ImageInfo );
+public:
+
+ enum Job { ImageInfoJob, FullImageInfoJob, ThumbNailJob };
+ SlaveReciever( QObject* parent );
+ ~SlaveReciever();
+
+public slots:
+ void recieveAnswer( const QCString&, const QByteArray& );
+public:
+ PixmapList outPix()const;
+ StringList outInf()const;
+
+private slots:
+ void slotSend();
+ void slotImageInfo();
+ void slotThumbNail();
+private:
+ QTimer *m_inf, *m_pix, *m_out;
+ StringList m_inList, m_outList;
+ PixmapList m_inPix, m_outPix;
+};
+
+
+#endif
diff --git a/noncore/graphics/opie-eye/slave/thumbnailtool.cpp b/noncore/graphics/opie-eye/slave/thumbnailtool.cpp
new file mode 100644
index 0000000..a202457
--- a/dev/null
+++ b/noncore/graphics/opie-eye/slave/thumbnailtool.cpp
@@ -0,0 +1,61 @@
+#include "thumbnailtool.h"
+
+#include <qfileinfo.h>
+#include <qdir.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qstring.h>
+
+static bool makeThumbDir( const QFileInfo& inf, bool make = false) {
+ QDir dir( inf.dirPath()+ "/.opie-eye" );
+ if ( !dir.exists() )
+ if ( make )
+ return dir.mkdir(QString::null);
+ else
+ return false;
+ return true;
+}
+
+
+/*
+ * check if the Opie opie-eye dir exists
+ * check if a thumbnail exists
+ * load the thumbnail
+ * /foo/bar/imagefoo.gif
+ * check for a png in /foo/bar/.opie-eye/%dx%d-imagefoo.gif
+ */
+QPixmap ThumbNailTool::getThumb( const QString& path, int width, int height ) {
+ QFileInfo inf( path );
+ qWarning( "Get Thumb" );
+ if ( !makeThumbDir( inf ) ) {
+ QPixmap pix;
+ return pix;
+ }
+ QString str = QString( "/.opie-eye/%1x%2-%3" ).arg( width ).arg( height ).arg( inf.fileName() );
+ qWarning( inf.dirPath()+str );
+ return QPixmap( inf.dirPath()+str,"PNG" );
+
+}
+
+void ThumbNailTool::putThumb( const QString& path, const QPixmap& pix, int width, int height ) {
+ QFileInfo inf( path );
+ makeThumbDir( inf, true );
+ QString str = QString( "/.opie-eye/%1x%2-%3" ).arg( width ).arg( height ).arg( inf.fileName() );
+ qWarning( inf.dirPath()+str );
+ pix.save( inf.dirPath()+str, "PNG" );
+}
+
+
+QPixmap ThumbNailTool::scaleImage( QImage& img, int w, int h ) {
+ double hs = (double)h / (double)img.height() ;
+ double ws = (double)w / (double)img.width() ;
+ double scaleFactor = (hs > ws) ? ws : hs;
+ int smoothW = (int)(scaleFactor * img.width());
+ int smoothH = (int)(scaleFactor * img.height());
+ QPixmap pixmap;
+ if ( img.width() <= w && img.height() <= h )
+ pixmap.convertFromImage( img );
+ else
+ pixmap.convertFromImage( img.smoothScale( smoothW, smoothH) );
+ return pixmap;
+}
diff --git a/noncore/graphics/opie-eye/slave/thumbnailtool.h b/noncore/graphics/opie-eye/slave/thumbnailtool.h
new file mode 100644
index 0000000..4d0a30f
--- a/dev/null
+++ b/noncore/graphics/opie-eye/slave/thumbnailtool.h
@@ -0,0 +1,19 @@
+/*
+ * GPLv2
+ */
+
+#ifndef THUMB_NAIL_TOOL_H
+#define THUMB_NAIL_TOOL_H
+class QString;
+class QPixmap;
+class QImage;
+
+struct ThumbNailTool {
+ static QPixmap scaleImage( QImage&, int width, int height );
+/* get one isInvalid() if non found */
+ static QPixmap getThumb( const QString&, int width, int height );
+/* put one */
+ static void putThumb( const QString&, const QPixmap&, int width, int heigh );
+};
+
+#endif