• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KImgIO

  • sources
  • kde-4.12
  • kdelibs
  • kimgio
psd.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE project
2  Copyright (C) 2003 Ignacio CastaƱo <castano@ludicon.com>
3 
4  This program is free software; you can redistribute it and/or
5  modify it under the terms of the Lesser GNU General Public
6  License as published by the Free Software Foundation; either
7  version 2 of the License, or (at your option) any later version.
8 
9  This code is based on Thacher Ulrich PSD loading code released
10  on public domain. See: http://tulrich.com/geekstuff/
11 */
12 
13 /* this code supports:
14  * reading:
15  * rle and raw psd files
16  * writing:
17  * not supported
18  */
19 
20 #include "psd.h"
21 
22 #include <QtGui/QImage>
23 #include <QtCore/QDataStream>
24 
25 #include <kdebug.h>
26 
27 typedef quint32 uint;
28 typedef quint16 ushort;
29 typedef quint8 uchar;
30 
31 namespace { // Private.
32 
33  enum ColorMode {
34  CM_BITMAP = 0,
35  CM_GRAYSCALE = 1,
36  CM_INDEXED = 2,
37  CM_RGB = 3,
38  CM_CMYK = 4,
39  CM_MULTICHANNEL = 7,
40  CM_DUOTONE = 8,
41  CM_LABCOLOR = 9
42  };
43 
44  struct PSDHeader {
45  uint signature;
46  ushort version;
47  uchar reserved[6];
48  ushort channel_count;
49  uint height;
50  uint width;
51  ushort depth;
52  ushort color_mode;
53  };
54 
55  static QDataStream & operator>> ( QDataStream & s, PSDHeader & header )
56  {
57  s >> header.signature;
58  s >> header.version;
59  for( int i = 0; i < 6; i++ ) {
60  s >> header.reserved[i];
61  }
62  s >> header.channel_count;
63  s >> header.height;
64  s >> header.width;
65  s >> header.depth;
66  s >> header.color_mode;
67  return s;
68  }
69  static bool seekBy(QDataStream& s, unsigned int bytes)
70  {
71  char buf[4096];
72  while (bytes) {
73  unsigned int num= qMin(bytes,( unsigned int )sizeof(buf));
74  unsigned int l = num;
75  s.readRawData(buf, l);
76  if(l != num)
77  return false;
78  bytes -= num;
79  }
80  return true;
81  }
82 
83  // Check that the header is a valid PSD.
84  static bool IsValid( const PSDHeader & header )
85  {
86  if( header.signature != 0x38425053 ) { // '8BPS'
87  return false;
88  }
89  return true;
90  }
91 
92  // Check that the header is supported.
93  static bool IsSupported( const PSDHeader & header )
94  {
95  if( header.version != 1 ) {
96  return false;
97  }
98  if( header.channel_count > 16 ) {
99  return false;
100  }
101  if( header.depth != 8 ) {
102  return false;
103  }
104  if( header.color_mode != CM_RGB ) {
105  return false;
106  }
107  return true;
108  }
109 
110  // Load the PSD image.
111  static bool LoadPSD( QDataStream & s, const PSDHeader & header, QImage & img )
112  {
113  // Create dst image.
114  img = QImage( header.width, header.height, QImage::Format_RGB32 );
115 
116  uint tmp;
117 
118  // Skip mode data.
119  s >> tmp;
120  s.device()->seek( s.device()->pos() + tmp );
121 
122  // Skip image resources.
123  s >> tmp;
124  s.device()->seek( s.device()->pos() + tmp );
125 
126  // Skip the reserved data.
127  s >> tmp;
128  s.device()->seek( s.device()->pos() + tmp );
129 
130  // Find out if the data is compressed.
131  // Known values:
132  // 0: no compression
133  // 1: RLE compressed
134  ushort compression;
135  s >> compression;
136 
137  if( compression > 1 ) {
138  // Unknown compression type.
139  return false;
140  }
141 
142  uint channel_num = header.channel_count;
143 
144  // Clear the image.
145  if( channel_num < 4 ) {
146  img.fill(qRgba(0, 0, 0, 0xFF));
147  }
148  else {
149  // Enable alpha.
150  img = img.convertToFormat(QImage::Format_ARGB32);
151 
152  // Ignore the other channels.
153  channel_num = 4;
154  }
155 
156  const uint pixel_count = header.height * header.width;
157 
158  static const uint components[4] = {2, 1, 0, 3}; // @@ Is this endian dependant?
159 
160  if( compression ) {
161 
162  // Skip row lengths.
163  if(!seekBy(s, header.height*header.channel_count*sizeof(ushort)))
164  return false;
165 
166  // Read RLE data.
167  for(uint channel = 0; channel < channel_num; channel++) {
168 
169  uchar * ptr = img.bits() + components[channel];
170 
171  uint count = 0;
172  while( count < pixel_count ) {
173  uchar c;
174  if(s.atEnd())
175  return false;
176  s >> c;
177  uint len = c;
178 
179  if( len < 128 ) {
180  // Copy next len+1 bytes literally.
181  len++;
182  count += len;
183  if ( count > pixel_count )
184  return false;
185 
186  while( len != 0 ) {
187  s >> *ptr;
188  ptr += 4;
189  len--;
190  }
191  }
192  else if( len > 128 ) {
193  // Next -len+1 bytes in the dest are replicated from next source byte.
194  // (Interpret len as a negative 8-bit int.)
195  len ^= 0xFF;
196  len += 2;
197  count += len;
198  if(s.atEnd() || count > pixel_count)
199  return false;
200  uchar val;
201  s >> val;
202  while( len != 0 ) {
203  *ptr = val;
204  ptr += 4;
205  len--;
206  }
207  }
208  else if( len == 128 ) {
209  // No-op.
210  }
211  }
212  }
213  }
214  else {
215  // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...)
216  // where each channel consists of an 8-bit value for each pixel in the image.
217 
218  // Read the data by channel.
219  for(uint channel = 0; channel < channel_num; channel++) {
220 
221  uchar * ptr = img.bits() + components[channel];
222 
223  // Read the data.
224  uint count = pixel_count;
225  while( count != 0 ) {
226  s >> *ptr;
227  ptr += 4;
228  count--;
229  }
230  }
231  }
232 
233  return true;
234  }
235 
236 } // Private
237 
238 
239 PSDHandler::PSDHandler()
240 {
241 }
242 
243 bool PSDHandler::canRead() const
244 {
245  if (canRead(device())) {
246  setFormat("psd");
247  return true;
248  }
249  return false;
250 }
251 
252 bool PSDHandler::read(QImage *image)
253 {
254  QDataStream s( device() );
255  s.setByteOrder( QDataStream::BigEndian );
256 
257  PSDHeader header;
258  s >> header;
259 
260  // Check image file format.
261  if( s.atEnd() || !IsValid( header ) ) {
262  kDebug(399) << "This PSD file is not valid.";
263  return false;
264  }
265 
266  // Check if it's a supported format.
267  if( !IsSupported( header ) ) {
268  kDebug(399) << "This PSD file is not supported.";
269  return false;
270  }
271 
272  QImage img;
273  if( !LoadPSD(s, header, img) ) {
274  kDebug(399) << "Error loading PSD file.";
275  return false;
276  }
277 
278  *image = img;
279  return true;
280 }
281 
282 bool PSDHandler::write(const QImage &)
283 {
284  // TODO Stub!
285  return false;
286 }
287 
288 QByteArray PSDHandler::name() const
289 {
290  return "psd";
291 }
292 
293 bool PSDHandler::canRead(QIODevice *device)
294 {
295  if (!device) {
296  qWarning("PSDHandler::canRead() called with no device");
297  return false;
298  }
299 
300  qint64 oldPos = device->pos();
301 
302  char head[4];
303  qint64 readBytes = device->read(head, sizeof(head));
304  if (readBytes != sizeof(head)) {
305  if (device->isSequential()) {
306  while (readBytes > 0)
307  device->ungetChar(head[readBytes-- - 1]);
308  } else {
309  device->seek(oldPos);
310  }
311  return false;
312  }
313 
314  if (device->isSequential()) {
315  while (readBytes > 0)
316  device->ungetChar(head[readBytes-- - 1]);
317  } else {
318  device->seek(oldPos);
319  }
320 
321  return qstrncmp(head, "8BPS", 4) == 0;
322 }
323 
324 
325 class PSDPlugin : public QImageIOPlugin
326 {
327 public:
328  QStringList keys() const;
329  Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
330  QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
331 };
332 
333 QStringList PSDPlugin::keys() const
334 {
335  return QStringList() << "psd" << "PSD";
336 }
337 
338 QImageIOPlugin::Capabilities PSDPlugin::capabilities(QIODevice *device, const QByteArray &format) const
339 {
340  if (format == "psd" || format == "PSD")
341  return Capabilities(CanRead);
342  if (!format.isEmpty())
343  return 0;
344  if (!device->isOpen())
345  return 0;
346 
347  Capabilities cap;
348  if (device->isReadable() && PSDHandler::canRead(device))
349  cap |= CanRead;
350  return cap;
351 }
352 
353 QImageIOHandler *PSDPlugin::create(QIODevice *device, const QByteArray &format) const
354 {
355  QImageIOHandler *handler = new PSDHandler;
356  handler->setDevice(device);
357  handler->setFormat(format);
358  return handler;
359 }
360 
361 Q_EXPORT_STATIC_PLUGIN(PSDPlugin)
362 Q_EXPORT_PLUGIN2(psd, PSDPlugin)
PSDHandler
Definition: psd.h:15
ushort
quint16 ushort
Definition: dds.cpp:37
ushort
quint16 ushort
Definition: psd.cpp:28
uchar
quint8 uchar
Definition: psd.cpp:29
PSDHandler::write
bool write(const QImage &image)
Definition: psd.cpp:282
PSDHandler::name
QByteArray name() const
Definition: psd.cpp:288
PSDHandler::canRead
bool canRead() const
Definition: psd.cpp:243
uint
quint32 uint
Definition: psd.cpp:27
operator>>
static QDataStream & operator>>(QDataStream &s, DDSPixelFormat &pf)
Definition: dds.cpp:144
PSDHandler::PSDHandler
PSDHandler()
Definition: psd.cpp:239
ColorMode
ColorMode
Definition: psd.cpp:33
PSDHandler::read
bool read(QImage *image)
Definition: psd.cpp:252
IsSupported
static bool IsSupported(const DDSHeader &header)
Definition: dds.cpp:276
uchar
quint8 uchar
Definition: dds.cpp:38
IsValid
static bool IsValid(const DDSHeader &header)
Definition: dds.cpp:205
QImageIOHandler
qRgba
QRgb qRgba(const QRgb &rgb, int a)
Change a QRgb value's alpha only.
Definition: xcf.cpp:67
uint
quint32 uint
Definition: dds.cpp:36
psd.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:47:50 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KImgIO

Skip menu "KImgIO"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal