LibreOffice Module vcl (master)  1
ipsd.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 
21 #include <vcl/graph.hxx>
22 #include <vcl/BitmapTools.hxx>
23 #include <vcl/outdev.hxx>
24 #include <sal/log.hxx>
25 #include <tools/fract.hxx>
26 #include <tools/helpers.hxx>
27 #include <tools/stream.hxx>
28 #include <memory>
29 #include <filter/PsdReader.hxx>
30 
31 
32 class FilterConfigItem;
33 
34 //============================ PSDReader ==================================
35 
36 #define PSD_BITMAP 0
37 #define PSD_GRAYSCALE 1
38 #define PSD_INDEXED 2
39 #define PSD_RGB 3
40 #define PSD_CMYK 4
41 #define PSD_MULTICHANNEL 7
42 #define PSD_DUOTONE 8
43 #define PSD_LAB 9
44 
45 namespace {
46 
47 struct PSDFileHeader
48 {
49  sal_uInt32 nSignature;
50  sal_uInt16 nVersion;
51  sal_uInt32 nPad1;
52  sal_uInt16 nPad2;
53  sal_uInt16 nChannels;
54  sal_uInt32 nRows;
55  sal_uInt32 nColumns;
56  sal_uInt16 nDepth;
57  sal_uInt16 nMode;
58 };
59 
60 class PSDReader {
61 
62 private:
63 
64  SvStream& m_rPSD; // the PSD file to be read in
65  std::unique_ptr<PSDFileHeader>
66  mpFileHeader;
67 
68  sal_uInt32 mnXResFixed;
69  sal_uInt32 mnYResFixed;
70 
71  bool mbStatus;
72  bool mbTransparent;
73 
74  std::unique_ptr<vcl::bitmap::RawBitmap> mpBitmap;
75  std::vector<Color> mvPalette;
76  sal_uInt16 mnDestBitDepth;
77  bool mbCompression; // RLE decoding
78  std::unique_ptr<sal_uInt8[]>
79  mpPalette;
80 
81  bool ImplReadBody();
82  bool ImplReadHeader();
83 
84 public:
85  explicit PSDReader(SvStream &rStream);
86  bool ReadPSD(Graphic & rGraphic);
87 };
88 
89 }
90 
91 //=================== Methods of PSDReader ==============================
92 
93 PSDReader::PSDReader(SvStream &rStream)
94  : m_rPSD(rStream)
95  , mnXResFixed(0)
96  , mnYResFixed(0)
97  , mbStatus(true)
98  , mbTransparent(false)
99  , mnDestBitDepth(0)
100  , mbCompression(false)
101 {
102 }
103 
104 bool PSDReader::ReadPSD(Graphic & rGraphic )
105 {
106  if (m_rPSD.GetError())
107  return false;
108 
109  m_rPSD.SetEndian( SvStreamEndian::BIG );
110 
111  // read header:
112 
113  if ( !ImplReadHeader() )
114  return false;
115 
116  if (mbStatus)
117  {
118  sal_uInt32 nResult;
119  if (o3tl::checked_multiply(mpFileHeader->nColumns, mpFileHeader->nRows, nResult) || nResult > SAL_MAX_INT32/2/3)
120  return false;
121  }
122 
123  Size aBitmapSize( mpFileHeader->nColumns, mpFileHeader->nRows );
124  mpBitmap.reset( new vcl::bitmap::RawBitmap( aBitmapSize, 24 ) );
125  if ( mpPalette && mbStatus )
126  {
127  mvPalette.resize( 256 );
128  for ( sal_uInt16 i = 0; i < 256; i++ )
129  {
130  mvPalette[i] = Color( mpPalette[ i ], mpPalette[ i + 256 ], mpPalette[ i + 512 ] );
131  }
132  }
133 
134  if ((mnDestBitDepth == 1 || mnDestBitDepth == 8 || mbTransparent) && mvPalette.empty())
135  {
136  mbStatus = false;
137  return mbStatus;
138  }
139 
140  // read bitmap data
141  if ( mbStatus && ImplReadBody() )
142  {
143  rGraphic = Graphic( vcl::bitmap::CreateFromData( std::move(*mpBitmap) ) );
144 
145  if ( mnXResFixed && mnYResFixed )
146  {
147  Fraction aFractX( 1, mnXResFixed >> 16 );
148  Fraction aFractY( 1, mnYResFixed >> 16 );
149  MapMode aMapMode( MapUnit::MapInch, Point(), aFractX, aFractY );
150  Size aPrefSize = OutputDevice::LogicToLogic(aBitmapSize, aMapMode, MapMode(MapUnit::Map100thMM));
151  rGraphic.SetPrefSize( aPrefSize );
152  rGraphic.SetPrefMapMode( MapMode( MapUnit::Map100thMM ) );
153  }
154  }
155  else
156  mbStatus = false;
157  return mbStatus;
158 }
159 
160 
161 bool PSDReader::ImplReadHeader()
162 {
163  mpFileHeader.reset( new PSDFileHeader );
164 
165  m_rPSD.ReadUInt32( mpFileHeader->nSignature ).ReadUInt16( mpFileHeader->nVersion ).ReadUInt32( mpFileHeader->nPad1 ). ReadUInt16( mpFileHeader->nPad2 ).ReadUInt16( mpFileHeader->nChannels ).ReadUInt32( mpFileHeader->nRows ). ReadUInt32( mpFileHeader->nColumns ).ReadUInt16( mpFileHeader->nDepth ).ReadUInt16( mpFileHeader->nMode );
166 
167  if ( ( mpFileHeader->nSignature != 0x38425053 ) || ( mpFileHeader->nVersion != 1 ) )
168  return false;
169 
170  if ( mpFileHeader->nRows == 0 || mpFileHeader->nColumns == 0 )
171  return false;
172 
173  if ( ( mpFileHeader->nRows > 30000 ) || ( mpFileHeader->nColumns > 30000 ) )
174  return false;
175 
176  sal_uInt16 nDepth = mpFileHeader->nDepth;
177  if (!( ( nDepth == 1 ) || ( nDepth == 8 ) || ( nDepth == 16 ) ) )
178  return false;
179 
180  mnDestBitDepth = ( nDepth == 16 ) ? 8 : nDepth;
181 
182  sal_uInt32 nColorLength(0);
183  m_rPSD.ReadUInt32( nColorLength );
184  if ( mpFileHeader->nMode == PSD_CMYK )
185  {
186  switch ( mpFileHeader->nChannels )
187  {
188  case 5 :
189  mbTransparent = true;
190  [[fallthrough]];
191  case 4 :
192  mnDestBitDepth = 24;
193  break;
194  default :
195  return false;
196  }
197  }
198  else switch ( mpFileHeader->nChannels )
199  {
200  case 2 :
201  mbTransparent = true;
202  break;
203  case 1 :
204  break;
205  case 4 :
206  mbTransparent = true;
207  [[fallthrough]];
208  case 3 :
209  mnDestBitDepth = 24;
210  break;
211  default:
212  return false;
213  }
214 
215  switch ( mpFileHeader->nMode )
216  {
217  case PSD_BITMAP :
218  {
219  if ( nColorLength || ( nDepth != 1 ) )
220  return false;
221  }
222  break;
223 
224  case PSD_INDEXED :
225  {
226  if ( nColorLength != 768 ) // we need the color map
227  return false;
228  mpPalette.reset( new sal_uInt8[ 768 ] );
229  m_rPSD.ReadBytes(mpPalette.get(), 768);
230  }
231  break;
232 
233  case PSD_DUOTONE : // we'll handle the duotone color like a normal grayscale picture
234  m_rPSD.SeekRel( nColorLength );
235  nColorLength = 0;
236  [[fallthrough]];
237  case PSD_GRAYSCALE :
238  {
239  if ( nColorLength )
240  return false;
241  mpPalette.reset( new sal_uInt8[ 768 ] );
242  for ( sal_uInt16 i = 0; i < 256; i++ )
243  {
244  mpPalette[ i ] = mpPalette[ i + 256 ] = mpPalette[ i + 512 ] = static_cast<sal_uInt8>(i);
245  }
246  }
247  break;
248 
249  case PSD_CMYK :
250  case PSD_RGB :
251  case PSD_MULTICHANNEL :
252  case PSD_LAB :
253  {
254  if ( nColorLength ) // color table is not supported by the other graphic modes
255  return false;
256  }
257  break;
258 
259  default:
260  return false;
261  }
262  sal_uInt32 nResourceLength(0);
263  m_rPSD.ReadUInt32(nResourceLength);
264  if (nResourceLength > m_rPSD.remainingSize())
265  return false;
266  sal_uInt32 nLayerPos = m_rPSD.Tell() + nResourceLength;
267 
268  // this is a loop over the resource entries to get the resolution info
269  while( m_rPSD.Tell() < nLayerPos )
270  {
271  sal_uInt32 nType(0);
272  sal_uInt16 nUniqueID(0);
273  sal_uInt8 n8(0);
274  m_rPSD.ReadUInt32(nType).ReadUInt16(nUniqueID).ReadUChar(n8);
275  if (nType != 0x3842494d)
276  break;
277  sal_uInt32 nPStringLen = n8;
278  if ( ! ( nPStringLen & 1 ) )
279  nPStringLen++;
280  m_rPSD.SeekRel( nPStringLen ); // skipping the pstring
281  sal_uInt32 nResEntryLen(0);
282  m_rPSD.ReadUInt32( nResEntryLen );
283  if ( nResEntryLen & 1 )
284  nResEntryLen++; // the resource entries are padded
285  sal_uInt32 nCurrentPos = m_rPSD.Tell();
286  if (nCurrentPos > nLayerPos || nResEntryLen > (nLayerPos - nCurrentPos)) // check if size
287  break; // is possible
288  switch( nUniqueID )
289  {
290  case 0x3ed : // UID for the resolution info
291  {
292  sal_Int16 nUnit;
293 
294  m_rPSD.ReadUInt32( mnXResFixed ).ReadInt16( nUnit ).ReadInt16( nUnit )
295  .ReadUInt32( mnYResFixed ).ReadInt16( nUnit ).ReadInt16( nUnit );
296  }
297  break;
298  }
299  m_rPSD.Seek( nCurrentPos + nResEntryLen ); // set the stream to the next
300  } // resource entry
301  m_rPSD.Seek( nLayerPos );
302  sal_uInt32 nLayerMaskLength(0);
303  m_rPSD.ReadUInt32( nLayerMaskLength );
304  m_rPSD.SeekRel( nLayerMaskLength );
305 
306  sal_uInt16 nCompression(0);
307  m_rPSD.ReadUInt16(nCompression);
308  if ( nCompression == 0 )
309  {
310  mbCompression = false;
311  }
312  else if ( nCompression == 1 )
313  {
314  m_rPSD.SeekRel( ( mpFileHeader->nRows * mpFileHeader->nChannels ) << 1 );
315  mbCompression = true;
316  }
317  else
318  return false;
319 
320  return true;
321 }
322 
323 namespace
324 {
325  const Color& SanitizePaletteIndex(std::vector<Color> const & rvPalette, sal_uInt8 nIndex)
326  {
327  if (nIndex >= rvPalette.size())
328  {
329  auto nSanitizedIndex = nIndex % rvPalette.size();
330  SAL_WARN_IF(nIndex != nSanitizedIndex, "filter.psd", "invalid colormap index: "
331  << static_cast<unsigned int>(nIndex) << ", colormap len is: "
332  << rvPalette.size());
333  nIndex = nSanitizedIndex;
334  }
335  return rvPalette[nIndex];
336  }
337 }
338 
339 bool PSDReader::ImplReadBody()
340 {
341  sal_uInt32 nX, nY;
342  signed char nRunCount = 0;
343  sal_uInt8 nDat = 0, nDummy, nRed, nGreen, nBlue;
344  BitmapColor aBitmapColor;
345  nX = nY = 0;
346 
347  switch ( mnDestBitDepth )
348  {
349  case 1 :
350  {
351  signed char nBitCount = -1;
352  while (nY < mpFileHeader->nRows && m_rPSD.good())
353  {
354  if ( nBitCount == -1 )
355  {
356  if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
357  {
358  char nTmp(0);
359  m_rPSD.ReadChar(nTmp);
360  nRunCount = nTmp;
361  }
362  }
363  if ( nRunCount & 0x80 ) // a run length packet
364  {
365  const sal_uInt16 nCount = -nRunCount + 1;
366  for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
367  {
368  if ( nBitCount == -1 ) // bits left in nDat?
369  {
370  m_rPSD.ReadUChar( nDat );
371  nDat ^= 0xff;
372  nBitCount = 7;
373  }
374  mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat >> nBitCount--));
375  if ( ++nX == mpFileHeader->nColumns )
376  {
377  nX = 0;
378  nY++;
379  nBitCount = -1;
380  if ( nY == mpFileHeader->nRows )
381  break;
382  }
383  }
384  }
385  else // a raw packet
386  {
387  const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
388  for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
389  {
390  if ( nBitCount == -1 ) // bits left in nDat ?
391  {
392  m_rPSD.ReadUChar( nDat );
393  nDat ^= 0xff;
394  nBitCount = 7;
395  }
396  mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat >> nBitCount--));
397  if ( ++nX == mpFileHeader->nColumns )
398  {
399  nX = 0;
400  nY++;
401  nBitCount = -1;
402  if ( nY == mpFileHeader->nRows )
403  break;
404  }
405  }
406  }
407  }
408  }
409  break;
410 
411  case 8 :
412  {
413  while (nY < mpFileHeader->nRows && m_rPSD.good())
414  {
415  if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
416  {
417  char nTmp(0);
418  m_rPSD.ReadChar(nTmp);
419  nRunCount = nTmp;
420  }
421 
422  if ( nRunCount & 0x80 ) // a run length packet
423  {
424  m_rPSD.ReadUChar( nDat );
425  if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
426  m_rPSD.ReadUChar( nDummy );
427  const sal_uInt16 nCount = -nRunCount + 1;
428  for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
429  {
430  mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat));
431  if ( ++nX == mpFileHeader->nColumns )
432  {
433  nX = 0;
434  nY++;
435  if ( nY == mpFileHeader->nRows )
436  break;
437  }
438  }
439  }
440  else // a raw packet
441  {
442  const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
443  for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
444  {
445  m_rPSD.ReadUChar( nDat );
446  if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
447  m_rPSD.ReadUChar( nDummy );
448  mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat));
449  if ( ++nX == mpFileHeader->nColumns )
450  {
451  nX = 0;
452  nY++;
453  if ( nY == mpFileHeader->nRows )
454  break;
455  }
456  }
457  }
458  }
459  }
460  break;
461 
462  case 24 :
463  {
464 
465  // the psd format is in plain order (RRRR GGGG BBBB) so we have to set each pixel three times
466  // maybe the format is CCCC MMMM YYYY KKKK
467 
468  while (nY < mpFileHeader->nRows && m_rPSD.good())
469  {
470  if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
471  {
472  char nTmp(0);
473  m_rPSD.ReadChar(nTmp);
474  nRunCount = nTmp;
475  }
476 
477  if ( nRunCount & 0x80 ) // a run length packet
478  {
479  m_rPSD.ReadUChar( nRed );
480  if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
481  m_rPSD.ReadUChar( nDummy );
482  const sal_uInt16 nCount = -nRunCount + 1;
483  for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
484  {
485  mpBitmap->SetPixel( nY, nX, Color( nRed, sal_uInt8(0), sal_uInt8(0) ) );
486  if ( ++nX == mpFileHeader->nColumns )
487  {
488  nX = 0;
489  nY++;
490  if ( nY == mpFileHeader->nRows )
491  break;
492  }
493  }
494  }
495  else // a raw packet
496  {
497  const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
498  for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
499  {
500  m_rPSD.ReadUChar( nRed );
501  if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
502  m_rPSD.ReadUChar( nDummy );
503  mpBitmap->SetPixel( nY, nX, Color( nRed, sal_uInt8(0), sal_uInt8(0) ) );
504  if ( ++nX == mpFileHeader->nColumns )
505  {
506  nX = 0;
507  nY++;
508  if ( nY == mpFileHeader->nRows )
509  break;
510  }
511  }
512  }
513  }
514  nY = 0;
515  while (nY < mpFileHeader->nRows && m_rPSD.good())
516  {
517  if ( mbCompression )
518  {
519  char nTmp(0);
520  m_rPSD.ReadChar(nTmp);
521  nRunCount = nTmp;
522  }
523 
524  if ( nRunCount & 0x80 ) // a run length packet
525  {
526  m_rPSD.ReadUChar( nGreen );
527  if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
528  m_rPSD.ReadUChar( nDummy );
529  const sal_uInt16 nCount = -nRunCount + 1;
530  for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
531  {
532  aBitmapColor = mpBitmap->GetPixel( nY, nX );
533  mpBitmap->SetPixel( nY, nX, Color( aBitmapColor.GetRed(), nGreen, aBitmapColor.GetBlue() ) );
534  if ( ++nX == mpFileHeader->nColumns )
535  {
536  nX = 0;
537  nY++;
538  if ( nY == mpFileHeader->nRows )
539  break;
540  }
541  }
542  }
543  else // a raw packet
544  {
545  const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
546  for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
547  {
548  m_rPSD.ReadUChar( nGreen );
549  if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
550  m_rPSD.ReadUChar( nDummy );
551  aBitmapColor = mpBitmap->GetPixel( nY, nX );
552  mpBitmap->SetPixel( nY, nX, Color( aBitmapColor.GetRed(), nGreen, aBitmapColor.GetBlue() ) );
553  if ( ++nX == mpFileHeader->nColumns )
554  {
555  nX = 0;
556  nY++;
557  if ( nY == mpFileHeader->nRows )
558  break;
559  }
560  }
561  }
562  }
563  nY = 0;
564  while (nY < mpFileHeader->nRows && m_rPSD.good())
565  {
566  if ( mbCompression )
567  {
568  char nTmp(0);
569  m_rPSD.ReadChar(nTmp);
570  nRunCount = nTmp;
571  }
572 
573  if ( nRunCount & 0x80 ) // a run length packet
574  {
575  m_rPSD.ReadUChar( nBlue );
576  if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
577  m_rPSD.ReadUChar( nDummy );
578  const sal_uInt16 nCount = -nRunCount + 1;
579  for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
580  {
581  aBitmapColor = mpBitmap->GetPixel( nY, nX );
582  mpBitmap->SetPixel( nY, nX, Color( aBitmapColor.GetRed(), aBitmapColor.GetGreen(), nBlue ) );
583  if ( ++nX == mpFileHeader->nColumns )
584  {
585  nX = 0;
586  nY++;
587  if ( nY == mpFileHeader->nRows )
588  break;
589  }
590  }
591  }
592  else // a raw packet
593  {
594  const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
595  for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
596  {
597  m_rPSD.ReadUChar( nBlue );
598  if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
599  m_rPSD.ReadUChar( nDummy );
600  aBitmapColor = mpBitmap->GetPixel( nY, nX );
601  mpBitmap->SetPixel( nY, nX, Color( aBitmapColor.GetRed(), aBitmapColor.GetGreen(), nBlue ) );
602  if ( ++nX == mpFileHeader->nColumns )
603  {
604  nX = 0;
605  nY++;
606  if ( nY == mpFileHeader->nRows )
607  break;
608  }
609  }
610  }
611  }
612  if (mpFileHeader->nMode == PSD_CMYK && m_rPSD.good())
613  {
614  sal_uInt32 nBlack, nBlackMax = 0;
615  std::unique_ptr<sal_uInt8[]> pBlack(new sal_uInt8[ mpFileHeader->nRows * mpFileHeader->nColumns ]);
616  nY = 0;
617  while (nY < mpFileHeader->nRows && m_rPSD.good())
618  {
619  if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
620  {
621  char nTmp(0);
622  m_rPSD.ReadChar(nTmp);
623  nRunCount = nTmp;
624  }
625 
626  if ( nRunCount & 0x80 ) // a run length packet
627  {
628  m_rPSD.ReadUChar( nDat );
629 
630  if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
631  m_rPSD.ReadUChar( nDummy );
632 
633  for ( sal_uInt16 i = 0; i < ( -nRunCount + 1 ); i++ )
634  {
635  nBlack = mpBitmap->GetPixel( nY, nX ).GetRed() + nDat;
636  if ( nBlack > nBlackMax )
637  nBlackMax = nBlack;
638  nBlack = mpBitmap->GetPixel( nY, nX ).GetGreen() + nDat;
639  if ( nBlack > nBlackMax )
640  nBlackMax = nBlack;
641  nBlack = mpBitmap->GetPixel( nY, nX ).GetBlue() + nDat;
642  if ( nBlack > nBlackMax )
643  nBlackMax = nBlack;
644  pBlack[ nX + nY * mpFileHeader->nColumns ] = nDat ^ 0xff;
645  if ( ++nX == mpFileHeader->nColumns )
646  {
647  nX = 0;
648  nY++;
649  if ( nY == mpFileHeader->nRows )
650  break;
651  }
652  }
653  }
654  else // a raw packet
655  {
656  for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
657  {
658  m_rPSD.ReadUChar( nDat );
659 
660  if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
661  m_rPSD.ReadUChar( nDummy );
662  nBlack = mpBitmap->GetPixel( nY, nX ).GetRed() + nDat;
663  if ( nBlack > nBlackMax )
664  nBlackMax = nBlack;
665  nBlack = mpBitmap->GetPixel( nY, nX ).GetGreen() + nDat;
666  if ( nBlack > nBlackMax )
667  nBlackMax = nBlack;
668  nBlack = mpBitmap->GetPixel( nY, nX ).GetBlue() + nDat;
669  if ( nBlack > nBlackMax )
670  nBlackMax = nBlack;
671  pBlack[ nX + nY * mpFileHeader->nColumns ] = nDat ^ 0xff;
672  if ( ++nX == mpFileHeader->nColumns )
673  {
674  nX = 0;
675  nY++;
676  if ( nY == mpFileHeader->nRows )
677  break;
678  }
679  }
680  }
681  }
682 
683  for ( nY = 0; nY < mpFileHeader->nRows; nY++ )
684  {
685  for ( nX = 0; nX < mpFileHeader->nColumns; nX++ )
686  {
687  sal_Int32 nDAT = pBlack[ nX + nY * mpFileHeader->nColumns ] * ( nBlackMax - 256 ) / 0x1ff;
688 
689  aBitmapColor = mpBitmap->GetPixel( nY, nX );
690  sal_uInt8 cR = static_cast<sal_uInt8>(MinMax( aBitmapColor.GetRed() - nDAT, 0, 255L ));
691  sal_uInt8 cG = static_cast<sal_uInt8>(MinMax( aBitmapColor.GetGreen() - nDAT, 0, 255L ));
692  sal_uInt8 cB = static_cast<sal_uInt8>(MinMax( aBitmapColor.GetBlue() - nDAT, 0, 255L ));
693  mpBitmap->SetPixel( nY, nX, Color( cR, cG, cB ) );
694  }
695  }
696  }
697  }
698  break;
699  }
700 
701  if (mbTransparent && m_rPSD.good())
702  {
703  // the psd is 24 or 8 bit grafix + alphachannel
704 
705  nY = nX = 0;
706  while ( nY < mpFileHeader->nRows )
707  {
708  if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
709  {
710  char nTmp(0);
711  m_rPSD.ReadChar(nTmp);
712  nRunCount = nTmp;
713  }
714 
715  if ( nRunCount & 0x80 ) // a run length packet
716  {
717  m_rPSD.ReadUChar( nDat );
718  if ( nDat )
719  nDat = 0;
720  else
721  nDat = 1;
722  if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
723  m_rPSD.ReadUChar( nDummy );
724  for ( sal_uInt16 i = 0; i < ( -nRunCount + 1 ); i++ )
725  {
726  mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat));
727  if ( ++nX == mpFileHeader->nColumns )
728  {
729  nX = 0;
730  nY++;
731  if ( nY == mpFileHeader->nRows )
732  break;
733  }
734  }
735  }
736  else // a raw packet
737  {
738  for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
739  {
740  m_rPSD.ReadUChar( nDat );
741  if ( nDat )
742  nDat = 0;
743  else
744  nDat = 1;
745  if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
746  m_rPSD.ReadUChar( nDummy );
747  mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat));
748  if ( ++nX == mpFileHeader->nColumns )
749  {
750  nX = 0;
751  nY++;
752  if ( nY == mpFileHeader->nRows )
753  break;
754  }
755  }
756  }
757  }
758  }
759 
760  return m_rPSD.good();
761 }
762 
763 //================== GraphicImport - the exported function ================
764 
765 bool ImportPsdGraphic(SvStream& rStream, Graphic& rGraphic)
766 {
767  PSDReader aPSDReader(rStream);
768  return aPSDReader.ReadPSD(rGraphic);
769 }
770 
771 
772 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt8 GetRed() const
Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
Definition: map.cxx:1466
void SetPrefMapMode(const MapMode &rPrefMapMode)
Definition: graph.cxx:380
std::enable_if< std::is_signed< T >::value||std::is_floating_point< T >::value, long >::type MinMax(T nVal, tools::Long nMin, tools::Long nMax)
BitmapEx CreateFromData(sal_uInt8 const *pData, sal_Int32 nWidth, sal_Int32 nHeight, sal_Int32 nStride, vcl::PixelFormat ePixelFormat)
Copy block of image data into the bitmap.
FPDF_BITMAP mpBitmap
#define PSD_GRAYSCALE
Definition: ipsd.cxx:37
int nCount
sal_uInt8 GetBlue() const
bool ImportPsdGraphic(SvStream &rStream, Graphic &rGraphic)
Definition: ipsd.cxx:765
#define PSD_DUOTONE
Definition: ipsd.cxx:42
int i
#define PSD_BITMAP
Definition: ipsd.cxx:36
std::enable_if< std::is_signed< T >::value, bool >::type checked_multiply(T a, T b, T &result)
sal_Int16 nVersion
Intended to be used to feed into CreateFromData to create a BitmapEx.
Definition: RawBitmap.hxx:21
short nBitCount
Definition: ipict.cxx:80
sal_uInt8 GetGreen() const
#define PSD_INDEXED
Definition: ipsd.cxx:38
#define SAL_WARN_IF(condition, area, stream)
unsigned char sal_uInt8
QPRO_FUNC_TYPE nType
void SetPrefSize(const Size &rPrefSize)
Definition: graph.cxx:369
#define PSD_RGB
Definition: ipsd.cxx:39
#define PSD_LAB
Definition: ipsd.cxx:43
#define PSD_CMYK
Definition: ipsd.cxx:40
#define PSD_MULTICHANNEL
Definition: ipsd.cxx:41