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 @@ | |||
1 | The Design of the Eye Caramba Opie Image Viewer. | ||
2 | |||
3 | It consists out of several Parts: | ||
4 | |||
5 | 1.) A interface for Getting Information, Files and Requesting Pixmap and the Full Image | ||
6 | 2.) 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 ) | ||
8 | 3.) 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. | ||
10 | 4.) 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 | |||
15 | TODO: | ||
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 | |||
15 | PFileSystem::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 | |||
32 | PFileSystem::~PFileSystem() { | ||
33 | delete m_storage; | ||
34 | } | ||
35 | |||
36 | |||
37 | void 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 | |||
50 | void 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 | |||
12 | class QPopupMenu; | ||
13 | class StorageInfo; | ||
14 | class PFileSystem : public QToolButton { | ||
15 | Q_OBJECT | ||
16 | public: | ||
17 | PFileSystem( QToolBar* ); | ||
18 | ~PFileSystem(); | ||
19 | |||
20 | signals: | ||
21 | void changeDir( const QString& ); | ||
22 | |||
23 | private slots: | ||
24 | void slotSelectDir( int ); | ||
25 | void changed(); | ||
26 | |||
27 | private: | ||
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 | |||
31 | namespace { | ||
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 | |||
92 | PIconView::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 | |||
124 | PIconView::~PIconView() { | ||
125 | } | ||
126 | |||
127 | void PIconView::slotDirUp() { | ||
128 | QDir dir( m_path ); | ||
129 | dir.cdUp(); | ||
130 | slotChangeDir( dir.absPath() ); | ||
131 | |||
132 | } | ||
133 | |||
134 | void 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 | |||
153 | QString 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 | |||
164 | void 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 | } | ||
179 | void 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 | |||
186 | void PIconView::resetView() { | ||
187 | slotViewChanged(m_views->currentItem()); | ||
188 | } | ||
189 | |||
190 | void 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 | |||
219 | void PIconView::slotReloadDir() { | ||
220 | slotChangeDir( m_path ); | ||
221 | } | ||
222 | |||
223 | |||
224 | void 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 | |||
233 | void 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 | |||
240 | void 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 | |||
251 | void 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 | } | ||
259 | void 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 | |||
269 | void PIconView::slotRename() { | ||
270 | |||
271 | } | ||
272 | |||
273 | void 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 | |||
286 | void PIconView::slotBeamDone( Ir* ir) { | ||
287 | delete ir; | ||
288 | } | ||
289 | |||
290 | void PIconView::slotStart() { | ||
291 | m_view->setUpdatesEnabled( false ); | ||
292 | } | ||
293 | |||
294 | void 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 | |||
13 | class QIconView; | ||
14 | class QIconViewItem; | ||
15 | class QComboBox; | ||
16 | class PIconViewItem; | ||
17 | class PDirLister; | ||
18 | class Ir; | ||
19 | class PIconView : public QVBox { | ||
20 | Q_OBJECT | ||
21 | friend class PIconViewItem; | ||
22 | public: | ||
23 | PIconView( QWidget* wid, Config *cfg ); | ||
24 | ~PIconView(); | ||
25 | void resetView(); | ||
26 | |||
27 | private: | ||
28 | QString currentFileName(bool &isDir)const; | ||
29 | void loadViews(); | ||
30 | |||
31 | private 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&); | ||
52 | private: | ||
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 | |||
27 | OPIE_EXPORT_APP( OApplicationFactory<PMainWindow> ) | ||
28 | |||
29 | PMainWindow::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 | |||
78 | PMainWindow::~PMainWindow() { | ||
79 | } | ||
80 | |||
81 | |||
82 | void 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 | |||
13 | class PIconView; | ||
14 | class PMainWindow : public QMainWindow { | ||
15 | Q_OBJECT | ||
16 | public: | ||
17 | static QString appName() { return QString::fromLatin1("opie-eye" ); } | ||
18 | PMainWindow(QWidget*, const char*, WFlags ); | ||
19 | ~PMainWindow(); | ||
20 | |||
21 | private: | ||
22 | Config m_cfg; | ||
23 | PIconView* m_view; | ||
24 | |||
25 | private 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 | |||
3 | namespace { | ||
4 | ViewMap m_view; | ||
5 | } | ||
6 | |||
7 | ViewMap* 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 | |||
4 | PDirLister::PDirLister( const char* name ) | ||
5 | : QObject( 0, name ) | ||
6 | {} | ||
7 | |||
8 | PDirLister::~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 | |||
14 | class PDirLister : public QObject { | ||
15 | Q_OBJECT | ||
16 | public: | ||
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; | ||
26 | public 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 | |||
33 | signals: | ||
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 | |||
43 | protected: | ||
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 | |||
3 | PDirView::PDirView( const Config& ) { | ||
4 | |||
5 | } | ||
6 | |||
7 | PDirView::~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 | |||
13 | class PInterfaceInfo; | ||
14 | class PDirLister; | ||
15 | |||
16 | struct PDirView { | ||
17 | PDirView( const Config& ); | ||
18 | virtual ~PDirView(); | ||
19 | virtual PInterfaceInfo* interfaceInfo()const = 0; | ||
20 | virtual PDirLister* dirLister()const = 0; | ||
21 | }; | ||
22 | |||
23 | typedef PDirView* (*phunkViewCreateFunc )(const Config& ); | ||
24 | typedef QMap<QString,phunkViewCreateFunc> ViewMap; | ||
25 | |||
26 | ViewMap* viewMap(); | ||
27 | PDirView* currentView(); | ||
28 | void 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 | |||
11 | class QWidget; | ||
12 | class Config; | ||
13 | struct 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 | |||
15 | struct 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 | |||
27 | struct 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 | |||
5 | PHUNK_VIEW_INTERFACE("Dir View", Dir_DirView ); | ||
6 | |||
7 | |||
8 | Dir_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 | |||
16 | Dir_DirView::~Dir_DirView() { | ||
17 | } | ||
18 | |||
19 | PInterfaceInfo* Dir_DirView::interfaceInfo()const{ | ||
20 | if (!m_info ) | ||
21 | m_info =new DirInterfaceInfo; | ||
22 | return m_info; | ||
23 | } | ||
24 | |||
25 | PDirLister* 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 | |||
11 | struct Dir_DirView : public PDirView { | ||
12 | Dir_DirView( const Config& ); | ||
13 | ~Dir_DirView(); | ||
14 | |||
15 | PInterfaceInfo* interfaceInfo()const; | ||
16 | PDirLister* dirLister()const; | ||
17 | private: | ||
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 | |||
11 | class DirInterfaceInfo : public PInterfaceInfo { | ||
12 | public: | ||
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 | |||
15 | namespace { | ||
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 | |||
27 | DirInterfaceInfo::DirInterfaceInfo() { | ||
28 | } | ||
29 | DirInterfaceInfo::~DirInterfaceInfo() { | ||
30 | } | ||
31 | |||
32 | QString DirInterfaceInfo::name()const { | ||
33 | return QString::fromLatin1(QObject::tr("DirView" )); | ||
34 | } | ||
35 | |||
36 | QWidget* 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 | |||
43 | void 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 | |||
11 | class DirInterfaceInfo : public PInterfaceInfo { | ||
12 | public: | ||
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 | |||
17 | Dir_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 | |||
35 | QString Dir_DirLister::defaultPath()const { | ||
36 | return QPEApplication::documentDir(); | ||
37 | } | ||
38 | |||
39 | QString 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 | |||
48 | QString Dir_DirLister::currentPath()const { | ||
49 | return m_currentDir.absPath(); | ||
50 | } | ||
51 | |||
52 | |||
53 | QStringList Dir_DirLister::folders()const { | ||
54 | return m_currentDir.entryList( QDir::Dirs ); | ||
55 | } | ||
56 | |||
57 | QStringList 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 | |||
76 | void Dir_DirLister::deleteImage( const QString& fl) { | ||
77 | QFile::remove( fl ); | ||
78 | } | ||
79 | |||
80 | void Dir_DirLister::thumbNail( const QString& str, int w, int h) { | ||
81 | SlaveMaster::self()->thumbNail( str, w, h ); | ||
82 | } | ||
83 | |||
84 | QImage Dir_DirLister::image( const QString& str, Factor f, int m) { | ||
85 | return SlaveMaster::self()->image( str, f, m ); | ||
86 | } | ||
87 | |||
88 | void Dir_DirLister::imageInfo( const QString& str) { | ||
89 | SlaveMaster::self()->thumbInfo( str ); | ||
90 | } | ||
91 | |||
92 | void 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 | |||
12 | class Config; | ||
13 | class Dir_DirLister : public PDirLister { | ||
14 | public: | ||
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 | |||
29 | private: | ||
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 | |||
11 | namespace { | ||
12 | PImageCache * _imgCache = 0; | ||
13 | PPixmapCache* _pxmCache = 0; | ||
14 | } | ||
15 | |||
16 | |||
17 | PImageCache::PImageCache() | ||
18 | : QCache<QImage>() | ||
19 | { | ||
20 | /* just to set an initial value.. 4 big images */ | ||
21 | setMaxCost( (1024*1024*16)/8*4 ); | ||
22 | } | ||
23 | |||
24 | PImageCache::~PImageCache() { | ||
25 | } | ||
26 | |||
27 | PImageCache* PImageCache::self() { | ||
28 | if ( !_imgCache ) | ||
29 | _imgCache = new PImageCache; | ||
30 | return _imgCache; | ||
31 | } | ||
32 | |||
33 | QImage* 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 | |||
48 | void 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 | |||
55 | PPixmapCache::PPixmapCache() { | ||
56 | /* | ||
57 | * 20 64x64 16 bit images | ||
58 | */ | ||
59 | setMaxCost( 64*64*QPixmap::defaultDepth()/8*20 ); | ||
60 | } | ||
61 | |||
62 | PPixmapCache::~PPixmapCache() { | ||
63 | } | ||
64 | |||
65 | PPixmapCache* PPixmapCache::self() { | ||
66 | if ( !_pxmCache ) | ||
67 | _pxmCache = new PPixmapCache; | ||
68 | |||
69 | return _pxmCache; | ||
70 | } | ||
71 | |||
72 | QPixmap* 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 | |||
83 | void 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 | |||
14 | class PImageCache : public QCache<QImage> { | ||
15 | private: | ||
16 | PImageCache(); | ||
17 | ~PImageCache(); | ||
18 | |||
19 | public: | ||
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 | |||
27 | class PPixmapCache : public QCache<QPixmap> { | ||
28 | private: | ||
29 | PPixmapCache(); | ||
30 | ~PPixmapCache(); | ||
31 | public: | ||
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 | |||
38 | inline void PPixmapCache::insertImage( const QString& path, const QPixmap& p, int width, int height ) { | ||
39 | insertImage( path, new QPixmap( p ), width, height ); | ||
40 | } | ||
41 | |||
42 | inline 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 | |||
9 | QDataStream & operator << (QDataStream & str, bool b) | ||
10 | { | ||
11 | str << Q_INT8(b); | ||
12 | return str; | ||
13 | } | ||
14 | QDataStream & operator >> (QDataStream & str, bool & b) | ||
15 | { | ||
16 | Q_INT8 l; | ||
17 | str >> l; | ||
18 | b = bool(l); | ||
19 | return str; | ||
20 | } | ||
21 | QDataStream &operator<<( QDataStream& s, const PixmapInfo& inf) { | ||
22 | return s << inf.file << inf.pixmap << inf.width << inf.height; | ||
23 | } | ||
24 | QDataStream &operator>>( QDataStream& s, PixmapInfo& inf ) { | ||
25 | s >> inf.file >> inf.pixmap >> inf.width >> inf.height; | ||
26 | return s; | ||
27 | } | ||
28 | QDataStream &operator<<( QDataStream& s, const ImageInfo& i) { | ||
29 | return s << i.kind << i.file << i.info; | ||
30 | } | ||
31 | QDataStream &operator>>( QDataStream& s, ImageInfo& i ) { | ||
32 | s >> i.kind >> i.file >> i.info; | ||
33 | return s; | ||
34 | } | ||
35 | |||
36 | |||
37 | |||
38 | SlaveMaster* SlaveMaster::m_master = 0; | ||
39 | |||
40 | SlaveMaster::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 | |||
48 | SlaveMaster::~SlaveMaster() { | ||
49 | } | ||
50 | |||
51 | SlaveMaster* SlaveMaster::self() { | ||
52 | if ( !m_master ) | ||
53 | m_master = new SlaveMaster; | ||
54 | return m_master; | ||
55 | } | ||
56 | |||
57 | void 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 | |||
66 | void 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 | |||
74 | void 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 | |||
92 | void 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 | |||
121 | void 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 | |||
143 | QImage 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 | |||
11 | class SlaveMaster : public QObject { | ||
12 | Q_OBJECT | ||
13 | typedef QValueList<ImageInfo> ImageInfos; | ||
14 | typedef QValueList<PixmapInfo> PixmapInfos; | ||
15 | public: | ||
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 ); | ||
22 | signals: | ||
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& ); | ||
29 | private slots: | ||
30 | void recieve( const QCString&, const QByteArray& ); | ||
31 | void slotTimerStart(); | ||
32 | private: | ||
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 | |||
4 | namespace { | ||
5 | ViewMap *_viewMap = 0; | ||
6 | PDirView *_dirView = 0; | ||
7 | } | ||
8 | |||
9 | |||
10 | ViewMap *viewMap() { | ||
11 | if ( !_viewMap ) | ||
12 | _viewMap = new ViewMap; | ||
13 | |||
14 | return _viewMap; | ||
15 | } | ||
16 | |||
17 | |||
18 | PDirView* currentView(){ | ||
19 | return _dirView; | ||
20 | } | ||
21 | |||
22 | |||
23 | void 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 @@ | |||
1 | CONFIG += qt warn_on #quick-app | ||
2 | DESTDIR = $(OPIEDIR)/bin | ||
3 | TEMPLATE = app | ||
4 | TARGET = opie-eye | ||
5 | # the name of the resulting object | ||
6 | |||
7 | HEADERS = 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 | |||
17 | SOURCES = 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 | |||
24 | INTERFACES = | ||
25 | # list of ui files | ||
26 | |||
27 | INCLUDEPATH += . $(OPIEDIR)/include | ||
28 | DEPENDPATH += $(OPIEDIR)/include | ||
29 | |||
30 | |||
31 | |||
32 | LIBS += -lqpe -lopie | ||
33 | |||
34 | include ( $(OPIEDIR)/include.pro ) | ||
diff --git a/noncore/graphics/opie-eye/slave/gif_slave.cpp b/noncore/graphics/opie-eye/slave/gif_slave.cpp new file mode 100644 index 0000000..feb69b6 --- a/dev/null +++ b/noncore/graphics/opie-eye/slave/gif_slave.cpp | |||
@@ -0,0 +1,305 @@ | |||
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 | |||
11 | PHUNK_VIEW_INTERFACE( "Gif", GifSlave ); | ||
12 | |||
13 | |||
14 | namespace { | ||
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 | |||
77 | static long int pos; | ||
78 | static char skipcomment,verbose; | ||
79 | char *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 | |||
85 | static bool debug = false; | ||
86 | static bool output= false; | ||
87 | |||
88 | void dump(long int, unsigned char *, size_t) { | ||
89 | } | ||
90 | |||
91 | void 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 | |||
111 | void 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 | |||
127 | void 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 | |||
145 | void 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 | |||
161 | int 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 | /****************************************************************************/ | ||
253 | extern void get_gif_info( const char * original_filename, QString& str, | ||
254 | bool full =false) | ||
255 | { | ||
256 | FILE * 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 | |||
274 | GifSlave::GifSlave() | ||
275 | : SlaveInterface(QStringList("gif")) | ||
276 | {} | ||
277 | |||
278 | GifSlave::~GifSlave() { | ||
279 | |||
280 | } | ||
281 | |||
282 | QString GifSlave::iconViewName(const QString& str) { | ||
283 | QString st; | ||
284 | get_gif_info(QFile::encodeName( str ).data(), st ); | ||
285 | return st; | ||
286 | } | ||
287 | |||
288 | QString GifSlave::fullImageInfo( const QString& str) { | ||
289 | QString st; | ||
290 | get_gif_info(QFile::encodeName( str ).data(), st, true ); | ||
291 | return st; | ||
292 | } | ||
293 | |||
294 | QPixmap 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 | |||
11 | class GifSlave : public SlaveInterface { | ||
12 | public: | ||
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 | |||
5 | PHUNK_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 | |||
24 | typedef 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. | ||
32 | typedef struct { | ||
33 | uchar * Data; | ||
34 | int Type; | ||
35 | unsigned Size; | ||
36 | }Section_t; | ||
37 | |||
38 | typedef unsigned char uchar; | ||
39 | |||
40 | typedef 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 | |||
48 | class 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 | |||
88 | public: | ||
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 | |||
118 | class FatalError { | ||
119 | const char* ex; | ||
120 | public: | ||
121 | FatalError(const char* s) { ex = s; } | ||
122 | void debug_print() const { qWarning("exception: %s", ex ); } | ||
123 | }; | ||
124 | |||
125 | |||
126 | |||
127 | static unsigned char * LastExifRefd; | ||
128 | static int ExifSettingsLength; | ||
129 | static double FocalplaneXRes; | ||
130 | static double FocalplaneUnits; | ||
131 | static int MotorolaOrder = 0; | ||
132 | static 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 | |||
159 | TagTable_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 | ||
180 | static 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 | //-------------------------------------------------------------------------- | ||
242 | int 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 | //-------------------------------------------------------------------------- | ||
386 | void 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 | //-------------------------------------------------------------------------- | ||
396 | int 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 | //-------------------------------------------------------------------------- | ||
408 | int 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 | //-------------------------------------------------------------------------- | ||
422 | unsigned 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 | //-------------------------------------------------------------------------- | ||
430 | double 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 | //-------------------------------------------------------------------------- | ||
470 | void 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 | //-------------------------------------------------------------------------- | ||
758 | void 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 | //-------------------------------------------------------------------------- | ||
774 | void 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 | //-------------------------------------------------------------------------- | ||
796 | int 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 | //-------------------------------------------------------------------------- | ||
806 | void 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 | //-------------------------------------------------------------------------- | ||
857 | int 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 | //-------------------------------------------------------------------------- | ||
881 | ExifData::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 | //-------------------------------------------------------------------------- | ||
905 | bool 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 | ||
939 | bool 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 | |||
954 | static QImage flip_image( const QImage& img ); | ||
955 | static QImage rotate_90( const QImage& img ); | ||
956 | static QImage rotate_180( const QImage& ); | ||
957 | static QImage rotate_270( const QImage& ); | ||
958 | |||
959 | //-------------------------------------------------------------------------- | ||
960 | // return a thumbnail that respects the orientation flag | ||
961 | // only if it seems sane | ||
962 | //-------------------------------------------------------------------------- | ||
963 | QImage 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 | */ | ||
987 | static QImage flip_image( const QImage& img ) { | ||
988 | return img.mirror( TRUE, FALSE ); | ||
989 | } | ||
990 | |||
991 | |||
992 | static QImage dest; | ||
993 | static int x, y; | ||
994 | static unsigned int *srcData, *destData; // we're not threaded anyway | ||
995 | static unsigned char *srcData8, *destData8; // 8 bit is char | ||
996 | static unsigned int *srcTable, *destTable; // destination table | ||
997 | |||
998 | |||
999 | static 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 | |||
1016 | static 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 | |||
1030 | static 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 | |||
1037 | static 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 | |||
1048 | static 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 | |||
1064 | static 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 | |||
1072 | static 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 | |||
1090 | static 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 | |||
1102 | static 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 | |||
1110 | static QString color_mode_to_string( bool b ) { | ||
1111 | return b ? QObject::tr( "Colormode: Color\n" ) : QObject::tr( "Colormode: Black and white\n" ); | ||
1112 | } | ||
1113 | |||
1114 | static 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 | |||
1134 | static 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 | |||
1175 | static 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 | |||
1219 | static 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 | |||
1254 | static 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 | |||
1291 | JpegSlave::JpegSlave() | ||
1292 | : SlaveInterface( QStringList::split( " ", "jpeg jpg" ) ) | ||
1293 | {} | ||
1294 | |||
1295 | JpegSlave::~JpegSlave() {} | ||
1296 | |||
1297 | QString 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 | */ | ||
1324 | QString 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 | |||
1413 | QPixmap 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 | |||
9 | class JpegSlave : public SlaveInterface { | ||
10 | public: | ||
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 | |||
16 | int 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 | ||
30 | int 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 | */ | ||
14 | PHUNK_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 | ||
25 | static 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 | ||
43 | static 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 | ||
54 | static const char* compressions[] = | ||
55 | { | ||
56 | QT_TR_NOOP("Deflate") | ||
57 | }; | ||
58 | |||
59 | // interlaced modes | ||
60 | static const char* interlaceModes[] = { | ||
61 | QT_TR_NOOP("None"), | ||
62 | QT_TR_NOOP("Adam7") | ||
63 | }; | ||
64 | |||
65 | |||
66 | static 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 | } | ||
179 | end: | ||
180 | delete[] data; | ||
181 | |||
182 | } | ||
183 | |||
184 | |||
185 | PNGSlave::PNGSlave() | ||
186 | : SlaveInterface("png") | ||
187 | { | ||
188 | } | ||
189 | PNGSlave::~PNGSlave() { | ||
190 | } | ||
191 | QString PNGSlave::iconViewName( const QString& path) { | ||
192 | QString str; | ||
193 | read_comment( path, false, str ); | ||
194 | return str; | ||
195 | } | ||
196 | |||
197 | QString PNGSlave::fullImageInfo( const QString& path) { | ||
198 | QString str; | ||
199 | read_comment( path, true, str ); | ||
200 | return str; | ||
201 | } | ||
202 | |||
203 | |||
204 | QPixmap 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 | |||
9 | class QString; | ||
10 | class QPixmap; | ||
11 | class PNGSlave : public SlaveInterface { | ||
12 | public: | ||
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 @@ | |||
1 | CONFIG += qte | ||
2 | TEMPLATE = app | ||
3 | TARGET = opie-eye_slave | ||
4 | DESTDIR = $(OPIEDIR)/bin | ||
5 | |||
6 | HEADERS = gif_slave.h slaveiface.h slavereciever.h \ | ||
7 | thumbnailtool.h png_slave.h jpeg_slave.h \ | ||
8 | ../iface/slaveiface.h | ||
9 | SOURCES = main.cpp gif_slave.cpp slavereciever.cpp \ | ||
10 | slaveiface.cpp thumbnailtool.cpp png_slave.cpp \ | ||
11 | jpeg_slave.cpp | ||
12 | |||
13 | INCLUDEPATH += $(OPIEDIR)/include ../ | ||
14 | DEPENDSPATH += $(OPIEDIR)/include | ||
15 | |||
16 | LIBS += -lqpe | ||
17 | |||
18 | include ( $(OPIEDIR)/include.pro ) \ No newline at end of file | ||
diff --git a/noncore/graphics/opie-eye/slave/slaveiface.cpp b/noncore/graphics/opie-eye/slave/slaveiface.cpp new file mode 100644 index 0000000..170f7d5 --- a/dev/null +++ b/noncore/graphics/opie-eye/slave/slaveiface.cpp | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * GPLv2 zecke@handhelds.org | ||
3 | */ | ||
4 | |||
5 | #include "slaveiface.h" | ||
6 | |||
7 | static SlaveMap* _slaveMap = 0; | ||
8 | SlaveMap* slaveMap() { | ||
9 | if ( !_slaveMap ) | ||
10 | _slaveMap = new SlaveMap; | ||
11 | return _slaveMap; | ||
12 | } | ||
13 | |||
14 | SlaveInterface::SlaveInterface( const QStringList& image ) | ||
15 | : m_list( image ) | ||
16 | { | ||
17 | |||
18 | } | ||
19 | |||
20 | SlaveInterface::~SlaveInterface() { | ||
21 | |||
22 | } | ||
23 | |||
24 | QStringList 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 | */ | ||
16 | class QPixmap; | ||
17 | class SlaveInterface { | ||
18 | public: | ||
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; | ||
27 | private: | ||
28 | QStringList m_list; | ||
29 | }; | ||
30 | |||
31 | inline bool SlaveInterface::supports( const QString& str)const { | ||
32 | return m_list.contains( QFileInfo( str ).extension(false) ); | ||
33 | } | ||
34 | |||
35 | typedef SlaveInterface* (*phunkSlaveCreateFunc )(); | ||
36 | typedef QMap<QString,phunkSlaveCreateFunc> SlaveMap; | ||
37 | |||
38 | typedef QMap<QString, SlaveInterface*> SlaveObjects; | ||
39 | |||
40 | SlaveMap* slaveMap(); | ||
41 | SlaveObjects* 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 | |||
13 | static SlaveObjects* _slaveObj = 0; | ||
14 | |||
15 | QDataStream & operator << (QDataStream & str, bool b) | ||
16 | { | ||
17 | str << Q_INT8(b); | ||
18 | return str; | ||
19 | } | ||
20 | |||
21 | QDataStream & operator >> (QDataStream & str, bool & b) | ||
22 | { | ||
23 | Q_INT8 l; | ||
24 | str >> l; | ||
25 | b = bool(l); | ||
26 | return str; | ||
27 | } | ||
28 | |||
29 | |||
30 | |||
31 | QDataStream &operator<<( QDataStream& s, const PixmapInfo& inf) { | ||
32 | return s << inf.file << inf.pixmap << inf.width << inf.height; | ||
33 | } | ||
34 | QDataStream &operator>>( QDataStream& s, PixmapInfo& inf ) { | ||
35 | s >> inf.file >> inf.pixmap >> inf.width >> inf.height; | ||
36 | return s; | ||
37 | } | ||
38 | QDataStream &operator<<( QDataStream& s, const ImageInfo& i) { | ||
39 | return s << i.kind << i.file << i.info; | ||
40 | } | ||
41 | QDataStream &operator>>( QDataStream& s, ImageInfo& i ) { | ||
42 | s >> i.kind >> i.file >> i.info; | ||
43 | return s; | ||
44 | } | ||
45 | |||
46 | |||
47 | |||
48 | SlaveObjects* slaveObjects() { | ||
49 | if ( !_slaveObj ) | ||
50 | _slaveObj = new SlaveObjects; | ||
51 | return _slaveObj; | ||
52 | } | ||
53 | |||
54 | SlaveReciever::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 | |||
76 | SlaveReciever::~SlaveReciever() { | ||
77 | } | ||
78 | |||
79 | void 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 | |||
130 | PixmapList SlaveReciever::outPix()const { | ||
131 | return m_outPix; | ||
132 | } | ||
133 | |||
134 | StringList SlaveReciever::outInf()const{ | ||
135 | return m_outList; | ||
136 | } | ||
137 | |||
138 | void 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 | |||
162 | void 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 | |||
187 | void 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 | |||
23 | typedef QValueList<PixmapInfo> PixmapList; | ||
24 | typedef QValueList<ImageInfo> StringList; | ||
25 | |||
26 | class QTimer; | ||
27 | class QSocket; | ||
28 | class 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 ); | ||
35 | public: | ||
36 | |||
37 | enum Job { ImageInfoJob, FullImageInfoJob, ThumbNailJob }; | ||
38 | SlaveReciever( QObject* parent ); | ||
39 | ~SlaveReciever(); | ||
40 | |||
41 | public slots: | ||
42 | void recieveAnswer( const QCString&, const QByteArray& ); | ||
43 | public: | ||
44 | PixmapList outPix()const; | ||
45 | StringList outInf()const; | ||
46 | |||
47 | private slots: | ||
48 | void slotSend(); | ||
49 | void slotImageInfo(); | ||
50 | void slotThumbNail(); | ||
51 | private: | ||
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 | |||
9 | static 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 | */ | ||
27 | QPixmap 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 | |||
40 | void 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 | |||
49 | QPixmap 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 | ||
7 | class QString; | ||
8 | class QPixmap; | ||
9 | class QImage; | ||
10 | |||
11 | struct 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 | ||