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