summaryrefslogtreecommitdiff
authorzecke <zecke>2004-03-22 23:32:41 (UTC)
committer zecke <zecke>2004-03-22 23:32:41 (UTC)
commit428b687982966dc2efabaf6dbcc55ad0ea30aa10 (patch) (unidiff)
tree86da20abd2e4b97a59dc32e17996bde5ee74cc91
parent7ce623c6351646ce738a81e103632d73c5454ecc (diff)
downloadopie-428b687982966dc2efabaf6dbcc55ad0ea30aa10.zip
opie-428b687982966dc2efabaf6dbcc55ad0ea30aa10.tar.gz
opie-428b687982966dc2efabaf6dbcc55ad0ea30aa10.tar.bz2
Initial Check in of the Eye Of Zilla. This ImageViewer features
Image Infos, EXIF, Jpeg,Png,Gif support. It supports scaled loading of Jpegs. an smart image cache.... GUI needs some work and we need to find a bug in QCOP as well. TODO: Add Image Service for example Mailer Add ImageCanvas/Zoomer/Display
Diffstat (more/less context) (ignore 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 @@
1The Design of the Eye Caramba Opie Image Viewer.
2
3It consists out of several Parts:
4
51.) A interface for Getting Information, Files and Requesting Pixmap and the Full Image
62.) A ImageCache which uses the current Interface to request the Pixmap in the given side
7 (the gui will listen to the slot and insert the image )
83.) A small library which gives the Image Info and Pixmap. Internally it'll have a forked slave
9 to do the actual work. It'll also write thumbnails.
104.) The Interface parts are designed for stuff like FileSystem View or Digi Cam support which would
11 read thumbnail from different locations
12
13
14
15TODO:
16 - Special QIconListViewItem painting routines to include BEAM,Rename,Delete,Rotate buttons
17 - Create SlideShows
18 -Add from View. Will ask to add to a slide show
19 -And special slideshow widget for the order
20 -Save in Config within AppDir of eyecaramba
21
22
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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 * No WArranty...
4 */
5
6#include <qpopupmenu.h>
7#include <qtoolbar.h>
8
9#include <qpe/resource.h>
10#include <qpe/storage.h>
11
12
13#include "filesystem.h"
14
15PFileSystem::PFileSystem( QToolBar* bar)
16 : QToolButton( bar )
17{
18 setIconSet( Resource::loadIconSet( "cardmon/pcmcia" ) );
19
20 m_pop = new QPopupMenu( this );
21 connect( m_pop, SIGNAL( activated( int ) ),
22 this, SLOT(slotSelectDir( int ) ) );
23
24 m_storage = new StorageInfo();
25 connect(m_storage, SIGNAL(disksChanged() ),
26 this, SLOT( changed() ) );
27 changed();
28
29 setPopup( m_pop );
30}
31
32PFileSystem::~PFileSystem() {
33 delete m_storage;
34}
35
36
37void PFileSystem::changed() {
38 m_pop->clear();
39 m_dev.clear();
40 const QList<FileSystem> &fs = m_storage->fileSystems();
41 QListIterator<FileSystem> it(fs );
42 for ( ; it.current(); ++it ) {
43 const QString disk = (*it)->name();
44 const QString path = (*it)->path();
45 m_dev.insert( disk, path );
46 m_pop->insertItem( disk );
47 }
48}
49
50void PFileSystem::slotSelectDir( int id ) {
51 emit changeDir( m_dev[m_pop->text(id )] );
52}
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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 * No WArranty...
4 */
5
6#ifndef PHUNK_FILE_SYSTEM_H
7#define PHUNK_FILE_SYSTEM_H
8
9#include <qtoolbutton.h>
10#include <qmap.h>
11
12class QPopupMenu;
13class StorageInfo;
14class PFileSystem : public QToolButton {
15 Q_OBJECT
16public:
17 PFileSystem( QToolBar* );
18 ~PFileSystem();
19
20signals:
21 void changeDir( const QString& );
22
23private slots:
24 void slotSelectDir( int );
25 void changed();
26
27private:
28 QPopupMenu* m_pop;
29 StorageInfo *m_storage;
30 QMap<QString, QString> m_dev;
31};
32
33
34#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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 * No WArranty...
4 */
5
6#include "iconview.h"
7
8#include <lib/imagecache.h>
9
10#include <iface/dirview.h>
11#include <iface/dirlister.h>
12
13#include <qpe/config.h>
14#include <qpe/resource.h>
15#include <qpe/qpemessagebox.h>
16#include <qpe/ir.h>
17#include <qpe/qcopenvelope_qws.h>
18
19#include <qiconview.h>
20#include <qlabel.h>
21#include <qhbox.h>
22#include <qcombobox.h>
23#include <qdir.h>
24#include <qapplication.h>
25#include <qmainwindow.h>
26#include <qtimer.h>
27#include <qstyle.h>
28
29
30
31namespace {
32 QPixmap* _dirPix = 0;
33 QPixmap* _unkPix = 0;
34 class IconViewItem : public QIconViewItem {
35 public:
36 IconViewItem( QIconView*, const QString& path, const QString& name, bool isDir = false);
37 QPixmap* pixmap()const;
38 QString path()const { return m_path; }
39 bool isDir()const { return m_isDir; }
40 void setText( const QString& );
41 private:
42 mutable QPixmap* m_pix;
43 QString m_path;
44 bool m_isDir : 1;
45 bool m_noInfo :1;
46 };
47
48
49/*
50 * If we request an Image or String
51 * we add it to the map
52 */
53 QMap<QString, IconViewItem*> g_stringInf;
54 QMap<QString, IconViewItem*> g_stringPix;
55
56 IconViewItem::IconViewItem( QIconView* view,const QString& path,
57 const QString& name, bool isDir )
58 : QIconViewItem( view ), m_path( path ), m_isDir( isDir ),
59 m_noInfo( false )
60 {
61 QIconViewItem::setText( name );
62 if ( isDir && !_dirPix )
63 _dirPix = new QPixmap( Resource::loadPixmap("advancedfm/FileBrowser"));
64 else if ( !isDir && !_unkPix )
65 _unkPix = new QPixmap( Resource::loadPixmap( "UnknownDocument" ) );
66 }
67 inline QPixmap* IconViewItem::pixmap()const {
68 if ( m_isDir )
69 return _dirPix;
70 else{
71 if (!m_noInfo && !g_stringInf.contains( m_path ) ) {
72 currentView()->dirLister()->imageInfo( m_path );
73 g_stringInf.insert( m_path, const_cast<IconViewItem*>(this));
74 }
75
76 m_pix = PPixmapCache::self()->cachedImage( m_path, 64, 64 );
77 if ( !m_pix && !g_stringPix.contains( m_path )) {
78 currentView()->dirLister()->thumbNail( m_path, 64, 64 );
79 g_stringPix.insert( m_path, const_cast<IconViewItem*>(this));
80 }
81 return m_pix ? m_pix : _unkPix;
82 }
83 }
84 inline void IconViewItem::setText( const QString& str ) {
85 QString text = QIconViewItem::text()+"\n"+str;
86 m_noInfo = true;
87 QIconViewItem::setText( text );
88 }
89}
90
91
92PIconView::PIconView( QWidget* wid, Config* cfg )
93 : QVBox( wid ), m_cfg( cfg )
94{
95 {
96 QCopEnvelope( "QPE/Application/opie-eye_slave", "foo()" );
97 }
98 m_path = QDir::homeDirPath();
99
100 QHBox *hbox = new QHBox( this );
101 QLabel* lbl = new QLabel( hbox );
102 lbl->setText( tr("View as" ) );
103
104 m_views = new QComboBox( hbox, "View As" );
105 connect( m_views, SIGNAL(activated(int)),
106 this, SLOT(slotViewChanged(int)) );
107
108 m_view= new QIconView( this );
109 connect(m_view, SIGNAL(clicked(QIconViewItem*) ),
110 this, SLOT(slotClicked(QIconViewItem*)) );
111
112 m_view->setArrangement( QIconView::LeftToRight );
113 m_view->setItemTextPos( QIconView::Right );
114
115
116 int dw = QApplication::desktop()->width();
117 int viewerWidth = dw-style().scrollBarExtent().width();
118 m_view->setGridX( viewerWidth-2*m_view->spacing() );
119 m_view->setGridY( fontMetrics().height()*2+40 );
120 loadViews();
121 slotViewChanged( m_views->currentItem() );
122}
123
124PIconView::~PIconView() {
125}
126
127void PIconView::slotDirUp() {
128 QDir dir( m_path );
129 dir.cdUp();
130 slotChangeDir( dir.absPath() );
131
132}
133
134void PIconView::slotChangeDir(const QString& path) {
135 if ( !currentView() )
136 return;
137
138 PDirLister *lister = currentView()->dirLister();
139 if (!lister )
140 return;
141
142 lister->setStartPath( path );
143 m_path = lister->currentPath();
144
145 m_view->clear();
146 addFolders( lister->folders() );
147 addFiles( lister->files() );
148
149 // looks ugly
150 static_cast<QMainWindow*>(parent())->setCaption( QObject::tr("%1 - O View", "Name of the dir").arg( m_path ) );
151}
152
153QString PIconView::currentFileName(bool &isDir)const {
154 isDir = false;
155 QIconViewItem* _it = m_view->currentItem();
156 if ( !_it )
157 return QString::null;
158
159 IconViewItem* it = static_cast<IconViewItem*>( _it );
160 isDir = it->isDir();
161 return it->path();
162}
163
164void PIconView::slotTrash() {
165 bool isDir;
166 QString pa = currentFileName( isDir );
167 if ( isDir && pa.isEmpty() )
168 return;
169
170 if (!QPEMessageBox::confirmDelete( this,
171 tr("Delete Image" ),
172 tr("the Image %1" ).arg(pa)))
173 return
174
175
176 currentView()->dirLister()->deleteImage( pa );
177 delete m_view->currentItem();
178}
179void PIconView::loadViews() {
180 ViewMap::Iterator it;
181 ViewMap* map = viewMap();
182 for ( it = map->begin(); it != map->end(); ++it )
183 m_views->insertItem( QObject::tr(it.key() ) );
184}
185
186void PIconView::resetView() {
187 slotViewChanged(m_views->currentItem());
188}
189
190void PIconView::slotViewChanged( int i) {
191 if (!m_views->count() ) {
192 setCurrentView( 0l);
193 return;
194 }
195
196 PDirView* cur = currentView();
197 delete cur;
198 QString str = m_views->text(i);
199 cur = (*(*viewMap())[str])(*m_cfg);
200 setCurrentView( cur );
201
202 /* connect to the signals of the lister */
203 PDirLister* lis = cur->dirLister();
204 connect(lis, SIGNAL(sig_thumbInfo(const QString&, const QString& )),
205 this, SLOT( slotThumbInfo(const QString&, const QString&)));
206 connect(lis, SIGNAL( sig_thumbNail(const QString&, const QPixmap&)),
207 this, SLOT(slotThumbNail(const QString&, const QPixmap&)));
208 connect(lis, SIGNAL(sig_start()),
209 this, SLOT(slotStart()));
210 connect(lis, SIGNAL(sig_end()) ,
211 this, SLOT(slotEnd()) );
212
213
214 /* reload now */
215 QTimer::singleShot( 0, this, SLOT(slotReloadDir()));
216}
217
218
219void PIconView::slotReloadDir() {
220 slotChangeDir( m_path );
221}
222
223
224void PIconView::addFolders( const QStringList& lst) {
225 QStringList::ConstIterator it;
226
227 for(it=lst.begin(); it != lst.end(); ++it ) {
228 (void)new IconViewItem( m_view, m_path+"/"+(*it), (*it), true );
229 }
230
231}
232
233void PIconView::addFiles( const QStringList& lst) {
234 QStringList::ConstIterator it;
235 for (it=lst.begin(); it!= lst.end(); ++it )
236 (void)new IconViewItem( m_view, m_path+"/"+(*it), (*it) );
237
238}
239
240void PIconView::slotClicked(QIconViewItem* _it) {
241 if(!_it )
242 return;
243
244 IconViewItem* it = static_cast<IconViewItem*>(_it);
245 if( it->isDir() )
246 slotChangeDir( it->path() );
247 else // view image
248 ;
249}
250
251void PIconView::slotThumbInfo( const QString& _path, const QString& str ) {
252 if ( g_stringInf.contains( _path ) ) {
253 IconViewItem* item = g_stringInf[_path];
254 item->setText( str );
255 item->repaint();
256 g_stringInf.remove( _path );
257 }
258}
259void PIconView::slotThumbNail(const QString& _path, const QPixmap &pix) {
260 if ( g_stringPix.contains( _path ) ) {
261 IconViewItem* item = g_stringPix[_path];
262 PPixmapCache::self()->insertImage( _path, pix, 64, 64 );
263 item->repaint();
264 g_stringPix.remove( _path );
265 }
266}
267
268
269void PIconView::slotRename() {
270
271}
272
273void PIconView::slotBeam() {
274 bool isDir;
275 QString pa = currentFileName( isDir );
276 if ( isDir && pa.isEmpty() )
277 return;
278
279 Ir* ir = new Ir( this );
280 connect( ir, SIGNAL(done(Ir*)),
281 this, SLOT(slotBeamDone(Ir*)));
282 ir->send(pa, tr( "Image" ) );
283
284}
285
286void PIconView::slotBeamDone( Ir* ir) {
287 delete ir;
288}
289
290void PIconView::slotStart() {
291 m_view->setUpdatesEnabled( false );
292}
293
294void PIconView::slotEnd() {
295 m_view->setUpdatesEnabled( true );
296}
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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 * No WArranty...
4 */
5
6#ifndef PHUNK_ICON_VIEW_H
7#define PHUNK_ICON_VIEW_H
8
9#include <qvbox.h>
10
11#include <qpe/config.h>
12
13class QIconView;
14class QIconViewItem;
15class QComboBox;
16class PIconViewItem;
17class PDirLister;
18class Ir;
19class PIconView : public QVBox {
20 Q_OBJECT
21 friend class PIconViewItem;
22public:
23 PIconView( QWidget* wid, Config *cfg );
24 ~PIconView();
25 void resetView();
26
27private:
28 QString currentFileName(bool &isDir)const;
29 void loadViews();
30
31private slots:
32 void slotDirUp();
33 void slotChangeDir(const QString&);
34 void slotTrash();
35 void slotViewChanged( int );
36 void slotReloadDir();
37 void slotRename();
38 void slotBeam();
39 void slotBeamDone( Ir* );
40
41 void slotStart();
42 void slotEnd();
43
44/* for performance reasons make it inline in the future */
45 void addFolders( const QStringList& );
46 void addFiles( const QStringList& );
47 void slotClicked(QIconViewItem* );
48
49/**/
50 void slotThumbInfo(const QString&, const QString&);
51 void slotThumbNail(const QString&, const QPixmap&);
52private:
53 Config *m_cfg;
54 QComboBox* m_views;
55 QIconView* m_view;
56 QString m_path;
57};
58
59#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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 * No WArranty...
4 */
5
6#include <qtoolbar.h>
7#include <qtoolbutton.h>
8#include <qlayout.h>
9#include <qdialog.h>
10#include <qmap.h>
11
12#include <qpe/resource.h>
13#include <qpe/config.h>
14#include <qpe/ir.h>
15
16#include <opie/oapplicationfactory.h>
17#include <opie/otabwidget.h>
18
19#include <iface/ifaceinfo.h>
20#include <iface/dirview.h>
21
22#include "iconview.h"
23#include "filesystem.h"
24
25#include "mainwindow.h"
26
27OPIE_EXPORT_APP( OApplicationFactory<PMainWindow> )
28
29PMainWindow::PMainWindow(QWidget* wid, const char* name, WFlags style)
30 : QMainWindow( wid, name, style ), m_cfg("phunkview")
31{
32 setCaption( QObject::tr("Opie Eye Caramba" ) );
33 m_cfg.setGroup("Zecke_view" );
34 /*
35 * Initialize ToolBar and IconView
36 * And Connect Them
37 */
38 QToolBar *bar = new QToolBar( this );
39 bar->setHorizontalStretchable( true );
40 setToolBarsMovable( false );
41
42 m_view = new PIconView( this, &m_cfg );
43 setCentralWidget( m_view );
44
45 QToolButton *btn = new QToolButton( bar );
46 btn->setIconSet( Resource::loadIconSet( "up" ) );
47 connect( btn, SIGNAL(clicked()),
48 m_view, SLOT(slotDirUp()) );
49
50 btn = new PFileSystem( bar );
51 connect( btn, SIGNAL( changeDir( const QString& ) ),
52 m_view, SLOT(slotChangeDir( const QString& ) ) );
53
54 btn = new QToolButton( bar );
55 btn->setIconSet( Resource::loadIconSet( "edit" ) );
56 connect( btn, SIGNAL(clicked()),
57 m_view, SLOT(slotRename()) );
58
59 if ( Ir::supported() ) {
60 btn = new QToolButton( bar );
61 btn->setIconSet( Resource::loadIconSet( "beam" ) );
62 connect( btn, SIGNAL(clicked()),
63 m_view, SLOT(slotBeam()) );
64 }
65
66 btn = new QToolButton( bar );
67 btn->setIconSet( Resource::loadIconSet( "trash" ) );
68 connect( btn, SIGNAL(clicked() ),
69 m_view, SLOT(slotTrash() ) );
70
71 btn = new QToolButton( bar );
72 btn->setIconSet( Resource::loadIconSet( "SettingsIcon" ) );
73 connect( btn, SIGNAL(clicked() ),
74 this, SLOT(slotConfig() ) );
75
76}
77
78PMainWindow::~PMainWindow() {
79}
80
81
82void PMainWindow::slotConfig() {
83 QDialog dlg(this, 0, true);
84 dlg.setCaption( tr("Phunk View - Config" ) );
85
86 QHBoxLayout *lay = new QHBoxLayout(&dlg);
87 OTabWidget *wid = new OTabWidget(&dlg );
88 lay->addWidget( wid );
89 ViewMap *vM = viewMap();
90 ViewMap::Iterator _it = vM->begin();
91 QMap<PDirView*, QWidget*> lst;
92
93 for( ; _it != vM->end(); ++_it ) {
94 PDirView *view = (_it.data())(m_cfg);
95 PInterfaceInfo *inf = view->interfaceInfo();
96 QWidget *_wid = inf->configWidget( m_cfg );
97 _wid->reparent(wid, QPoint() );
98 lst.insert( view, _wid );
99 wid->addTab( _wid, QString::null, inf->name() );
100 }
101
102 dlg.showMaximized();
103 bool act = ( dlg.exec() == QDialog::Accepted );
104
105 QMap<PDirView*, QWidget*>::Iterator it;
106 for ( it = lst.begin(); it != lst.end(); ++it ) {
107 if ( act )
108 it.key()->interfaceInfo()->writeConfig(it.data(), m_cfg);
109 delete it.key();
110 }
111
112 if ( act )
113 m_view->resetView();
114}
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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 * No WArranty...
4 */
5
6#ifndef PHUNK_MAIN_WINDOW_H
7#define PHUNK_MAIN_WINDOW_H
8
9#include <qmainwindow.h>
10
11#include <qpe/config.h>
12
13class PIconView;
14class PMainWindow : public QMainWindow {
15 Q_OBJECT
16public:
17 static QString appName() { return QString::fromLatin1("opie-eye" ); }
18 PMainWindow(QWidget*, const char*, WFlags );
19 ~PMainWindow();
20
21private:
22 Config m_cfg;
23 PIconView* m_view;
24
25private slots:
26 void slotConfig();
27};
28
29#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 @@
1#include <iface/dirview.h>
2
3namespace {
4 ViewMap m_view;
5}
6
7ViewMap* viewMap() {
8 return m_view;
9}
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 @@
1#include "dirlister.h"
2
3
4PDirLister::PDirLister( const char* name )
5 : QObject( 0, name )
6{}
7
8PDirLister::~PDirLister()
9{}
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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 * No WArranty...
4 */
5
6#ifndef PHUNK_DIR_LISTER_H
7#define PHUNK_DIR_LISTER_H
8
9#include <qobject.h>
10#include <qstring.h>
11#include <qstringlist.h>
12
13
14class PDirLister : public QObject {
15 Q_OBJECT
16public:
17 enum Factor { Width, Height, None };
18
19 PDirLister( const char* name );
20
21 virtual QString defaultPath()const = 0;
22 virtual QString setStartPath( const QString& ) = 0;
23 virtual QString currentPath()const = 0;
24 virtual QStringList folders()const = 0;
25 virtual QStringList files()const = 0;
26public slots:
27 virtual void deleteImage( const QString& ) = 0;
28 virtual void imageInfo( const QString&) = 0;
29 virtual void fullImageInfo( const QString& ) = 0;
30 virtual void thumbNail( const QString&, int max_wid, int max_h ) = 0;
31 virtual QImage image( const QString&, Factor, int max = 0) = 0;
32
33signals:
34 void sig_dirchanged();
35 void sig_filechanged();
36 void sig_start();
37 void sig_end();
38// If this app ever happens to get multithreaded...
39 void sig_thumbInfo( const QString&, const QString& );
40 void sig_fullInfo( const QString&, const QString& );
41 void sig_thumbNail( const QString&, const QPixmap& );
42
43protected:
44 ~PDirLister();
45};
46
47#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 @@
1#include "dirview.h"
2
3PDirView::PDirView( const Config& ) {
4
5}
6
7PDirView::~PDirView() {
8
9}
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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 * No WArranty...
4 */
5
6#ifndef PHUNK_DIR_VIEW_H
7#define PHUNK_DIR_VIEW_H
8
9#include <qmap.h>
10
11#include <qpe/config.h>
12
13class PInterfaceInfo;
14class PDirLister;
15
16struct PDirView {
17 PDirView( const Config& );
18 virtual ~PDirView();
19 virtual PInterfaceInfo* interfaceInfo()const = 0;
20 virtual PDirLister* dirLister()const = 0;
21};
22
23typedef PDirView* (*phunkViewCreateFunc )(const Config& );
24typedef QMap<QString,phunkViewCreateFunc> ViewMap;
25
26ViewMap* viewMap();
27PDirView* currentView();
28void setCurrentView( PDirView* );
29
30
31
32#define PHUNK_VIEW_INTERFACE( NAME, IMPL ) \
33 static PDirView *create_ ## IMPL( const Config& cfg ) { \
34 return new IMPL( cfg ); \
35 } \
36 static ViewMap::Iterator dummy_ ## IMPL = viewMap()->insert( NAME, create_ ## IMPL );
37
38
39
40#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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 * No WArranty...
4 */
5
6#ifndef PHUNK_INTERFACE_INFO_H
7#define PHUNK_INTERFACE_INFO_H
8
9#include <qstring.h>
10
11class QWidget;
12class Config;
13struct PInterfaceInfo {
14 virtual QString name()const = 0;
15 virtual QWidget* configWidget( const Config& ) = 0;
16 virtual void writeConfig( QWidget* wid, Config& ) = 0;
17};
18
19#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 @@
1/*
2 *GPLv2
3 */
4
5#ifndef SLAVE_INTERFACE_H
6#define SLAVE_INTERFACE_H
7
8#include <qpixmap.h>
9#include <qstring.h>
10
11/**
12 * The Data Packets we use
13 */
14
15struct ImageInfo {
16 ImageInfo() : kind(false){}
17 bool operator==( const ImageInfo other ) {
18 if ( kind != other.kind ) return false;
19 if ( file != other.file ) return false;
20 return true;
21 }
22 bool kind;
23 QString file;
24 QString info;
25};
26
27struct PixmapInfo {
28 PixmapInfo() : width( -1 ), height( -1 ) {}
29 bool operator==( const PixmapInfo& r ) {
30 if ( width != r.width ) return false;
31 if ( height != r.height ) return false;
32 if ( file != r.file ) return false;
33 return true;
34 }
35 int width, height;
36 QString file;
37 QPixmap pixmap;
38};
39
40
41/*
42 * Image Infos
43 */
44
45
46
47#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 @@
1#include "dir_lister.h"
2#include "dir_ifaceinfo.h"
3#include "dir_dirview.h"
4
5PHUNK_VIEW_INTERFACE("Dir View", Dir_DirView );
6
7
8Dir_DirView::Dir_DirView( const Config& cfg)
9 : PDirView(cfg)
10{
11 m_cfg = cfg.readBoolEntry( "Dir_Check_All_Files", true);
12 m_lister = 0;
13 m_info = 0;
14}
15
16Dir_DirView::~Dir_DirView() {
17}
18
19PInterfaceInfo* Dir_DirView::interfaceInfo()const{
20 if (!m_info )
21 m_info =new DirInterfaceInfo;
22 return m_info;
23}
24
25PDirLister* Dir_DirView::dirLister()const{
26 if (!m_lister )
27 m_lister = new Dir_DirLister(m_cfg);
28 return m_lister;
29}
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 @@
1/*
2 * GPLv2 only zecke@handhelds.org
3 */
4
5#ifndef DIR_DIR_VIEW_H
6#define DIR_DIR_VIEW_H
7
8#include <iface/dirview.h>
9
10
11struct Dir_DirView : public PDirView {
12 Dir_DirView( const Config& );
13 ~Dir_DirView();
14
15 PInterfaceInfo* interfaceInfo()const;
16 PDirLister* dirLister()const;
17private:
18 bool m_cfg : 1;
19 mutable PDirLister* m_lister;
20 mutable PInterfaceInfo *m_info;
21};
22
23
24#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 @@
1/*
2 * GPLv2
3 * zecke@handhelds.org
4 */
5
6#ifndef DIR_IFACE_INFO_H
7#define DIR_IFACE_INFO_H
8
9#include <iface/ifaceinfo.h>s
10
11class DirInterfaceInfo : public PInterfaceInfo {
12public:
13 DirInterfaceInfo();
14 ~DirInterfaceInfo();
15
16 QString name()const;
17 QWidget* configWidget(const Config&);
18 void writeConfig( QWidget* wid, Config& );
19};
20
21#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 @@
1/*
2 * GPLv2
3 * zecke@handhelds.org
4 */
5
6#include <qwidget.h>
7#include <qcheckbox.h>
8#include <qhbox.h>
9#include <qlabel.h>
10
11#include <qpe/config.h>
12
13#include "dir_ifaceinfo.h"
14
15namespace {
16 class DirImageWidget : public QHBox {
17 public:
18 DirImageWidget() {
19 chkbox = new QCheckBox( QObject::tr("Show all files"), this );
20 }
21 ~DirImageWidget() {}
22 QCheckBox* chkbox;
23 };
24}
25
26
27DirInterfaceInfo::DirInterfaceInfo() {
28}
29DirInterfaceInfo::~DirInterfaceInfo() {
30}
31
32QString DirInterfaceInfo::name()const {
33 return QString::fromLatin1(QObject::tr("DirView" ));
34}
35
36QWidget* DirInterfaceInfo::configWidget(const Config& cfg) {
37 DirImageWidget* wid = new DirImageWidget();
38 wid->chkbox->setChecked( cfg.readBoolEntry("Dir_Check_All_Files", true) );
39
40 return wid;
41}
42
43void DirInterfaceInfo::writeConfig( QWidget* _wid, Config& cfg) {
44 qWarning( "Write Config" );
45 DirImageWidget* wid = static_cast<DirImageWidget*>(_wid);
46 cfg.writeEntry("Dir_Check_All_Files", wid->chkbox->isChecked() );
47}
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 @@
1/*
2 * GPLv2
3 * zecke@handhelds.org
4 */
5
6#ifndef DIR_IFACE_INFO_H
7#define DIR_IFACE_INFO_H
8
9#include <iface/ifaceinfo.h>
10
11class DirInterfaceInfo : public PInterfaceInfo {
12public:
13 DirInterfaceInfo();
14 virtual ~DirInterfaceInfo();
15
16 QString name()const;
17 QWidget* configWidget(const Config&);
18 void writeConfig( QWidget* wid, Config& );
19};
20
21#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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 */
4
5#include "dir_lister.h"
6
7#include <lib/slavemaster.h>
8
9
10#include <qpe/config.h>
11#include <qpe/qpeapplication.h>
12
13#include <qdir.h>
14#include <qfileinfo.h>
15
16
17Dir_DirLister::Dir_DirLister( bool list )
18 : PDirLister( "dir_dir_lister" )
19{
20 m_allFiles = list;
21 qWarning("All Files %d", m_allFiles );
22
23 SlaveMaster* master = SlaveMaster::self();
24 connect( master, SIGNAL(sig_start()), this, SIGNAL(sig_start()) );
25 connect( master, SIGNAL(sig_end()), this, SIGNAL(sig_end()) );
26 connect( master, SIGNAL(sig_thumbInfo(const QString&, const QString&)),
27 this, SIGNAL(sig_thumbInfo(const QString&, const QString&)) );
28 connect( master, SIGNAL(sig_fullInfo(const QString&, const QString&)),
29 this, SIGNAL(sig_fullInfo(const QString&, const QString&)) );
30 connect( master, SIGNAL(sig_thumbNail(const QString&, const QPixmap&)),
31 this, SIGNAL(sig_thumbNail(const QString&, const QPixmap&)) );
32
33}
34
35QString Dir_DirLister::defaultPath()const {
36 return QPEApplication::documentDir();
37}
38
39QString Dir_DirLister::setStartPath( const QString& path ) {
40 m_currentDir.cd( path );
41 if (!m_currentDir.exists() )
42 m_currentDir.cd(defaultPath());
43
44
45 return m_currentDir.absPath();
46}
47
48QString Dir_DirLister::currentPath()const {
49 return m_currentDir.absPath();
50}
51
52
53QStringList Dir_DirLister::folders()const {
54 return m_currentDir.entryList( QDir::Dirs );
55}
56
57QStringList Dir_DirLister::files()const {
58 if ( m_allFiles )
59 return m_currentDir.entryList( QDir::Files );
60 else {
61 QStringList out;
62 QStringList list = m_currentDir.entryList( QDir::Files | QDir::Readable );
63 for (QStringList::Iterator it = list.begin(); it != list.end();++it ) {
64 QFileInfo inf( *it );
65 QString ext = inf.extension(false).lower();
66 if( ext == QString::fromLatin1("jpg") ||
67 ext == QString::fromLatin1("jpeg" ) ||
68 ext == QString::fromLatin1("png" ) ||
69 ext == QString::fromLatin1("gif" ) )
70 out.append( *it );
71 }
72 return out;
73 }
74}
75
76void Dir_DirLister::deleteImage( const QString& fl) {
77 QFile::remove( fl );
78}
79
80void Dir_DirLister::thumbNail( const QString& str, int w, int h) {
81 SlaveMaster::self()->thumbNail( str, w, h );
82}
83
84QImage Dir_DirLister::image( const QString& str, Factor f, int m) {
85 return SlaveMaster::self()->image( str, f, m );
86}
87
88void Dir_DirLister::imageInfo( const QString& str) {
89 SlaveMaster::self()->thumbInfo( str );
90}
91
92void Dir_DirLister::fullImageInfo( const QString& str) {
93 SlaveMaster::self()->imageInfo( str );
94}
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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 */
4
5#ifndef DIR_LISTER_INTERFACE_LISTER_H
6#define DIR_LISTER_INTERFACE_LISTER_H
7
8#include <qdir.h>
9
10#include <iface/dirlister.h>
11
12class Config;
13class Dir_DirLister : public PDirLister {
14public:
15 Dir_DirLister( bool );
16
17 QString defaultPath()const;
18 QString setStartPath( const QString& );
19 QString currentPath()const;
20 QStringList folders()const;
21 QStringList files()const;
22
23 void deleteImage( const QString& );
24 void thumbNail( const QString&, int, int );
25 QImage image( const QString&, Factor, int );
26 void imageInfo( const QString& );
27 void fullImageInfo( const QString& );
28
29private:
30 bool m_allFiles;
31 QDir m_currentDir;
32};
33
34#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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 * No WArranty...
4 */
5
6#include <iface/dirview.h>
7#include <iface/dirlister.h>
8
9#include "imagecache.h"
10
11namespace {
12 PImageCache * _imgCache = 0;
13 PPixmapCache* _pxmCache = 0;
14}
15
16
17PImageCache::PImageCache()
18 : QCache<QImage>()
19{
20 /* just to set an initial value.. 4 big images */
21 setMaxCost( (1024*1024*16)/8*4 );
22}
23
24PImageCache::~PImageCache() {
25}
26
27PImageCache* PImageCache::self() {
28 if ( !_imgCache )
29 _imgCache = new PImageCache;
30 return _imgCache;
31}
32
33QImage* PImageCache::cachedImage( const QString& _path, int ori, int max ) {
34 QString path = QString( "%1_%2:" ).arg( ori ).arg( max );
35 path += _path;
36
37 QImage* img = find( path );
38 if ( !img ) {
39// img = currentView()->dirLister()->image( _path, PDirLister::Factor(ori), max);
40// insertImage( _path, img, ori, max );
41 currentView()->dirLister()->image( _path, PDirLister::Factor( ori ), max );
42 }
43
44
45 return img;
46}
47
48void PImageCache::insertImage( const QString& _path, const QImage* img, int ori, int max ) {
49 QString path = QString("%1_%2:" ).arg( ori ).arg( max );
50 path += _path;
51 insert( path, img, (img->height()*img->width()*img->depth())/8 );
52}
53
54
55PPixmapCache::PPixmapCache() {
56 /*
57 * 20 64x64 16 bit images
58 */
59 setMaxCost( 64*64*QPixmap::defaultDepth()/8*20 );
60}
61
62PPixmapCache::~PPixmapCache() {
63}
64
65PPixmapCache* PPixmapCache::self() {
66 if ( !_pxmCache )
67 _pxmCache = new PPixmapCache;
68
69 return _pxmCache;
70}
71
72QPixmap* PPixmapCache::cachedImage( const QString& _path, int width, int height ) {
73 QString path = QString( "%1_%2:" ).arg( width ).arg( height );
74 path += _path;
75
76 QPixmap* pxm = find( path );
77
78
79
80 return pxm;
81}
82
83void PPixmapCache::insertImage( const QString& _path, const QPixmap* pix, int width, int height ) {
84 QString path = QString("%1_%2:" ).arg( width ).arg( height );
85 path += _path;
86 insert( path, pix, (pix->height()*pix->width()*pix->depth())/8 );
87}
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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 * No WArranty...
4 */
5
6#ifndef PHUNK_IMAGE_CACHE_H
7#define PHUNK_IMAGE_CACHE_H
8
9#include <qimage.h>
10#include <qpixmap.h>
11#include <qcache.h>
12
13
14class PImageCache : public QCache<QImage> {
15private:
16 PImageCache();
17 ~PImageCache();
18
19public:
20 static PImageCache *self();
21 QImage* cachedImage( const QString& path, int orientation = 3, int max = 0); //const;
22 void insertImage( const QString& path, const QImage &, int orien = 3, int max = 0);
23 void insertImage( const QString& path, const QImage *, int orien=3, int max = 0 );
24};
25
26
27class PPixmapCache : public QCache<QPixmap> {
28private:
29 PPixmapCache();
30 ~PPixmapCache();
31public:
32 static PPixmapCache *self();
33 QPixmap* cachedImage( const QString& path, int width, int height );
34 void insertImage( const QString& path, const QPixmap &, int width, int height );
35 void insertImage( const QString& path, const QPixmap *, int width, int height );
36};
37
38inline void PPixmapCache::insertImage( const QString& path, const QPixmap& p, int width, int height ) {
39 insertImage( path, new QPixmap( p ), width, height );
40}
41
42inline void PImageCache::insertImage( const QString& path, const QImage& p, int width, int height ) {
43 insertImage( path, new QImage( p ), width, height );
44}
45
46#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 @@
1#include "slavemaster.h"
2
3#include <qpe/qpeapplication.h>
4#include <qpe/qcopenvelope_qws.h>
5
6#include <qcopchannel_qws.h>
7#include <qtimer.h>
8
9QDataStream & operator << (QDataStream & str, bool b)
10{
11 str << Q_INT8(b);
12 return str;
13}
14QDataStream & operator >> (QDataStream & str, bool & b)
15{
16 Q_INT8 l;
17 str >> l;
18 b = bool(l);
19 return str;
20}
21QDataStream &operator<<( QDataStream& s, const PixmapInfo& inf) {
22 return s << inf.file << inf.pixmap << inf.width << inf.height;
23}
24QDataStream &operator>>( QDataStream& s, PixmapInfo& inf ) {
25 s >> inf.file >> inf.pixmap >> inf.width >> inf.height;
26 return s;
27}
28QDataStream &operator<<( QDataStream& s, const ImageInfo& i) {
29 return s << i.kind << i.file << i.info;
30}
31QDataStream &operator>>( QDataStream& s, ImageInfo& i ) {
32 s >> i.kind >> i.file >> i.info;
33 return s;
34}
35
36
37
38SlaveMaster* SlaveMaster::m_master = 0;
39
40SlaveMaster::SlaveMaster()
41 : m_started( false )
42{
43 QCopChannel *chan= new QCopChannel( "QPE/opie-eye",this );
44 connect(chan, SIGNAL(received(const QCString&,const QByteArray&)),
45 this, SLOT(recieve(const QCString&,const QByteArray&)) );
46}
47
48SlaveMaster::~SlaveMaster() {
49}
50
51SlaveMaster* SlaveMaster::self() {
52 if ( !m_master )
53 m_master = new SlaveMaster;
54 return m_master;
55}
56
57void SlaveMaster::thumbInfo( const QString& str) {
58 m_inThumbInfo.append( str );
59
60 if ( !m_started ) {
61 QTimer::singleShot( 0, this, SLOT(slotTimerStart()));
62 m_started = true;
63 }
64}
65
66void SlaveMaster::imageInfo( const QString& str ) {
67 m_inImageInfo.append( str );
68 if ( !m_started ) {
69 QTimer::singleShot( 0, this, SLOT(slotTimerStart()));
70 m_started = true;
71 }
72}
73
74void SlaveMaster::thumbNail( const QString& str, int w, int h ) {
75 if ( str.isEmpty() ) {
76 qWarning( "Asking for empty nail" );
77 return;
78 }
79 qWarning( "Asking for thumbNail in size %d %d" + str, w,h );
80 PixmapInfo item;
81 item.file = str; item.width = w; item.height = h;
82 item.pixmap = QPixmap();
83 m_inThumbNail.append( item );
84
85 if ( !m_started ) {
86 QTimer::singleShot( 0, this, SLOT(slotTimerStart()));
87 m_started = true;
88 }
89}
90
91
92void SlaveMaster::recieve( const QCString& str, const QByteArray& at) {
93
94 ImageInfos infos;
95 PixmapInfos pixinfos;
96
97 QDataStream stream( at, IO_ReadOnly );
98 if ( str == "pixmapsHandled(PixmapList)" )
99 stream >> pixinfos;
100 else if ( str == "pixmapsHandled(StringList)" )
101 stream >> infos;
102
103 qWarning( "PixInfos %d", pixinfos.count() );
104
105 bool got_data = ( !infos.isEmpty() || !pixinfos.isEmpty() );
106 if ( got_data ) {
107 emit sig_start();
108 for ( ImageInfos::Iterator _it = infos.begin(); _it != infos.end(); ++_it ) {
109 if ( (*_it).kind )
110 emit sig_fullInfo( (*_it).file, (*_it).info );
111 else
112 emit sig_thumbInfo( (*_it).file, (*_it).info );
113 }
114
115 for ( PixmapInfos::Iterator it = pixinfos.begin(); it != pixinfos.end(); ++it )
116 emit sig_thumbNail( (*it).file, (*it).pixmap );
117 emit sig_end();
118 }
119}
120
121void SlaveMaster::slotTimerStart() {
122 m_started = false;
123
124 if ( !m_inThumbInfo.isEmpty() ) {
125 QCopEnvelope env("QPE/opie-eye_slave", "thumbInfos(QStringList)" );
126 env << m_inThumbInfo;
127 }
128 if ( !m_inImageInfo.isEmpty() ) {
129 QCopEnvelope env("QPE/opie-eye_slave", "fullInfos(QStringList)" );
130 env << m_inImageInfo;
131 }
132 if ( !m_inThumbNail.isEmpty() ) {
133 QCopEnvelope env("QPE/opie-eye_slave", "pixmapInfos(PixmapInfos)" );
134 env << m_inThumbNail;
135 }
136
137
138 m_inThumbInfo.clear();
139 m_inImageInfo.clear();
140 m_inThumbNail.clear();
141}
142
143QImage SlaveMaster::image( const QString& str, PDirLister::Factor, int ) {
144 return QImage();
145}
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 @@
1#ifndef OPIE_EYE_SLAVE_MASTER_H
2#define OPIE_EYE_SLAVE_MASTER_H
3
4#include <iface/dirlister.h>
5#include <iface/slaveiface.h>
6
7#include <qobject.h>
8#include <qstring.h>
9#include <qsize.h>
10
11class SlaveMaster : public QObject {
12 Q_OBJECT
13 typedef QValueList<ImageInfo> ImageInfos;
14 typedef QValueList<PixmapInfo> PixmapInfos;
15public:
16 static SlaveMaster *self();
17
18 void thumbInfo( const QString& );
19 void imageInfo( const QString& );
20 void thumbNail( const QString&, int w, int h );
21 QImage image( const QString&, PDirLister::Factor, int );
22signals:
23 void sig_start();
24 void sig_end();
25
26 void sig_thumbInfo( const QString&, const QString& );
27 void sig_fullInfo( const QString&, const QString& );
28 void sig_thumbNail( const QString&, const QPixmap& );
29private slots:
30 void recieve( const QCString&, const QByteArray& );
31 void slotTimerStart();
32private:
33 SlaveMaster();
34 ~SlaveMaster();
35 static SlaveMaster *m_master;
36 bool m_started : 1;
37 QStringList m_inThumbInfo;
38 QStringList m_inImageInfo;
39 PixmapInfos m_inThumbNail;
40};
41
42
43#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 @@
1#include <iface/dirview.h>
2
3
4namespace {
5 ViewMap *_viewMap = 0;
6 PDirView *_dirView = 0;
7}
8
9
10ViewMap *viewMap() {
11 if ( !_viewMap )
12 _viewMap = new ViewMap;
13
14 return _viewMap;
15}
16
17
18PDirView* currentView(){
19 return _dirView;
20}
21
22
23void setCurrentView( PDirView* view ) {
24 _dirView = view;
25}
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 @@
1CONFIG += qt warn_on #quick-app
2DESTDIR = $(OPIEDIR)/bin
3TEMPLATE = app
4TARGET = opie-eye
5# the name of the resulting object
6
7HEADERS = gui/iconview.h gui/filesystem.h gui/mainwindow.h \
8 lib/imagecache.h impl/dir/dir_dirview.h \
9 iface/dirview.h iface/dirlister.h iface/ifaceinfo.h \
10 impl/dir/dir_lister.h impl/dir/dir_ifaceinfo.h \
11 lib/slavemaster.h \
12 iface/slaveiface.h
13
14# A list header files
15
16
17SOURCES = gui/iconview.cpp gui/filesystem.cpp gui/mainwindow.cpp \
18 lib/imagecache.cpp lib/viewmap.cpp \
19 impl/dir/dir_dirview.cpp iface/dirlister.cpp \
20 iface/dirview.cpp impl/dir/dir_lister.cpp \
21 impl/dir/dir_ifaceinfo.cpp lib/slavemaster.cpp
22# A list of source files
23
24INTERFACES =
25# list of ui files
26
27INCLUDEPATH += . $(OPIEDIR)/include
28DEPENDPATH += $(OPIEDIR)/include
29
30
31
32LIBS += -lqpe -lopie
33
34include ( $(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 @@
1#include "gif_slave.h"
2
3#include "thumbnailtool.h"
4
5#include <qimage.h>
6#include <qobject.h>
7#include <qfile.h>
8#include <qpixmap.h>
9
10
11PHUNK_VIEW_INTERFACE( "Gif", GifSlave );
12
13
14namespace {
15/*
16** $Id$
17**
18** Minimal GIF parser, for use in extracting and setting metadata.
19** Modified for standalone & KDE calling by Bryce Nesbitt
20**
21** TODO:
22** Support gif comments that span more than one comment block.
23** Verify that Unicode utf-8 is fully unmolested by this code.
24** Implement gif structure verifier.
25**
26** Based on: GIFtrans v1.12.2
27** Copyright (C) 24.2.94 by Andreas Ley <ley@rz.uni-karlsruhe.de>
28**
29*******************************************************************************
30**
31** Original distribution site is
32** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.c
33** A man-page by knordlun@fltxa.helsinki.fi (Kai Nordlund) is at
34** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.1
35** An online version by taylor@intuitive.com (Dave Taylor) is at
36** http://www.intuitive.com/coolweb/Addons/giftrans-doc.html
37** To compile for MS-DOS or OS/2, you need getopt:
38** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/getopt.c
39** MS-DOS executable can be found at
40** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.exe
41** OS/2 executable can be found at
42** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.os2.exe
43** A template rgb.txt for use with the MS-DOS version can be found at
44** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/rgb.txt
45** Additional info can be found on
46** http://melmac.corp.harris.com/transparent_images.html
47**
48** The GIF file format is documented in
49** ftp://ftp.uu.net/doc/literary/obi/Standards/Graphics/Formats/gif89a.doc.Z
50** A good quick reference is at:
51** http://www.goice.co.jp/member/mo/formats/gif.html
52**
53*******************************************************************************
54**
55** This program is free software; you can redistribute it and/or modify
56** it under the terms of the GNU General Public License as published by
57** the Free Software Foundation; either version 2 of the License, or
58** (at your option) any later version.
59**
60** This program is distributed in the hope that it will be useful,
61** but WITHOUT ANY WARRANTY; without even the implied warranty of
62** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
63** GNU General Public License for more details.
64**
65** You should have received a copy of the GNU General Public License
66** along with this program; if not, write to the Free Software
67** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
68**
69*/
70#define SUCCESS (0)
71#define FAILURE (1)
72
73#define READ_BINARY "r"
74#define WRITE_BINARY "w"
75
76
77static long int pos;
78static char skipcomment,verbose;
79char *global_comment;
80
81#define readword(buffer) ((buffer)[0]+256*(buffer)[1])
82#define readflag(buffer) ((buffer)?true:false)
83#define hex(c) ('a'<=(c)&&(c)<='z'?(c)-'a'+10:'A'<=(c)&&(c)<='Z'?(c)-'A'+10:(c)-'0')
84
85static bool debug = false;
86static bool output= false;
87
88void dump(long int, unsigned char *, size_t) {
89}
90
91void skipdata(FILE *src)
92{
93 unsigned char size,buffer[256];
94
95 do {
96 pos=ftell(src);
97 (void)fread((void *)&size,1,1,src);
98 if (debug)
99 dump(pos,&size,1);
100 if (debug) {
101 pos=ftell(src);
102 (void)fread((void *)buffer,(size_t)size,1,src);
103 dump(pos,buffer,(size_t)size);
104 }
105 else
106 (void)fseek(src,(long int)size,SEEK_CUR);
107 } while (!feof(src)&&size>0);
108}
109
110
111void transdata(FILE *src, FILE *dest)
112{
113 unsigned char size,buffer[256];
114
115 do {
116 pos=ftell(src);
117 (void)fread((void *)&size,1,1,src);
118 pos=ftell(src);
119 (void)fread((void *)buffer,(size_t)size,1,src);
120 if (debug)
121 dump(pos,buffer,(size_t)size);
122 if (output)
123 (void)fwrite((void *)buffer,(size_t)size,1,dest);
124 } while (!feof(src)&&size>0);
125}
126
127void transblock(FILE *src, FILE* dest)
128{
129 unsigned char size,buffer[256];
130
131 pos=ftell(src);
132 (void)fread((void *)&size,1,1,src);
133 if (debug)
134 dump(pos,&size,1);
135 if (output)
136 (void)fwrite((void *)&size,1,1,dest);
137 pos=ftell(src);
138 (void)fread((void *)buffer,(size_t)size,1,src);
139 if (debug)
140 dump(pos,buffer,(size_t)size);
141 if (output)
142 (void)fwrite((void *)buffer,(size_t)size,1,dest);
143}
144
145void dumpcomment(FILE *src, QCString& str)
146{
147 unsigned char size;
148
149 pos=ftell(src);
150 (void)fread((void *)&size,1,1,src);
151 if (debug)
152 dump(pos,&size,1);
153 str.resize( size+1 );
154 (void)fread((void *)str.data(),size,1,src);
155 (void)fseek(src,(long int)pos,SEEK_SET);
156}
157
158
159
160
161int giftrans(FILE *src, FILE* dest, QString& str, bool full)
162{
163 unsigned char buffer[3*256],lsd[7],gct[3*256];
164 unsigned int size,gct_size;
165
166 /* Header */
167 pos=ftell(src);
168 (void)fread((void *)buffer,6,1,src);
169 if (strncmp((char *)buffer,"GIF",3)) {
170 str = QObject::tr("Not a GIF file");
171 (void)fprintf(stderr,"Not GIF file!\n");
172 return(1);
173 }
174
175 /* Logical Screen Descriptor */
176 pos=ftell(src);
177 (void)fread((void *)lsd,7,1,src);
178 //(void)fprintf(stderr,"Logical Screen Descriptor:\n");
179 str += QObject::tr("Dimensions: %1x%2\n").arg( readword(lsd) ).arg( readword(lsd+2 ) );
180 //(void)fprintf(stderr,"Global Color Table Flag: %s\n",readflag(lsd[4]&0x80));
181 str += QObject::tr("Depth: %1 bits\n").arg( (lsd[4]&0x70>>4 )+1);
182 //(void)fprintf(stderr,"Depth : %d bits\n",(lsd[4]&0x70>>4)+1);
183 if (lsd[4]&0x80 && full) {
184 str += QObject::tr("Sort Flag: %1\n" ).arg(readflag(lsd[4]&0x8) );
185 str += QObject::tr("Size of Global Color Table: %1 colors\n" ).arg( 2<<(lsd[4]&0x7));
186 str += QObject::tr("Background Color Index: %1\n" ).arg(lsd[5]);
187 }
188 if (lsd[6] && full)
189 str += QObject::tr("Pixel Aspect Ratio: %1 (Aspect Ratio %2)\n" ).arg( lsd[6] ).
190 arg( ((double)lsd[6]+15)/64 );
191
192 /* Global Color Table */
193 if (lsd[4]&0x80) {
194 gct_size=2<<(lsd[4]&0x7);
195 pos=ftell(src);
196 (void)fread((void *)gct,gct_size,3,src);
197 }
198
199 do {
200 pos=ftell(src);
201 (void)fread((void *)buffer,1,1,src);
202 switch (buffer[0]) {
203 case 0x2c: /* Image Descriptor */
204 (void)fread((void *)(buffer+1),9,1,src);
205 /* Local Color Table */
206 if (buffer[8]&0x80) {
207 size=2<<(buffer[8]&0x7);
208 pos=ftell(src);
209 (void)fread((void *)buffer,size,3,src);
210 }
211 /* Table Based Image Data */
212 pos=ftell(src);
213 (void)fread((void *)buffer,1,1,src);
214 transdata(src,dest);
215 break;
216 case 0x21: /* Extension */
217 (void)fread((void *)(buffer+1),1,1,src);
218 switch (buffer[1]) {
219 case 0xfe: /* Comment Extension */
220 if (true)
221 {
222 QCString st;
223 dumpcomment(src, st);
224 str += QObject::tr("Comment: %1\n" ).arg( st );
225 }
226 if (skipcomment)
227 skipdata(src);
228 else {
229 transdata(src,dest);
230 }
231 break;
232 case 0x01: /* Plain Text Extension */
233 case 0xf9: /* Graphic Control Extension */
234 case 0xff: /* Application Extension */
235 default:
236 transblock(src,dest);
237 transdata(src,dest);
238 break;
239 }
240 break;
241 case 0x3b: /* Trailer (write comment just before here) */
242 break;
243 default:
244 (void)fprintf(stderr,"0x%08lx: Error, unknown block 0x%02x!\n",ftell(src)-1,buffer[0]);
245 return(1);
246 }
247 } while (buffer[0]!=0x3b&&!feof(src));
248 return(buffer[0]==0x3b?SUCCESS:FAILURE);
249}
250
251
252/****************************************************************************/
253extern void get_gif_info( const char * original_filename, QString& str,
254 bool full =false)
255{
256FILE * infile;
257
258 if ((infile = fopen(original_filename, READ_BINARY)) == NULL) {
259 fprintf(stderr, "can't open gif image '%s'\n", original_filename);
260 return ;
261 }
262
263 output = FALSE;
264 verbose = TRUE;
265 debug = FALSE;
266 skipcomment = FALSE;
267 giftrans( infile, NULL, str, full );
268 fclose( infile );
269}
270
271}
272
273
274GifSlave::GifSlave()
275 : SlaveInterface(QStringList("gif"))
276{}
277
278GifSlave::~GifSlave() {
279
280}
281
282QString GifSlave::iconViewName(const QString& str) {
283 QString st;
284 get_gif_info(QFile::encodeName( str ).data(), st );
285 return st;
286}
287
288QString GifSlave::fullImageInfo( const QString& str) {
289 QString st;
290 get_gif_info(QFile::encodeName( str ).data(), st, true );
291 return st;
292}
293
294QPixmap GifSlave::pixmap(const QString& path, int width, int height ) {
295 static QImage img;
296 img.load( path );
297 if ( img.isNull() ) {
298 QPixmap pix;
299 return pix;
300 }
301
302 return ThumbNailTool::scaleImage( img, width,height );
303}
304
305
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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 */
4
5
6#ifndef SLAVE_GIF_IMPL_H
7#define SLAVE_GIF_IMPL_H
8
9#include "slaveiface.h"
10
11class GifSlave : public SlaveInterface {
12public:
13 GifSlave();
14 ~GifSlave();
15
16 QString iconViewName( const QString& );
17 QString fullImageInfo( const QString& );
18 QPixmap pixmap( const QString&, int width, int height );
19};
20
21
22#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 @@
1#include "jpeg_slave.h"
2
3#include "thumbnailtool.h"
4
5PHUNK_VIEW_INTERFACE( "JPEG", JpegSlave )
6
7#include <qtopia/timestring.h>
8#include <qobject.h>
9#include <qimage.h>
10
11/**
12 exif.h
13*/
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <math.h>
18#include <time.h>
19
20#include <qstring.h>
21#include <qfile.h>
22#include <qimage.h>
23
24typedef enum {
25 READ_EXIF = 1,
26 READ_IMAGE = 2,
27 READ_ALL = 3
28}ReadMode_t;
29
30//--------------------------------------------------------------------------
31// This structure is used to store jpeg file sections in memory.
32typedef struct {
33 uchar * Data;
34 int Type;
35 unsigned Size;
36}Section_t;
37
38typedef unsigned char uchar;
39
40typedef struct {
41 unsigned short Tag;
42 const char*const Desc;
43}TagTable_t;
44
45#define MAX_SECTIONS 20
46#define PSEUDO_IMAGE_MARKER 0x123; // Extra value.
47
48class ExifData {
49 Section_t Sections[MAX_SECTIONS];
50
51 QString CameraMake;
52 QString CameraModel;
53 QString DateTime;
54 int Orientation;
55 int Height, Width;
56 int ExifImageLength, ExifImageWidth;
57 int IsColor;
58 int Process;
59 int FlashUsed;
60 float FocalLength;
61 float ExposureTime;
62 float ApertureFNumber;
63 float Distance;
64 int Whitebalance;
65 int MeteringMode;
66 float CCDWidth;
67 float ExposureBias;
68 int ExposureProgram;
69 int ISOequivalent;
70 int CompressionLevel;
71 QString UserComment;
72 QString Comment;
73 QImage Thumbnail;
74
75 int ReadJpegSections (QFile & infile, ReadMode_t ReadMode);
76 void DiscardData(void);
77 int Get16u(void * Short);
78 int Get32s(void * Long);
79 unsigned Get32u(void * Long);
80 double ConvertAnyFormat(void * ValuePtr, int Format);
81 void ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength);
82 void process_COM (const uchar * Data, int length);
83 void process_SOFn (const uchar * Data, int marker);
84 int Get16m(const void * Short);
85 void process_EXIF(unsigned char * CharBuf, unsigned int length);
86 int Exif2tm(struct tm * timeptr, char * ExifTime);
87
88public:
89 ExifData();
90 bool scan(const QString &);
91 QString getCameraMake() { return CameraMake; }
92 QString getCameraModel() { return CameraModel; }
93 QString getDateTime() { return DateTime; }
94 int getOrientation() { return Orientation; }
95 int getHeight() { return Height; }
96 int getWidth() { return Width; }
97 int getIsColor() { return IsColor; }
98 int getProcess() { return Process; }
99 int getFlashUsed() { return FlashUsed; }
100 float getFocalLength() { return FocalLength; }
101 float getExposureTime() { return ExposureTime; }
102 float getApertureFNumber() { return ApertureFNumber; }
103 float getDistance() { return Distance; }
104 int getWhitebalance() { return Whitebalance; }
105 int getMeteringMode() { return MeteringMode; }
106 float getCCDWidth() { return CCDWidth; }
107 float getExposureBias() { return ExposureBias; }
108 int getExposureProgram() { return ExposureProgram; }
109 int getISOequivalent() { return ISOequivalent; }
110 int getCompressionLevel() { return CompressionLevel; }
111 QString getUserComment() { return UserComment; }
112 QString getComment() { return Comment; }
113 QImage getThumbnail();
114 bool isThumbnailSane();
115 bool isNullThumbnail() { return !isThumbnailSane(); }
116};
117
118class FatalError {
119 const char* ex;
120public:
121 FatalError(const char* s) { ex = s; }
122 void debug_print() const { qWarning("exception: %s", ex ); }
123};
124
125
126
127static unsigned char * LastExifRefd;
128static int ExifSettingsLength;
129static double FocalplaneXRes;
130static double FocalplaneUnits;
131static int MotorolaOrder = 0;
132static int SectionsRead;
133//static int HaveAll;
134
135//--------------------------------------------------------------------------
136// Table of Jpeg encoding process names
137
138#define M_SOF0 0xC0 // Start Of Frame N
139#define M_SOF1 0xC1 // N indicates which compression process
140#define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use
141#define M_SOF3 0xC3
142#define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers
143#define M_SOF6 0xC6
144#define M_SOF7 0xC7
145#define M_SOF9 0xC9
146#define M_SOF10 0xCA
147#define M_SOF11 0xCB
148#define M_SOF13 0xCD
149#define M_SOF14 0xCE
150#define M_SOF15 0xCF
151#define M_SOI 0xD8 // Start Of Image (beginning of datastream)
152#define M_EOI 0xD9 // End Of Image (end of datastream)
153#define M_SOS 0xDA // Start Of Scan (begins compressed data)
154#define M_JFIF 0xE0 // Jfif marker
155#define M_EXIF 0xE1 // Exif marker
156#define M_COM 0xFE // COMment
157
158
159TagTable_t ProcessTable[] = {
160 { M_SOF0, "Baseline"},
161 { M_SOF1, "Extended sequential"},
162 { M_SOF2, "Progressive"},
163 { M_SOF3, "Lossless"},
164 { M_SOF5, "Differential sequential"},
165 { M_SOF6, "Differential progressive"},
166 { M_SOF7, "Differential lossless"},
167 { M_SOF9, "Extended sequential, arithmetic coding"},
168 { M_SOF10, "Progressive, arithmetic coding"},
169 { M_SOF11, "Lossless, arithmetic coding"},
170 { M_SOF13, "Differential sequential, arithmetic coding"},
171 { M_SOF14, "Differential progressive, arithmetic coding"},
172 { M_SOF15, "Differential lossless, arithmetic coding"},
173 { 0, "Unknown"}
174};
175
176
177
178//--------------------------------------------------------------------------
179// Describes format descriptor
180static int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
181#define NUM_FORMATS 12
182
183#define FMT_BYTE 1
184#define FMT_STRING 2
185#define FMT_USHORT 3
186#define FMT_ULONG 4
187#define FMT_URATIONAL 5
188#define FMT_SBYTE 6
189#define FMT_UNDEFINED 7
190#define FMT_SSHORT 8
191#define FMT_SLONG 9
192#define FMT_SRATIONAL 10
193#define FMT_SINGLE 11
194#define FMT_DOUBLE 12
195
196//--------------------------------------------------------------------------
197// Describes tag values
198
199#define TAG_EXIF_OFFSET 0x8769
200#define TAG_INTEROP_OFFSET 0xa005
201
202#define TAG_MAKE 0x010F
203#define TAG_MODEL 0x0110
204#define TAG_ORIENTATION 0x0112
205
206#define TAG_EXPOSURETIME 0x829A
207#define TAG_FNUMBER 0x829D
208
209#define TAG_SHUTTERSPEED 0x9201
210#define TAG_APERTURE 0x9202
211#define TAG_MAXAPERTURE 0x9205
212#define TAG_FOCALLENGTH 0x920A
213
214#define TAG_DATETIME_ORIGINAL 0x9003
215#define TAG_USERCOMMENT 0x9286
216
217#define TAG_SUBJECT_DISTANCE 0x9206
218#define TAG_FLASH 0x9209
219
220#define TAG_FOCALPLANEXRES 0xa20E
221#define TAG_FOCALPLANEUNITS 0xa210
222#define TAG_EXIF_IMAGEWIDTH 0xA002
223#define TAG_EXIF_IMAGELENGTH 0xA003
224
225// the following is added 05-jan-2001 vcs
226#define TAG_EXPOSURE_BIAS 0x9204
227#define TAG_WHITEBALANCE 0x9208
228#define TAG_METERING_MODE 0x9207
229#define TAG_EXPOSURE_PROGRAM 0x8822
230#define TAG_ISO_EQUIVALENT 0x8827
231#define TAG_COMPRESSION_LEVEL 0x9102
232
233#define TAG_THUMBNAIL_OFFSET 0x0201
234#define TAG_THUMBNAIL_LENGTH 0x0202
235
236
237
238
239//--------------------------------------------------------------------------
240// Parse the marker stream until SOS or EOI is seen;
241//--------------------------------------------------------------------------
242int ExifData::ReadJpegSections (QFile & infile, ReadMode_t ReadMode)
243{
244 int a;
245
246 a = infile.getch();
247
248 if (a != 0xff || infile.getch() != M_SOI) {
249 SectionsRead = 0;
250 return false;
251 }
252 for(SectionsRead = 0; SectionsRead < MAX_SECTIONS-1; ){
253 int marker = 0;
254 int got;
255 unsigned int ll,lh;
256 unsigned int itemlen;
257 uchar * Data;
258
259 for (a=0;a<7;a++){
260 marker = infile.getch();
261 if (marker != 0xff) break;
262
263 if (a >= 6){
264
265 qWarning( "too many padding bytes" );
266 return false;
267
268 }
269 }
270
271 if (marker == 0xff){
272 // 0xff is legal padding, but if we get that many, something's wrong.
273 return false;
274 }
275
276 Sections[SectionsRead].Type = marker;
277
278 // Read the length of the section.
279 lh = (uchar) infile.getch();
280 ll = (uchar) infile.getch();
281
282 itemlen = (lh << 8) | ll;
283
284 if (itemlen < 2) {
285 return false;;
286 }
287
288 Sections[SectionsRead].Size = itemlen;
289
290 Data = (uchar *)malloc(itemlen+1); // Add 1 to allow sticking a 0 at the end.
291 Sections[SectionsRead].Data = Data;
292
293 // Store first two pre-read bytes.
294 Data[0] = (uchar)lh;
295 Data[1] = (uchar)ll;
296
297 got = infile.readBlock((char*)Data+2, itemlen-2); // Read the whole section.
298 if (( unsigned ) got != itemlen-2){
299 return false;
300 }
301 SectionsRead++;
302
303 switch(marker){
304
305 case M_SOS: // stop before hitting compressed data
306 // If reading entire image is requested, read the rest of the data.
307 if (ReadMode & READ_IMAGE){
308 unsigned long size;
309
310 size = QMAX( 0ul, infile.size()-infile.at() );
311 Data = (uchar *)malloc(size);
312 if (Data == NULL){
313 return false;
314 }
315
316 got = infile.readBlock((char*)Data, size);
317 if (( unsigned ) got != size){
318 return false;
319 }
320
321 Sections[SectionsRead].Data = Data;
322 Sections[SectionsRead].Size = size;
323 Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER;
324 SectionsRead ++;
325 //HaveAll = 1;
326 }
327 return true;
328
329 case M_EOI: // in case it's a tables-only JPEG stream
330 qWarning( "No image in jpeg!" );
331 return false;
332
333 case M_COM: // Comment section
334 // pieczy 2002-02-12
335 // now the User comment goes to UserComment
336 // so we can store a Comment section also in READ_EXIF mode
337 process_COM(Data, itemlen);
338 break;
339
340 case M_JFIF:
341 // Regular jpegs always have this tag, exif images have the exif
342 // marker instead, althogh ACDsee will write images with both markers.
343 // this program will re-create this marker on absence of exif marker.
344 // hence no need to keep the copy from the file.
345 free(Sections[--SectionsRead].Data);
346 break;
347
348 case M_EXIF:
349 // Seen files from some 'U-lead' software with Vivitar scanner
350 // that uses marker 31 for non exif stuff. Thus make sure
351 // it says 'Exif' in the section before treating it as exif.
352 if ((ReadMode & READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){
353 process_EXIF((uchar *)Data, itemlen);
354 }else{
355 // Discard this section.
356 free(Sections[--SectionsRead].Data);
357 }
358 break;
359
360 case M_SOF0:
361 case M_SOF1:
362 case M_SOF2:
363 case M_SOF3:
364 case M_SOF5:
365 case M_SOF6:
366 case M_SOF7:
367 case M_SOF9:
368 case M_SOF10:
369 case M_SOF11:
370 case M_SOF13:
371 case M_SOF14:
372 case M_SOF15:
373 process_SOFn(Data, marker);
374 default:
375 break;
376 break;
377 }
378 }
379 return true;
380}
381
382
383//--------------------------------------------------------------------------
384// Discard read data.
385//--------------------------------------------------------------------------
386void ExifData::DiscardData(void)
387{
388 for (int a=0; a < SectionsRead; a++)
389 free(Sections[a].Data);
390 SectionsRead = 0;
391}
392
393//--------------------------------------------------------------------------
394// Convert a 16 bit unsigned value from file's native byte order
395//--------------------------------------------------------------------------
396int ExifData::Get16u(void * Short)
397{
398 if (MotorolaOrder){
399 return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
400 }else{
401 return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0];
402 }
403}
404
405//--------------------------------------------------------------------------
406// Convert a 32 bit signed value from file's native byte order
407//--------------------------------------------------------------------------
408int ExifData::Get32s(void * Long)
409{
410 if (MotorolaOrder){
411 return ((( char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16)
412 | (((uchar *)Long)[2] << 8 ) | (((uchar *)Long)[3] << 0 );
413 }else{
414 return ((( char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16)
415 | (((uchar *)Long)[1] << 8 ) | (((uchar *)Long)[0] << 0 );
416 }
417}
418
419//--------------------------------------------------------------------------
420// Convert a 32 bit unsigned value from file's native byte order
421//--------------------------------------------------------------------------
422unsigned ExifData::Get32u(void * Long)
423{
424 return (unsigned)Get32s(Long) & 0xffffffff;
425}
426
427//--------------------------------------------------------------------------
428// Evaluate number, be it int, rational, or float from directory.
429//--------------------------------------------------------------------------
430double ExifData::ConvertAnyFormat(void * ValuePtr, int Format)
431{
432 double Value;
433 Value = 0;
434
435 switch(Format){
436 case FMT_SBYTE: Value = *(signed char *)ValuePtr; break;
437 case FMT_BYTE: Value = *(uchar *)ValuePtr; break;
438
439 case FMT_USHORT: Value = Get16u(ValuePtr); break;
440
441 case FMT_ULONG: Value = Get32u(ValuePtr); break;
442
443 case FMT_URATIONAL:
444 case FMT_SRATIONAL:
445 {
446 int Num,Den;
447 Num = Get32s(ValuePtr);
448 Den = Get32s(4+(char *)ValuePtr);
449 if (Den == 0){
450 Value = 0;
451 }else{
452 Value = (double)Num/Den;
453 }
454 break;
455 }
456
457 case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break;
458 case FMT_SLONG: Value = Get32s(ValuePtr); break;
459
460 // Not sure if this is correct (never seen float used in Exif format)
461 case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break;
462 case FMT_DOUBLE: Value = *(double *)ValuePtr; break;
463 }
464 return Value;
465}
466
467//--------------------------------------------------------------------------
468// Process one of the nested EXIF directories.
469//--------------------------------------------------------------------------
470void ExifData::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength)
471{
472 int de;
473 int a;
474 int NumDirEntries;
475 unsigned ThumbnailOffset = 0;
476 unsigned ThumbnailSize = 0;
477
478 NumDirEntries = Get16u(DirStart);
479 #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
480
481 {
482 unsigned char * DirEnd;
483 DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
484 if (DirEnd+4 > (OffsetBase+ExifLength)){
485 if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength){
486 // Version 1.3 of jhead would truncate a bit too much.
487 // This also caught later on as well.
488 }else{
489 // Note: Files that had thumbnails trimmed with jhead 1.3 or earlier
490 // might trigger this.
491 return;
492 }
493 }
494 if (DirEnd < LastExifRefd) LastExifRefd = DirEnd;
495 }
496
497 for (de=0;de<NumDirEntries;de++){
498 int Tag, Format, Components;
499 unsigned char * ValuePtr;
500 int ByteCount;
501 char * DirEntry;
502 DirEntry = (char *)DIR_ENTRY_ADDR(DirStart, de);
503
504 Tag = Get16u(DirEntry);
505 Format = Get16u(DirEntry+2);
506 Components = Get32u(DirEntry+4);
507
508 if ((Format-1) >= NUM_FORMATS) {
509 // (-1) catches illegal zero case as unsigned underflows to positive large.
510 return;
511 }
512
513 ByteCount = Components * BytesPerFormat[Format];
514
515 if (ByteCount > 4){
516 unsigned OffsetVal;
517 OffsetVal = Get32u(DirEntry+8);
518 // If its bigger than 4 bytes, the dir entry contains an offset.
519 if (OffsetVal+ByteCount > ExifLength){
520 // Bogus pointer offset and / or bytecount value
521 //printf("Offset %d bytes %d ExifLen %d\n",OffsetVal, ByteCount, ExifLength);
522
523 return;
524 }
525 ValuePtr = OffsetBase+OffsetVal;
526 }else{
527 // 4 bytes or less and value is in the dir entry itself
528 ValuePtr = (unsigned char *)DirEntry+8;
529 }
530
531 if (LastExifRefd < ValuePtr+ByteCount){
532 // Keep track of last byte in the exif header that was actually referenced.
533 // That way, we know where the discardable thumbnail data begins.
534 LastExifRefd = ValuePtr+ByteCount;
535 }
536
537 // Extract useful components of tag
538 switch(Tag){
539
540 case TAG_MAKE:
541 ExifData::CameraMake = QString((char*)ValuePtr);
542 break;
543
544 case TAG_MODEL:
545 ExifData::CameraModel = QString((char*)ValuePtr);
546 break;
547
548 case TAG_ORIENTATION:
549 Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
550 break;
551
552 case TAG_DATETIME_ORIGINAL:
553 DateTime = QString((char*)ValuePtr);
554 break;
555
556 case TAG_USERCOMMENT:
557 // Olympus has this padded with trailing spaces. Remove these first.
558 for (a=ByteCount;;){
559 a--;
560 if ((ValuePtr)[a] == ' '){
561 (ValuePtr)[a] = '\0';
562 }else{
563 break;
564 }
565 if (a == 0) break;
566 }
567
568 // Copy the comment
569 if (memcmp(ValuePtr, "ASCII",5) == 0){
570 for (a=5;a<10;a++){
571 int c;
572 c = (ValuePtr)[a];
573 if (c != '\0' && c != ' '){
574 //strncpy(ImageInfo.Comments, (const char*)(a+ValuePtr), 199);
575 UserComment.sprintf("%s", (const char*)(a+ValuePtr));
576 break;
577 }
578 }
579 }else{
580 //strncpy(ImageInfo.Comments, (const char*)ValuePtr, 199);
581 UserComment.sprintf("%s", (const char*)ValuePtr);
582 }
583 break;
584
585 case TAG_FNUMBER:
586 // Simplest way of expressing aperture, so I trust it the most.
587 // (overwrite previously computd value if there is one)
588 ExifData::ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
589 break;
590
591 case TAG_APERTURE:
592 case TAG_MAXAPERTURE:
593 // More relevant info always comes earlier, so only use this field if we don't
594 // have appropriate aperture information yet.
595 if (ExifData::ApertureFNumber == 0){
596 ExifData::ApertureFNumber
597 = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5);
598 }
599 break;
600
601 case TAG_FOCALLENGTH:
602 // Nice digital cameras actually save the focal length as a function
603 // of how farthey are zoomed in.
604 ExifData::FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);
605 break;
606
607 case TAG_SUBJECT_DISTANCE:
608 // Inidcates the distacne the autofocus camera is focused to.
609 // Tends to be less accurate as distance increases.
610 ExifData::Distance = (float)ConvertAnyFormat(ValuePtr, Format);
611 break;
612
613 case TAG_EXPOSURETIME:
614 // Simplest way of expressing exposure time, so I trust it most.
615 // (overwrite previously computd value if there is one)
616 ExifData::ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format);
617 break;
618
619 case TAG_SHUTTERSPEED:
620 // More complicated way of expressing exposure time, so only use
621 // this value if we don't already have it from somewhere else.
622 if (ExifData::ExposureTime == 0){
623 ExifData::ExposureTime
624 = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2)));
625 }
626 break;
627
628 case TAG_FLASH:
629 if (ConvertAnyFormat(ValuePtr, Format)){
630 ExifData::FlashUsed = 1;
631 }
632 break;
633
634 case TAG_EXIF_IMAGELENGTH:
635 ExifImageLength = (int)ConvertAnyFormat(ValuePtr, Format);
636 break;
637
638 case TAG_EXIF_IMAGEWIDTH:
639 ExifImageWidth = (int)ConvertAnyFormat(ValuePtr, Format);
640 break;
641
642 case TAG_FOCALPLANEXRES:
643 FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
644 break;
645
646 case TAG_FOCALPLANEUNITS:
647 switch((int)ConvertAnyFormat(ValuePtr, Format)){
648 case 1: FocalplaneUnits = 25.4; break; // inch
649 case 2:
650 // According to the information I was using, 2 means meters.
651 // But looking at the Cannon powershot's files, inches is the only
652 // sensible value.
653 FocalplaneUnits = 25.4;
654 break;
655
656 case 3: FocalplaneUnits = 10; break; // centimeter
657 case 4: FocalplaneUnits = 1; break; // milimeter
658 case 5: FocalplaneUnits = .001; break; // micrometer
659 }
660 break;
661
662 // Remaining cases contributed by: Volker C. Schoech (schoech@gmx.de)
663
664 case TAG_EXPOSURE_BIAS:
665 ExifData::ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format);
666 break;
667
668 case TAG_WHITEBALANCE:
669 ExifData::Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
670 break;
671
672 case TAG_METERING_MODE:
673 ExifData::MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
674 break;
675
676 case TAG_EXPOSURE_PROGRAM:
677 ExifData::ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
678 break;
679
680 case TAG_ISO_EQUIVALENT:
681 ExifData::ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
682 if ( ExifData::ISOequivalent < 50 ) ExifData::ISOequivalent *= 200;
683 break;
684
685 case TAG_COMPRESSION_LEVEL:
686 ExifData::CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format);
687 break;
688
689 case TAG_THUMBNAIL_OFFSET:
690 ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);
691 break;
692
693 case TAG_THUMBNAIL_LENGTH:
694 ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);
695 break;
696
697 }
698
699 if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET){
700 unsigned char * SubdirStart;
701 SubdirStart = OffsetBase + Get32u(ValuePtr);
702 if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){
703 return;
704 }
705 ProcessExifDir(SubdirStart, OffsetBase, ExifLength);
706 continue;
707 }
708 }
709
710 {
711 // In addition to linking to subdirectories via exif tags,
712 // there's also a potential link to another directory at the end of each
713 // directory. this has got to be the result of a comitee!
714 unsigned char * SubdirStart;
715 unsigned Offset;
716
717 if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){
718 Offset = Get32u(DIR_ENTRY_ADDR(DirStart, NumDirEntries));
719 // There is at least one jpeg from an HP camera having an Offset of almost MAXUINT.
720 // Adding OffsetBase to it produces an overflow, so compare with ExifLength here.
721 // See http://bugs.kde.org/show_bug.cgi?id=54542
722 if (Offset && Offset < ExifLength){
723 SubdirStart = OffsetBase + Offset;
724 if (SubdirStart > OffsetBase+ExifLength){
725 if (SubdirStart < OffsetBase+ExifLength+20){
726 // Jhead 1.3 or earlier would crop the whole directory!
727 // As Jhead produces this form of format incorrectness,
728 // I'll just let it pass silently
729 qWarning( "Thumbnail removed with Jhead 1.3 or earlier" );
730 }else{
731 return;
732 }
733 }else{
734 if (SubdirStart <= OffsetBase+ExifLength){
735 ProcessExifDir(SubdirStart, OffsetBase, ExifLength);
736 }
737 }
738 }
739 }else{
740 // The exif header ends before the last next directory pointer.
741 }
742 }
743
744 if (ThumbnailSize && ThumbnailOffset){
745 if (ThumbnailSize + ThumbnailOffset <= ExifLength){
746 // The thumbnail pointer appears to be valid. Store it.
747 Thumbnail.loadFromData(OffsetBase + ThumbnailOffset, ThumbnailSize, "JPEG");
748 }
749 }
750}
751
752//--------------------------------------------------------------------------
753// Process a COM marker. We want to leave the bytes unchanged. The
754// progam that displays this text may decide to remove blanks, convert
755// newlines, or otherwise modify the text. In particular we want to be
756// safe for passing utf-8 text.
757//--------------------------------------------------------------------------
758void ExifData::process_COM (const uchar * Data, int length)
759{
760 QChar ch;
761 int a;
762
763 for (a=2;a<length;a++){
764 ch = Data[a];
765 if (ch == '\000') continue; // Remove nulls
766 Comment.append(ch);
767 }
768}
769
770
771//--------------------------------------------------------------------------
772// Process a SOFn marker. This is useful for the image dimensions
773//--------------------------------------------------------------------------
774void ExifData::process_SOFn (const uchar * Data, int marker)
775{
776 int data_precision, num_components;
777
778 data_precision = Data[2];
779 ExifData::Height = Get16m(Data+3);
780 ExifData::Width = Get16m(Data+5);
781 num_components = Data[7];
782
783 if (num_components == 3){
784 ExifData::IsColor = 1;
785 }else{
786 ExifData::IsColor = 0;
787 }
788
789 ExifData::Process = marker;
790
791}
792
793//--------------------------------------------------------------------------
794// Get 16 bits motorola order (always) for jpeg header stuff.
795//--------------------------------------------------------------------------
796int ExifData::Get16m(const void * Short)
797{
798 return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
799}
800
801
802//--------------------------------------------------------------------------
803// Process a EXIF marker
804// Describes all the drivel that most digital cameras include...
805//--------------------------------------------------------------------------
806void ExifData::process_EXIF(unsigned char * CharBuf, unsigned int length)
807{
808 ExifData::FlashUsed = 0; // If it s from a digicam, and it used flash, it says so.
809
810 FocalplaneXRes = 0;
811 FocalplaneUnits = 0;
812 ExifImageWidth = 0;
813 ExifImageLength = 0;
814
815 { // Check the EXIF header component
816 static const uchar ExifHeader[] = "Exif\0\0";
817 if (memcmp(CharBuf+2, ExifHeader,6)){
818 return;
819 }
820 }
821
822 if (memcmp(CharBuf+8,"II",2) == 0){
823 // printf("Exif section in Intel order\n");
824 MotorolaOrder = 0;
825 }else{
826 if (memcmp(CharBuf+8,"MM",2) == 0){
827 // printf("Exif section in Motorola order\n");
828 MotorolaOrder = 1;
829 }else{
830 return;
831 }
832 }
833
834 // Check the next two values for correctness.
835 if (Get16u(CharBuf+10) != 0x2a
836 || Get32u(CharBuf+12) != 0x08){
837 return;
838 }
839
840 LastExifRefd = CharBuf;
841
842 // First directory starts 16 bytes in. Offsets start at 8 bytes in.
843 ProcessExifDir(CharBuf+16, CharBuf+8, length-6);
844
845 // This is how far the interesting (non thumbnail) part of the exif went.
846 ExifSettingsLength = LastExifRefd - CharBuf;
847
848 // Compute the CCD width, in milimeters.
849 if (FocalplaneXRes != 0){
850 ExifData::CCDWidth = (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes);
851 }
852}
853
854//--------------------------------------------------------------------------
855// Convert exif time to Unix time structure
856//--------------------------------------------------------------------------
857int ExifData::Exif2tm(struct tm * timeptr, char * ExifTime)
858{
859 int a;
860
861 timeptr->tm_wday = -1;
862
863 // Check for format: YYYY:MM:DD HH:MM:SS format.
864 a = sscanf(ExifTime, "%d:%d:%d %d:%d:%d",
865 &timeptr->tm_year, &timeptr->tm_mon, &timeptr->tm_mday,
866 &timeptr->tm_hour, &timeptr->tm_min, &timeptr->tm_sec);
867
868 if (a == 6){
869 timeptr->tm_isdst = -1;
870 timeptr->tm_mon -= 1; // Adjust for unix zero-based months
871 timeptr->tm_year -= 1900; // Adjust for year starting at 1900
872 return true; // worked.
873 }
874
875 return false; // Wasn't in Exif date format.
876}
877
878//--------------------------------------------------------------------------
879// Contructor for initialising
880//--------------------------------------------------------------------------
881ExifData::ExifData()
882{
883 ExifData::Whitebalance = -1;
884 ExifData::MeteringMode = -1;
885 ExifData::FlashUsed = -1;
886 Orientation = 0;
887 Height = 0;
888 Width = 0;
889 IsColor = 0;
890 Process = 0;
891 FocalLength = 0;
892 ExposureTime = 0;
893 ApertureFNumber = 0;
894 Distance = 0;
895 CCDWidth = 0;
896 ExposureBias = 0;
897 ExposureProgram = 0;
898 ISOequivalent = 0;
899 CompressionLevel = 0;
900}
901
902//--------------------------------------------------------------------------
903// process a EXIF jpeg file
904//--------------------------------------------------------------------------
905bool ExifData::scan(const QString & path)
906{
907 int ret;
908
909 QFile f(path);
910 f.open(IO_ReadOnly);
911
912 // Scan the JPEG headers.
913 ret = ReadJpegSections(f, READ_EXIF);
914
915 if (ret == false){
916 qWarning( "Not JPEG file!" );
917 DiscardData();
918 f.close();
919 return false;
920 }
921 f.close();
922 DiscardData();
923
924 //now make the strings clean,
925 // for exmaple my Casio is a "QV-4000 "
926 CameraMake = CameraMake.stripWhiteSpace();
927 CameraModel = CameraModel.stripWhiteSpace();
928 UserComment = UserComment.stripWhiteSpace();
929 Comment = Comment.stripWhiteSpace();
930 return true;
931}
932
933//--------------------------------------------------------------------------
934// Does the embedded thumbnail match the jpeg image?
935//--------------------------------------------------------------------------
936#ifndef JPEG_TOL
937#define JPEG_TOL 0.02
938#endif
939bool ExifData::isThumbnailSane() {
940 if (Thumbnail.isNull()) return false;
941
942 // check whether thumbnail dimensions match the image
943 // not foolproof, but catches some altered images (jpegtran -rotate)
944 if (ExifImageLength != 0 && ExifImageLength != Height) return false;
945 if (ExifImageWidth != 0 && ExifImageWidth != Width) return false;
946 if (Thumbnail.width() == 0 || Thumbnail.height() == 0) return false;
947 if (Height == 0 || Width == 0) return false;
948 double d = (double)Height/Width*Thumbnail.width()/Thumbnail.height();
949 return (1-JPEG_TOL < d) && (d < 1+JPEG_TOL);
950}
951
952
953
954static QImage flip_image( const QImage& img );
955static QImage rotate_90( const QImage& img );
956static QImage rotate_180( const QImage& );
957static QImage rotate_270( const QImage& );
958
959//--------------------------------------------------------------------------
960// return a thumbnail that respects the orientation flag
961// only if it seems sane
962//--------------------------------------------------------------------------
963QImage ExifData::getThumbnail() {
964 if (!isThumbnailSane()) return NULL;
965 if (!Orientation || Orientation == 1) return Thumbnail;
966
967 // now fix orientation
968
969 QImage dest = Thumbnail;
970 switch (Orientation) { // notice intentional fallthroughs
971 case 2: dest = flip_image( dest ); break;
972 case 4: dest = flip_image( dest );
973 case 3: dest =rotate_180( dest ); break;
974 case 5: dest = flip_image( dest );
975 case 6: dest = rotate_90( dest ); break;
976 case 7: dest = flip_image( dest );
977 case 8: dest = rotate_270( dest ); break;
978 default: break; // should never happen
979 }
980 return dest;
981}
982
983
984/*
985 *
986 */
987static QImage flip_image( const QImage& img ) {
988 return img.mirror( TRUE, FALSE );
989}
990
991
992static QImage dest;
993static int x, y;
994static unsigned int *srcData, *destData; // we're not threaded anyway
995static unsigned char *srcData8, *destData8; // 8 bit is char
996static unsigned int *srcTable, *destTable; // destination table
997
998
999static QImage rotate_90_8( const QImage &img ) {
1000 dest.create(img.height(), img.width(), img.depth());
1001 dest.setNumColors(img.numColors());
1002 srcTable = (unsigned int *)img.colorTable();
1003 destTable = (unsigned int *)dest.colorTable();
1004 for ( x=0; x < img.numColors(); ++x )
1005 destTable[x] = srcTable[x];
1006 for ( y=0; y < img.height(); ++y ){
1007 srcData8 = (unsigned char *)img.scanLine(y);
1008 for ( x=0; x < img.width(); ++x ){
1009 destData8 = (unsigned char *)dest.scanLine(x);
1010 destData8[img.height()-y-1] = srcData8[x];
1011 }
1012 }
1013 return dest;
1014}
1015
1016static QImage rotate_90_all( const QImage& img ) {
1017 dest.create(img.height(), img.width(), img.depth());
1018 for ( y=0; y < img.height(); ++y ) {
1019 srcData = (unsigned int *)img.scanLine(y);
1020 for ( x=0; x < img.width(); ++x ) {
1021 destData = (unsigned int *)dest.scanLine(x);
1022 destData[img.height()-y-1] = srcData[x];
1023 }
1024 }
1025
1026 return dest;
1027}
1028
1029
1030static QImage rotate_90( const QImage & img ) {
1031 if ( img.depth() > 8)
1032 return rotate_90_all( img );
1033 else
1034 return rotate_90_8( img );
1035}
1036
1037static QImage rotate_180_all( const QImage& img ) {
1038 dest.create(img.width(), img.height(), img.depth());
1039 for ( y=0; y < img.height(); ++y ){
1040 srcData = (unsigned int *)img.scanLine(y);
1041 destData = (unsigned int *)dest.scanLine(img.height()-y-1);
1042 for ( x=0; x < img.width(); ++x )
1043 destData[img.width()-x-1] = srcData[x];
1044 }
1045 return dest;
1046}
1047
1048static QImage rotate_180_8( const QImage& img ) {
1049 dest.create(img.width(), img.height(), img.depth());
1050 dest.setNumColors(img.numColors());
1051 srcTable = (unsigned int *)img.colorTable();
1052 destTable = (unsigned int *)dest.colorTable();
1053 for ( x=0; x < img.numColors(); ++x )
1054 destTable[x] = srcTable[x];
1055 for ( y=0; y < img.height(); ++y ){
1056 srcData8 = (unsigned char *)img.scanLine(y);
1057 destData8 = (unsigned char *)dest.scanLine(img.height()-y-1);
1058 for ( x=0; x < img.width(); ++x )
1059 destData8[img.width()-x-1] = srcData8[x];
1060 }
1061 return dest;
1062}
1063
1064static QImage rotate_180( const QImage& img ) {
1065 if ( img.depth() > 8 )
1066 return rotate_180_all( img );
1067 else
1068 return rotate_180_8( img );
1069}
1070
1071
1072static QImage rotate_270_8( const QImage& img ) {
1073 dest.create(img.height(), img.width(), img.depth());
1074 dest.setNumColors(img.numColors());
1075 srcTable = (unsigned int *)img.colorTable();
1076 destTable = (unsigned int *)dest.colorTable();
1077 for ( x=0; x < img.numColors(); ++x )
1078 destTable[x] = srcTable[x];
1079 for ( y=0; y < img.height(); ++y ){
1080 srcData8 = (unsigned char *)img.scanLine(y);
1081 for ( x=0; x < img.width(); ++x ){
1082 destData8 = (unsigned char *)dest.scanLine(img.width()-x-1);
1083 destData8[y] = srcData8[x];
1084 }
1085 }
1086
1087 return dest;
1088}
1089
1090static QImage rotate_270_all( const QImage& img ) {
1091 dest.create(img.height(), img.width(), img.depth());
1092 for ( y=0; y < img.height(); ++y ){
1093 srcData = (unsigned int *)img.scanLine(y);
1094 for ( x=0; x < img.width(); ++x ){
1095 destData = (unsigned int *)dest.scanLine(img.width()-x-1);
1096 destData[y] = srcData[x];
1097 }
1098 }
1099 return dest;
1100}
1101
1102static QImage rotate_270( const QImage& img ) {
1103 if ( img.depth() > 8 )
1104 return rotate_270_all( img );
1105 else
1106 return rotate_270_8( img );
1107}
1108
1109
1110static QString color_mode_to_string( bool b ) {
1111 return b ? QObject::tr( "Colormode: Color\n" ) : QObject::tr( "Colormode: Black and white\n" );
1112}
1113
1114static QString compression_to_string( int level ) {
1115 QString str;
1116 switch( level ) {
1117 case 1:
1118 str = QObject::tr( "Basic" );
1119 break;
1120 case 2:
1121 str = QObject::tr( "Normal" );
1122 break;
1123 case 4:
1124 str = QObject::tr( "Fine" );
1125 break;
1126 default:
1127 str = QObject::tr( "Unknown" );
1128
1129 }
1130 return QObject::tr("Quality: %1\n").arg(str);
1131}
1132
1133
1134static QDateTime parseDateTime( const QString& string )
1135{
1136 QDateTime dt;
1137 if ( string.length() != 19 )
1138 return dt;
1139
1140 QString year = string.left( 4 );
1141 QString month = string.mid( 5, 2 );
1142 QString day = string.mid( 8, 2 );
1143 QString hour = string.mid( 11, 2 );
1144 QString minute = string.mid( 14, 2 );
1145 QString seconds = string.mid( 18, 2 );
1146
1147 bool ok;
1148 bool allOk = true;
1149 int y = year.toInt( &ok );
1150 allOk &= ok;
1151
1152 int mo = month.toInt( &ok );
1153 allOk &= ok;
1154
1155 int d = day.toInt( &ok );
1156 allOk &= ok;
1157
1158 int h = hour.toInt( &ok );
1159 allOk &= ok;
1160
1161 int mi = minute.toInt( &ok );
1162 allOk &= ok;
1163
1164 int s = seconds.toInt( &ok );
1165 allOk &= ok;
1166
1167 if ( allOk ) {
1168 dt.setDate( QDate( y, mo, d ) );
1169 dt.setTime( QTime( h, mi, s ) );
1170 }
1171
1172 return dt;
1173}
1174
1175static QString white_balance_string( int i ) {
1176 QString balance;
1177 switch ( i ) {
1178 case 0:
1179 balance = QObject::tr( "Unknown" );
1180 break;
1181 case 1:
1182 balance = QObject::tr( "Daylight" );
1183 break;
1184 case 2:
1185 balance = QObject::tr( "Fluorescent" );
1186 break;
1187 case 3:
1188 balance = QObject::tr( "Tungsten" );
1189 break;
1190 case 17:
1191 balance = QObject::tr( "Standard light A" );
1192 break;
1193 case 18:
1194 balance = QObject::tr( "Standard light B" );
1195 break;
1196 case 19:
1197 balance = QObject::tr( "Standard light C" );
1198 break;
1199 case 20:
1200 balance = QObject::tr( "D55" );
1201 break;
1202 case 21:
1203 balance = QObject::tr( "D65" );
1204 break;
1205 case 22:
1206 balance = QObject::tr( "D75" );
1207 break;
1208 case 255:
1209 balance = QObject::tr( "Other" );
1210 break;
1211 default:
1212 balance = QObject::tr( "Unknown" );
1213 }
1214 return QObject::tr( "White Balance: %1\n" ).arg( balance );
1215
1216}
1217
1218
1219static QString metering_mode( int i) {
1220 QString meter;
1221 switch( i ) {
1222 case 0:
1223 meter = QObject::tr( "Unknown" );
1224 break;
1225 case 1:
1226 meter = QObject::tr( "Average" );
1227 break;
1228 case 2:
1229 meter = QObject::tr( "Center weighted average" );
1230 break;
1231 case 3:
1232 meter = QObject::tr( "Spot" );
1233 break;
1234 case 4:
1235 meter = QObject::tr( "MultiSpot" );
1236 break;
1237 case 5:
1238 meter = QObject::tr( "Pattern" );
1239 break;
1240 case 6:
1241 meter = QObject::tr( "Partial" );
1242 break;
1243 case 255:
1244 meter = QObject::tr( "Other" );
1245 break;
1246 default:
1247 meter = QObject::tr( "Unknown" );
1248 }
1249
1250 return QObject::tr( "Metering Mode: %1\n" ).arg( meter );
1251}
1252
1253
1254static QString exposure_program( int i ) {
1255 QString exp;
1256 switch( i ) {
1257 case 0:
1258 exp = QObject::tr( "Not defined" );
1259 break;
1260 case 1:
1261 exp = QObject::tr( "Manual" );
1262 break;
1263 case 2:
1264 exp = QObject::tr( "Normal progam" );
1265 break;
1266 case 3:
1267 exp = QObject::tr( "Aperture priority" );
1268 break;
1269 case 4:
1270 exp = QObject::tr( "Shutter priority" );
1271 break;
1272 case 5:
1273 exp = QObject::tr( "Creative progam\n(biased toward fast shutter speed" );
1274 break;
1275 case 6:
1276 exp = QObject::tr( "Action progam\n(biased toward fast shutter speed)" );
1277 break;
1278 case 7:
1279 exp = QObject::tr( "Portrait mode\n(for closeup photos with the background out of focus)" );
1280 break;
1281 case 8:
1282 exp = QObject::tr( "Landscape mode\n(for landscape photos with the background in focus)" );
1283 break;
1284 default:
1285 exp = QObject::tr( "Unknown" );
1286 }
1287
1288 return QObject::tr( "Exposure Program: %1\n" ).arg( exp );
1289}
1290
1291JpegSlave::JpegSlave()
1292 : SlaveInterface( QStringList::split( " ", "jpeg jpg" ) )
1293{}
1294
1295JpegSlave::~JpegSlave() {}
1296
1297QString JpegSlave::iconViewName( const QString& path) {
1298 ExifData ImageInfo;
1299 if ( !ImageInfo.scan( path ) )
1300 return QString::null;
1301
1302 QString tag;
1303 tag = QObject::tr( "<qt>Comment: %1\n" ).arg( ImageInfo.getComment() );
1304 {
1305// ODP fixme
1306 QString timestring = TimeString::dateString( parseDateTime( ImageInfo.getDateTime() ), FALSE );
1307 tag += QObject::tr( "Date/Time: %1\n" ).arg( timestring );
1308 }
1309 tag += QObject::tr( "Dimensions: %1x%2\n" ).arg(ImageInfo.getWidth())
1310 .arg(ImageInfo.getHeight() );
1311
1312 tag += color_mode_to_string( ImageInfo.getIsColor() );
1313
1314 tag += compression_to_string( ImageInfo.getCompressionLevel() );
1315 tag += QObject::tr( "</qt>" );
1316
1317 return tag;
1318}
1319
1320
1321/*
1322 * messy messy string creation
1323 */
1324QString JpegSlave::fullImageInfo( const QString& path) {
1325 ExifData ImageInfo;
1326 if ( !ImageInfo.scan( path ) )
1327 return QString::null;
1328
1329 QString tag, tmp;
1330 tag = QObject::tr( "Comment: %1\n" ).arg( ImageInfo.getComment() );
1331
1332 tmp = ImageInfo.getCameraMake();
1333 if ( tmp.length() )
1334 tag += QObject::tr( "Manufacturer: %1\n" ).arg( tmp );
1335 tmp = ImageInfo.getCameraModel();
1336 if ( tmp.length() )
1337 tag += QObject::tr( "Model: %1\n" ).arg( tmp );
1338 {
1339// ODP fixme
1340 tmp = TimeString::dateString( parseDateTime( ImageInfo.getDateTime() ), FALSE );
1341 tag += QObject::tr( "Date/Time: %1\n" ).arg( tmp );
1342 }
1343 tag += QObject::tr( "Dimensions: %1x%2\n" ).arg(ImageInfo.getWidth())
1344 .arg(ImageInfo.getHeight() );
1345
1346 tag += color_mode_to_string( ImageInfo.getIsColor() );
1347
1348 tag += compression_to_string( ImageInfo.getCompressionLevel() );
1349 if ( ImageInfo.getOrientation() )
1350 tag += QObject::tr( "Orientation: %1\n" ).arg(ImageInfo.getOrientation() );
1351
1352
1353 {
1354 int flash_used = ImageInfo.getFlashUsed();
1355 if ( flash_used >= 0 )
1356 tag += QObject::tr( "Flash used\n" );
1357 }
1358
1359 if ( ImageInfo.getFocalLength() ) {
1360 tag += QObject::tr( "Focal length: %1\n" ).arg( QString().sprintf( "%4.1f", ImageInfo.getFocalLength() ) );
1361 if ( ImageInfo.getCCDWidth() )
1362 tag += QObject::tr( "35mm equivalent: %1\n" ).arg( (int)(ImageInfo.getFocalLength()/ImageInfo.getCCDWidth()*35 + 0.5) );
1363
1364 }
1365
1366 if ( ImageInfo.getCCDWidth() )
1367 tag += QObject::tr( "CCD width: %1" ).arg( ImageInfo.getCCDWidth() );
1368 if ( ImageInfo.getExposureTime() ) {
1369 tmp = QString().sprintf("%4.2f", ImageInfo.getExposureTime() );
1370 float exposureTime = ImageInfo.getExposureTime();
1371 if ( exposureTime > 0 && exposureTime <= 0.5 )
1372 tmp += QString().sprintf(" (1/%d)", (int)(0.5 +1/exposureTime) );
1373 tag += QObject::tr( "Exposure time: %1\n" ).arg( tmp );
1374 }
1375
1376 if ( ImageInfo.getApertureFNumber() )
1377 tag += QObject::tr( "Aperture: %1\n" ).arg( QString().sprintf("f/%3.1f", (double)ImageInfo.getApertureFNumber() ) );
1378
1379 if ( ImageInfo.getDistance() ) {
1380 if ( ImageInfo.getDistance() < 0 )
1381 tag += QObject::tr( "Distance: %1\n" ).arg( QObject::tr( "Infinite" ) );
1382 else
1383 tag += QObject::tr( "Distance: %1\n" ).arg( QString().sprintf( "%5.2fm", (double)ImageInfo.getDistance() ) );
1384 }
1385
1386 if ( ImageInfo.getExposureBias() ) {
1387 tag += QObject::tr( "Exposure bias: %1\n", QString().sprintf("%4.2f", (double)ImageInfo.getExposureBias() ) );
1388 }
1389
1390 if ( ImageInfo.getWhitebalance() != -1 )
1391 tag += white_balance_string( ImageInfo.getWhitebalance() );
1392
1393
1394 if( ImageInfo.getMeteringMode() != -1 )
1395 tag += metering_mode( ImageInfo.getMeteringMode() );
1396
1397 if ( ImageInfo.getExposureProgram() )
1398 tag += exposure_program( ImageInfo.getExposureProgram() );
1399 if ( ImageInfo.getISOequivalent() )
1400 tag += QObject::tr( "ISO equivalent: %1\n" ).arg( QString().sprintf("%2d", ImageInfo.getISOequivalent() ) );
1401
1402 tmp = ImageInfo.getUserComment();
1403 if ( tmp.length() )
1404 tag += QObject::tr( "EXIF comment: %1" ).arg( tmp );
1405
1406 tag += QObject::tr( "</qt>" );
1407
1408
1409
1410 return tag;
1411}
1412
1413QPixmap JpegSlave::pixmap( const QString& path, int wid, int hei) {
1414 ExifData ImageInfo;
1415 if ( !ImageInfo.scan( path ) || ImageInfo.isNullThumbnail() ) {
1416 QImage img;
1417 QImageIO iio( path, 0l );
1418 QString str = QString( "Fast Shrink( 4 ) Scale( %1, %2, ScaleFree)" ).arg( wid ).arg( hei );
1419 iio.setParameters( str.latin1() );// will be strdupped anyway
1420 img = iio.read() ? iio.image() : QImage();
1421 return ThumbNailTool::scaleImage( img, wid,hei );
1422 }else{
1423 QImage img = ImageInfo.getThumbnail();
1424 return ThumbNailTool::scaleImage( img, wid,hei );
1425 }
1426}
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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 */
4#ifndef JPEG_SLAVE_IMPL_H
5#define JPEG_SLAVE_IMPL_H
6
7#include "slaveiface.h"
8
9class JpegSlave : public SlaveInterface {
10public:
11 JpegSlave();
12 ~JpegSlave();
13
14 QString iconViewName( const QString& );
15 QString fullImageInfo( const QString& );
16 QPixmap pixmap( const QString&, int, int );
17};
18
19#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 @@
1/*
2 * GPLv2 Slave Main
3 */
4
5#include "gif_slave.h"
6#include "png_slave.h"
7#include "jpeg_slave.h"
8#include "thumbnailtool.h"
9#include "slavereciever.h"
10
11#include <qpixmap.h>
12#include <qcopchannel_qws.h>
13
14#include <qtopia/qpeapplication.h>
15
16int main( int argc, char* argv[] ) {
17 QPEApplication app( argc, argv );
18 SlaveReciever rec( 0 );
19
20 QCopChannel chan( "QPE/opie-eye_slave" );
21 QObject::connect(&chan,SIGNAL(received(const QCString&, const QByteArray&)),
22 &rec, SLOT(recieveAnswer(const QCString&,const QByteArray&)));
23 QObject::connect(qApp,SIGNAL(appMessage(const QCString&, const QByteArray&)),
24 &rec, SLOT(recieveAnswer(const QCString&,const QByteArray&)));
25
26 return app.exec();
27}
28
29#ifdef DEBUG_IT
30int main( int argc, char* argv[] ) {
31 QString str = QString::fromLatin1(argv[2] );
32 QApplication app( argc, argv );
33 GifSlave slave;
34 qWarning( str +" "+slave.iconViewName(str ) );
35 qWarning( str+" "+slave.fullImageInfo( str ) );
36
37 PNGSlave pngslave;
38 qWarning( str + " " + pngslave.iconViewName(str) );
39 qWarning( str + " " + pngslave.fullImageInfo(str));
40
41
42 JpegSlave jpgslave;
43 qWarning( str + " " + jpgslave.iconViewName(str ) );
44 qWarning( str + " " + jpgslave.fullImageInfo( str ) );
45//return app.exec();
46 QPixmap pix = ThumbNailTool::getThumb( str, 24, 24 );
47 if ( pix.isNull() ) {
48 qWarning( "No Thumbnail" );
49 pix = slave.pixmap(str, 24, 24);
50 }
51
52 if (!pix.isNull() ) {
53 qWarning( "Saving Thumbnail" );
54 ThumbNailTool::putThumb( str, pix, 24, 24 );
55 }
56
57}
58
59#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 @@
1#include "png_slave.h"
2
3#include "thumbnailtool.h"
4
5#include <qobject.h>
6#include <qfile.h>
7#include <qimage.h>
8#include <qpixmap.h>
9#include <qstring.h>
10
11/*
12 * GPLv2 from kfile plugin
13 */
14PHUNK_VIEW_INTERFACE( "PNG", PNGSlave );
15
16#define CHUNK_SIZE(data, index) ((data[index ]<<24) + (data[index+1]<<16) + \
17 (data[index+2]<< 8) + data[index+3])
18#define CHUNK_TYPE(data, index) &data[index+4]
19#define CHUNK_HEADER_SIZE 12
20#define CHUNK_DATA(data, index, offset) data[8+index+offset]
21
22/* TRANSLATOR QObject */
23
24// known translations for common png keys
25static const char* knownTranslations[]
26#ifdef __GNUC__
27__attribute__((unused))
28#endif
29 = {
30 QT_TR_NOOP("Title"),
31 QT_TR_NOOP("Author"),
32 QT_TR_NOOP("Description"),
33 QT_TR_NOOP("Copyright"),
34 QT_TR_NOOP("Creation Time"),
35 QT_TR_NOOP("Software"),
36 QT_TR_NOOP("Disclaimer"),
37 QT_TR_NOOP("Warning"),
38 QT_TR_NOOP("Source"),
39 QT_TR_NOOP("Comment")
40};
41
42// and for the colors
43static const char* colors[] = {
44 QT_TR_NOOP("Grayscale"),
45 QT_TR_NOOP("Unknown"),
46 QT_TR_NOOP("RGB"),
47 QT_TR_NOOP("Palette"),
48 QT_TR_NOOP("Grayscale/Alpha"),
49 QT_TR_NOOP("Unknown"),
50 QT_TR_NOOP("RGB/Alpha")
51};
52
53 // and compressions
54static const char* compressions[] =
55{
56 QT_TR_NOOP("Deflate")
57};
58
59 // interlaced modes
60static const char* interlaceModes[] = {
61 QT_TR_NOOP("None"),
62 QT_TR_NOOP("Adam7")
63};
64
65
66static void read_comment( const QString& inf,
67 bool readComments, QString& str ) {
68 QFile f(inf);
69 f.open(IO_ReadOnly);
70
71 if (f.size() < 26) return;
72 // the technical group will be read from the first 26 bytes. If the file
73 // is smaller, we can't even read this.
74
75 uchar *data = new uchar[f.size()+1];
76 f.readBlock(reinterpret_cast<char*>(data), f.size());
77 data[f.size()]='\n';
78
79 // find the start
80 if (data[0] == 137 && data[1] == 80 && data[2] == 78 && data[3] == 71 &&
81 data[4] == 13 && data[5] == 10 && data[6] == 26 && data[7] == 10 )
82 {
83 // ok
84 // the IHDR chunk should be the first
85 if (!strncmp((char*)&data[12], "IHDR", 4))
86 {
87 // we found it, get the dimensions
88 ulong x,y;
89 x = (data[16]<<24) + (data[17]<<16) + (data[18]<<8) + data[19];
90 y = (data[20]<<24) + (data[21]<<16) + (data[22]<<8) + data[23];
91
92 uint type = data[25];
93 uint bpp = data[24];
94
95 // the bpp are only per channel, so we need to multiply the with
96 // the channel count
97 switch (type)
98 {
99 case 0: break; // Grayscale
100 case 2: bpp *= 3; break; // RGB
101 case 3: break; // palette
102 case 4: bpp *= 2; break; // grayscale w. alpha
103 case 6: bpp *= 4; break; // RGBA
104
105 default: // we don't get any sensible value here
106 bpp = 0;
107 }
108
109
110 str = QObject::tr("Dimensions: %1x%2\n" ).arg(x).arg(y);
111 str += QObject::tr("Depth: %1\n" ).arg(bpp);
112 str += QObject::tr("ColorMode: %1\n").arg(
113 (type < sizeof(colors)/sizeof(colors[0]))
114 ? QObject::tr(colors[data[25]]) : QObject::tr("Unknown") );
115
116 str += QObject::tr("Compression: %1\n").arg(
117 (data[26] < sizeof(compressions)/sizeof(compressions[0]))
118 ? QObject::tr(compressions[data[26]]) : QObject::tr("Unknown") );
119
120 str += QObject::tr("InterlaceMode: %1\n" ).arg(
121 (data[28] < sizeof(interlaceModes)/sizeof(interlaceModes[0]))
122 ? QObject::tr(interlaceModes[data[28]]) : QObject::tr("Unknown"));
123 }
124
125 if ( readComments ) {
126 uint index = 8;
127 index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE;
128
129 while(index<f.size()-12)
130 {
131 while (index < f.size() - 12 &&
132 strncmp((char*)CHUNK_TYPE(data,index), "tEXt", 4))
133 {
134 if (!strncmp((char*)CHUNK_TYPE(data,index), "IEND", 4))
135 goto end;
136
137 index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE;
138 }
139
140 if (index < f.size() - 12)
141 {
142 // we found a tEXt field
143 // get the key, it's a null terminated string at the
144 // chunk start
145
146 uchar* key = &CHUNK_DATA(data,index,0);
147
148 int keysize=0;
149 for (;key[keysize]!=0; keysize++)
150 // look if we reached the end of the file
151 // (it might be corrupted)
152 if (8+index+keysize>=f.size())
153 goto end;
154
155 // the text comes after the key, but isn't null terminated
156 uchar* text = &CHUNK_DATA(data,index, keysize+1);
157 uint textsize = CHUNK_SIZE(data, index)-keysize-1;
158
159 // security check, also considering overflow wraparound from the addition --
160 // we may endup with a /smaller/ index if we wrap all the way around
161 uint firstIndex = (uint)(text - data);
162 uint onePastLastIndex = firstIndex + textsize;
163
164 if ( onePastLastIndex > f.size() || onePastLastIndex <= firstIndex)
165 goto end;
166
167 QByteArray arr(textsize);
168 arr = QByteArray(textsize).duplicate((const char*)text,
169 textsize);
170 str += QObject::tr(
171 QString(reinterpret_cast<char*>(key)),
172 QString(arr) );
173
174 index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE;
175 }
176 }
177 }
178 }
179end:
180 delete[] data;
181
182}
183
184
185PNGSlave::PNGSlave()
186 : SlaveInterface("png")
187{
188}
189PNGSlave::~PNGSlave() {
190}
191QString PNGSlave::iconViewName( const QString& path) {
192 QString str;
193 read_comment( path, false, str );
194 return str;
195}
196
197QString PNGSlave::fullImageInfo( const QString& path) {
198 QString str;
199 read_comment( path, true, str );
200 return str;
201}
202
203
204QPixmap PNGSlave::pixmap( const QString& path, int width, int height) {
205 QImage img; img.load( path );
206 if ( img.isNull() )
207 return QPixmap();
208 else
209 return ThumbNailTool::scaleImage( img, width,height );
210}
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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 */
4#ifndef PNG_SLAVE_IMPL_H
5#define PNG_SLAVE_IMPL_H
6
7#include "slaveiface.h"
8
9class QString;
10class QPixmap;
11class PNGSlave : public SlaveInterface {
12public:
13 PNGSlave();
14 ~PNGSlave();
15
16 QString iconViewName( const QString& );
17 QString fullImageInfo( const QString& );
18 QPixmap pixmap( const QString&, int, int );
19};
20
21#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 @@
1CONFIG += qte
2TEMPLATE = app
3TARGET = opie-eye_slave
4DESTDIR = $(OPIEDIR)/bin
5
6HEADERS = gif_slave.h slaveiface.h slavereciever.h \
7 thumbnailtool.h png_slave.h jpeg_slave.h \
8 ../iface/slaveiface.h
9SOURCES = main.cpp gif_slave.cpp slavereciever.cpp \
10 slaveiface.cpp thumbnailtool.cpp png_slave.cpp \
11 jpeg_slave.cpp
12
13INCLUDEPATH += $(OPIEDIR)/include ../
14DEPENDSPATH += $(OPIEDIR)/include
15
16LIBS += -lqpe
17
18include ( $(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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 */
4
5#include "slaveiface.h"
6
7static SlaveMap* _slaveMap = 0;
8SlaveMap* slaveMap() {
9 if ( !_slaveMap )
10 _slaveMap = new SlaveMap;
11 return _slaveMap;
12}
13
14SlaveInterface::SlaveInterface( const QStringList& image )
15 : m_list( image )
16{
17
18}
19
20SlaveInterface::~SlaveInterface() {
21
22}
23
24QStringList SlaveInterface::imageFormats()const {
25 return m_list;
26}
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 @@
1/*
2 * GPLv2
3 */
4
5#ifndef P_SLAVE_INTER_FACE_H
6#define P_SLAVE_INTER_FACE_H
7
8#include <qfileinfo.h>
9#include <qstringlist.h>
10#include <qmap.h>
11
12/**
13 * @short The slave worker Interface for generating Preview + Image Info + Full
14 * IMage Info
15 */
16class QPixmap;
17class SlaveInterface {
18public:
19 SlaveInterface(const QStringList& imageformats);
20 virtual ~SlaveInterface();
21
22 QStringList imageFormats()const;
23 bool supports( const QString& )const;
24 virtual QString iconViewName(const QString&) = 0;
25 virtual QString fullImageInfo(const QString& )= 0;
26 virtual QPixmap pixmap( const QString&, int width, int height ) = 0;
27private:
28 QStringList m_list;
29};
30
31inline bool SlaveInterface::supports( const QString& str)const {
32 return m_list.contains( QFileInfo( str ).extension(false) );
33}
34
35typedef SlaveInterface* (*phunkSlaveCreateFunc )();
36typedef QMap<QString,phunkSlaveCreateFunc> SlaveMap;
37
38typedef QMap<QString, SlaveInterface*> SlaveObjects;
39
40SlaveMap* slaveMap();
41SlaveObjects* slaveObjects();
42
43
44
45#define PHUNK_VIEW_INTERFACE( NAME, IMPL ) \
46 static SlaveInterface *create_ ## IMPL() { \
47 return new IMPL(); \
48 } \
49 static SlaveMap::Iterator dummy_ ## IMPL = slaveMap()->insert( NAME, create_ ## IMPL );
50
51
52
53#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 @@
1/*
2 * GPLv2 zecke@handhelds.org
3 */
4
5#include "slavereciever.h"
6#include "slaveiface.h"
7
8#include <qpe/qcopenvelope_qws.h>
9#include <qpe/qpeapplication.h>
10
11#include <qtimer.h>
12
13static SlaveObjects* _slaveObj = 0;
14
15QDataStream & operator << (QDataStream & str, bool b)
16{
17 str << Q_INT8(b);
18 return str;
19}
20
21QDataStream & operator >> (QDataStream & str, bool & b)
22{
23 Q_INT8 l;
24 str >> l;
25 b = bool(l);
26 return str;
27}
28
29
30
31QDataStream &operator<<( QDataStream& s, const PixmapInfo& inf) {
32 return s << inf.file << inf.pixmap << inf.width << inf.height;
33}
34QDataStream &operator>>( QDataStream& s, PixmapInfo& inf ) {
35 s >> inf.file >> inf.pixmap >> inf.width >> inf.height;
36 return s;
37}
38QDataStream &operator<<( QDataStream& s, const ImageInfo& i) {
39 return s << i.kind << i.file << i.info;
40}
41QDataStream &operator>>( QDataStream& s, ImageInfo& i ) {
42 s >> i.kind >> i.file >> i.info;
43 return s;
44}
45
46
47
48SlaveObjects* slaveObjects() {
49 if ( !_slaveObj )
50 _slaveObj = new SlaveObjects;
51 return _slaveObj;
52}
53
54SlaveReciever::SlaveReciever( QObject* par)
55 : QObject( par )
56{
57 m_inf = new QTimer(this);
58 connect(m_inf,SIGNAL(timeout()),
59 this, SLOT(slotImageInfo()));
60 m_pix = new QTimer(this);
61 connect(m_pix,SIGNAL(timeout()),
62 this, SLOT(slotThumbNail()));
63
64 m_out = new QTimer(this);
65 connect(m_out,SIGNAL(timeout()),
66 this, SLOT(slotSend()));
67
68 SlaveObjects *obj = slaveObjects(); // won't be changed
69 SlaveMap::Iterator it;
70 SlaveMap* map = slaveMap(); // SlaveMap won't be changed during execution!!!
71 for(it = map->begin(); it != map->end(); ++it ) {
72 obj->insert( it.key(), (*it.data())() );
73 }
74}
75
76SlaveReciever::~SlaveReciever() {
77}
78
79void SlaveReciever::recieveAnswer( const QCString& string, const QByteArray& ar) {
80 qWarning( "String is %s", string.data() );
81 QDataStream stream(ar, IO_ReadOnly );
82 QStringList lst;
83 static ImageInfo inf;
84 static PixmapInfo pix;
85
86 if ( string == "thumbInfo(QString)" ) {
87 stream >> inf.file;
88 m_inList.append(inf);
89 }else if ( string == "thumbInfos(QStringList)" ) {
90 stream >> lst;
91 for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) {
92 qWarning( "Adding thumbinfo for file "+ *it );
93 inf.file = (*it);
94 m_inList.append(inf);
95 }
96 }else if ( string == "fullInfo(QString)" ) {
97 inf.kind = true;
98 stream >> inf.file;
99 m_inList.append(inf);
100 }else if ( string == "fullInfos(QStringList)" ) {
101 stream >> lst;
102 for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) {
103 qWarning( "Adding fullInfo for"+ *it );
104 inf.file = (*it);
105 inf.kind = true;
106 m_inList.append(inf);
107 }
108 }else if ( string == "pixmapInfo(QString,int,int)" ) {
109 stream >> pix.file >> pix.width >> pix.height;
110 m_inPix.append(pix);
111 }else if ( string == "pixmapInfos(PixmapInfos)" ) {
112 PixmapList list;
113 stream >> list;
114 for(PixmapList::Iterator it = list.begin(); it != list.end(); ++it ) {
115 qWarning( "Got %d %d " + (*it).file, (*it).width , (*it).height );
116 m_inPix.append(*it);
117 }
118 }
119
120 if (!m_inf->isActive() && !m_inList.isEmpty() )
121 m_inf->start(5);
122
123 if (!m_pix->isActive() && !m_inPix.isEmpty() )
124 m_pix->start(5);
125
126 QPEApplication::setKeepRunning();
127
128}
129
130PixmapList SlaveReciever::outPix()const {
131 return m_outPix;
132}
133
134StringList SlaveReciever::outInf()const{
135 return m_outList;
136}
137
138void SlaveReciever::slotImageInfo() {
139 ImageInfo inf = m_inList.first();
140 m_inList.remove( inf );
141
142 static SlaveObjects::Iterator it;
143 static SlaveObjects* map = slaveObjects(); // SlaveMap won't be changed during execution!!!
144 for(it = map->begin(); it != map->end(); ++it ) {
145 if( (*it)->supports(inf.file ) ) {
146 /* full image info */
147 if (inf.kind )
148 inf.info = (*it)->fullImageInfo( inf.file );
149 else
150 inf.info = (*it)->iconViewName( inf.file );
151 m_outList.append( inf );
152 break;
153 }
154 }
155
156 if (m_inList.isEmpty() )
157 m_inf->stop();
158 if (!m_out->isActive() && !m_outList.isEmpty() )
159 m_out->start( 100 );
160}
161
162void SlaveReciever::slotThumbNail() {
163 PixmapInfo inf = m_inPix.first();
164 m_inPix.remove( inf );
165
166 static SlaveObjects::Iterator it;
167 static SlaveObjects* map = slaveObjects(); // SlaveMap won't be changed during execution!!!
168 for(it = map->begin(); it != map->end(); ++it ) {
169 SlaveInterface* iface = it.data();
170 if( iface->supports(inf.file ) ) {
171 /* pixmap */
172 qWarning( "Asking for thumbNail in size %d %d for "+inf.file, inf.width, inf.height );
173 inf.pixmap = iface->pixmap(inf.file, 64, 64);
174 m_outPix.append( inf );
175 break;
176 }
177 }
178
179
180
181 if(m_inPix.isEmpty() )
182 m_pix->stop();
183 if(!m_out->isActive() && !m_outPix.isEmpty() )
184 m_out->start(100);
185}
186
187void SlaveReciever::slotSend() {
188
189 m_out->stop();
190
191 qWarning( "Sending %d %d", outPix().count(), outInf().count() );
192 /* queue it and send */
193 /* if this ever gets a service introduce request queues
194 * so we can differinatate between different clients
195 */
196 if (! m_outPix.isEmpty() ) {
197 QCopEnvelope answer("QPE/opie-eye", "pixmapsHandled(PixmapList)" );
198 answer << outPix();
199 for ( PixmapList::Iterator it = m_outPix.begin();it!=m_outPix.end();++it ) {
200 qWarning( "Sending out %s %d %d", (*it).file.latin1(), (*it).width, (*it).height );
201 }
202 }
203 if ( !m_outList.isEmpty() ) {
204 QCopEnvelope answer("QPE/opie-eye", "pixmapsHandled(StringList)" );
205 answer << outInf();
206 for ( StringList::Iterator it = m_outList.begin();it!=m_outList.end();++it ) {
207 qWarning( "Sending out2 " + (*it).file );
208 }
209 }
210
211 m_outList.clear();
212 m_outPix.clear();
213}
214
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 @@
1/*
2 * GPLv2
3 */
4
5
6#ifndef SLAVE_RECEIVER_H
7#define SLAVE_RECEIVER_H
8
9/**
10 * Receive Requests
11 */
12
13#include <iface/slaveiface.h>
14
15#include <qobject.h>
16#include <qdatastream.h>
17#include <qstringlist.h>
18#include <qvaluelist.h>
19#include <qpixmap.h>
20
21
22
23typedef QValueList<PixmapInfo> PixmapList;
24typedef QValueList<ImageInfo> StringList;
25
26class QTimer;
27class QSocket;
28class SlaveReciever : public QObject {
29 Q_OBJECT
30
31 friend QDataStream &operator<<( QDataStream&, const PixmapInfo& );
32 friend QDataStream &operator>>( QDataStream&, PixmapInfo& );
33 friend QDataStream &operator<<( QDataStream&, const ImageInfo& );
34 friend QDataStream &operator>>( QDataStream&, ImageInfo );
35public:
36
37 enum Job { ImageInfoJob, FullImageInfoJob, ThumbNailJob };
38 SlaveReciever( QObject* parent );
39 ~SlaveReciever();
40
41public slots:
42 void recieveAnswer( const QCString&, const QByteArray& );
43public:
44 PixmapList outPix()const;
45 StringList outInf()const;
46
47private slots:
48 void slotSend();
49 void slotImageInfo();
50 void slotThumbNail();
51private:
52 QTimer *m_inf, *m_pix, *m_out;
53 StringList m_inList, m_outList;
54 PixmapList m_inPix, m_outPix;
55};
56
57
58#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 @@
1#include "thumbnailtool.h"
2
3#include <qfileinfo.h>
4#include <qdir.h>
5#include <qimage.h>
6#include <qpixmap.h>
7#include <qstring.h>
8
9static bool makeThumbDir( const QFileInfo& inf, bool make = false) {
10 QDir dir( inf.dirPath()+ "/.opie-eye" );
11 if ( !dir.exists() )
12 if ( make )
13 return dir.mkdir(QString::null);
14 else
15 return false;
16 return true;
17}
18
19
20/*
21 * check if the Opie opie-eye dir exists
22 * check if a thumbnail exists
23 * load the thumbnail
24 * /foo/bar/imagefoo.gif
25 * check for a png in /foo/bar/.opie-eye/%dx%d-imagefoo.gif
26 */
27QPixmap ThumbNailTool::getThumb( const QString& path, int width, int height ) {
28 QFileInfo inf( path );
29 qWarning( "Get Thumb" );
30 if ( !makeThumbDir( inf ) ) {
31 QPixmap pix;
32 return pix;
33 }
34 QString str = QString( "/.opie-eye/%1x%2-%3" ).arg( width ).arg( height ).arg( inf.fileName() );
35 qWarning( inf.dirPath()+str );
36 return QPixmap( inf.dirPath()+str,"PNG" );
37
38}
39
40void ThumbNailTool::putThumb( const QString& path, const QPixmap& pix, int width, int height ) {
41 QFileInfo inf( path );
42 makeThumbDir( inf, true );
43 QString str = QString( "/.opie-eye/%1x%2-%3" ).arg( width ).arg( height ).arg( inf.fileName() );
44 qWarning( inf.dirPath()+str );
45 pix.save( inf.dirPath()+str, "PNG" );
46}
47
48
49QPixmap ThumbNailTool::scaleImage( QImage& img, int w, int h ) {
50 double hs = (double)h / (double)img.height() ;
51 double ws = (double)w / (double)img.width() ;
52 double scaleFactor = (hs > ws) ? ws : hs;
53 int smoothW = (int)(scaleFactor * img.width());
54 int smoothH = (int)(scaleFactor * img.height());
55 QPixmap pixmap;
56 if ( img.width() <= w && img.height() <= h )
57 pixmap.convertFromImage( img );
58 else
59 pixmap.convertFromImage( img.smoothScale( smoothW, smoothH) );
60 return pixmap;
61}
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 @@
1/*
2 * GPLv2
3 */
4
5#ifndef THUMB_NAIL_TOOL_H
6#define THUMB_NAIL_TOOL_H
7class QString;
8class QPixmap;
9class QImage;
10
11struct ThumbNailTool {
12 static QPixmap scaleImage( QImage&, int width, int height );
13/* get one isInvalid() if non found */
14 static QPixmap getThumb( const QString&, int width, int height );
15/* put one */
16 static void putThumb( const QString&, const QPixmap&, int width, int heigh );
17};
18
19#endif