37 #define PSD_GRAYSCALE 1
41 #define PSD_MULTICHANNEL 7
49 sal_uInt32 nSignature;
65 std::unique_ptr<PSDFileHeader>
68 sal_uInt32 mnXResFixed;
69 sal_uInt32 mnYResFixed;
74 std::unique_ptr<vcl::bitmap::RawBitmap>
mpBitmap;
75 std::vector<Color> mvPalette;
76 sal_uInt16 mnDestBitDepth;
78 std::unique_ptr<sal_uInt8[]>
82 bool ImplReadHeader();
85 explicit PSDReader(
SvStream &rStream);
86 bool ReadPSD(
Graphic & rGraphic);
93 PSDReader::PSDReader(
SvStream &rStream)
98 , mbTransparent(false)
100 , mbCompression(false)
104 bool PSDReader::ReadPSD(
Graphic & rGraphic )
106 if (m_rPSD.GetError())
109 m_rPSD.SetEndian( SvStreamEndian::BIG );
113 if ( !ImplReadHeader() )
119 if (
o3tl::checked_multiply(mpFileHeader->nColumns, mpFileHeader->nRows, nResult) || nResult > SAL_MAX_INT32/2/3)
123 Size aBitmapSize( mpFileHeader->nColumns, mpFileHeader->nRows );
125 if ( mpPalette && mbStatus )
127 mvPalette.resize( 256 );
128 for ( sal_uInt16 i = 0;
i < 256;
i++ )
130 mvPalette[
i] =
Color( mpPalette[ i ], mpPalette[ i + 256 ], mpPalette[ i + 512 ] );
134 if ((mnDestBitDepth == 1 || mnDestBitDepth == 8 || mbTransparent) && mvPalette.empty())
141 if ( mbStatus && ImplReadBody() )
145 if ( mnXResFixed && mnYResFixed )
147 Fraction aFractX( 1, mnXResFixed >> 16 );
148 Fraction aFractY( 1, mnYResFixed >> 16 );
149 MapMode aMapMode( MapUnit::MapInch,
Point(), aFractX, aFractY );
161 bool PSDReader::ImplReadHeader()
163 mpFileHeader.reset(
new PSDFileHeader );
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 );
167 if ( ( mpFileHeader->nSignature != 0x38425053 ) || ( mpFileHeader->nVersion != 1 ) )
170 if ( mpFileHeader->nRows == 0 || mpFileHeader->nColumns == 0 )
173 if ( ( mpFileHeader->nRows > 30000 ) || ( mpFileHeader->nColumns > 30000 ) )
176 sal_uInt16 nDepth = mpFileHeader->nDepth;
177 if (!( ( nDepth == 1 ) || ( nDepth == 8 ) || ( nDepth == 16 ) ) )
180 mnDestBitDepth = ( nDepth == 16 ) ? 8 : nDepth;
182 sal_uInt32 nColorLength(0);
183 m_rPSD.ReadUInt32( nColorLength );
184 if ( mpFileHeader->nMode ==
PSD_CMYK )
186 switch ( mpFileHeader->nChannels )
189 mbTransparent =
true;
198 else switch ( mpFileHeader->nChannels )
201 mbTransparent =
true;
206 mbTransparent =
true;
215 switch ( mpFileHeader->nMode )
219 if ( nColorLength || ( nDepth != 1 ) )
226 if ( nColorLength != 768 )
229 m_rPSD.ReadBytes(mpPalette.get(), 768);
234 m_rPSD.SeekRel( nColorLength );
242 for ( sal_uInt16 i = 0;
i < 256;
i++ )
244 mpPalette[
i ] = mpPalette[
i + 256 ] = mpPalette[
i + 512 ] =
static_cast<sal_uInt8>(
i);
262 sal_uInt32 nResourceLength(0);
263 m_rPSD.ReadUInt32(nResourceLength);
264 if (nResourceLength > m_rPSD.remainingSize())
266 sal_uInt32 nLayerPos = m_rPSD.Tell() + nResourceLength;
269 while( m_rPSD.Tell() < nLayerPos )
272 sal_uInt16 nUniqueID(0);
274 m_rPSD.ReadUInt32(nType).ReadUInt16(nUniqueID).ReadUChar(n8);
275 if (nType != 0x3842494d)
277 sal_uInt32 nPStringLen = n8;
278 if ( ! ( nPStringLen & 1 ) )
280 m_rPSD.SeekRel( nPStringLen );
281 sal_uInt32 nResEntryLen(0);
282 m_rPSD.ReadUInt32( nResEntryLen );
283 if ( nResEntryLen & 1 )
285 sal_uInt32 nCurrentPos = m_rPSD.Tell();
286 if (nCurrentPos > nLayerPos || nResEntryLen > (nLayerPos - nCurrentPos))
294 m_rPSD.ReadUInt32( mnXResFixed ).ReadInt16( nUnit ).ReadInt16( nUnit )
295 .ReadUInt32( mnYResFixed ).ReadInt16( nUnit ).ReadInt16( nUnit );
299 m_rPSD.Seek( nCurrentPos + nResEntryLen );
301 m_rPSD.Seek( nLayerPos );
302 sal_uInt32 nLayerMaskLength(0);
303 m_rPSD.ReadUInt32( nLayerMaskLength );
304 m_rPSD.SeekRel( nLayerMaskLength );
306 sal_uInt16 nCompression(0);
307 m_rPSD.ReadUInt16(nCompression);
308 if ( nCompression == 0 )
310 mbCompression =
false;
312 else if ( nCompression == 1 )
314 m_rPSD.SeekRel( ( mpFileHeader->nRows * mpFileHeader->nChannels ) << 1 );
315 mbCompression =
true;
325 const Color& SanitizePaletteIndex(std::vector<Color>
const & rvPalette,
sal_uInt8 nIndex)
327 if (nIndex >= rvPalette.size())
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;
335 return rvPalette[nIndex];
339 bool PSDReader::ImplReadBody()
342 signed char nRunCount = 0;
343 sal_uInt8 nDat = 0, nDummy, nRed, nGreen, nBlue;
347 switch ( mnDestBitDepth )
352 while (nY < mpFileHeader->nRows && m_rPSD.good())
354 if ( nBitCount == -1 )
359 m_rPSD.ReadChar(nTmp);
363 if ( nRunCount & 0x80 )
365 const sal_uInt16
nCount = -nRunCount + 1;
366 for (sal_uInt16 i = 0;
i < nCount && m_rPSD.good(); ++
i)
368 if ( nBitCount == -1 )
370 m_rPSD.ReadUChar( nDat );
374 mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat >> nBitCount--));
375 if ( ++nX == mpFileHeader->nColumns )
380 if ( nY == mpFileHeader->nRows )
387 const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
388 for (sal_uInt16 i = 0;
i < nCount && m_rPSD.good(); ++
i)
390 if ( nBitCount == -1 )
392 m_rPSD.ReadUChar( nDat );
396 mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat >> nBitCount--));
397 if ( ++nX == mpFileHeader->nColumns )
402 if ( nY == mpFileHeader->nRows )
413 while (nY < mpFileHeader->nRows && m_rPSD.good())
418 m_rPSD.ReadChar(nTmp);
422 if ( nRunCount & 0x80 )
424 m_rPSD.ReadUChar( nDat );
425 if ( mpFileHeader->nDepth == 16 )
426 m_rPSD.ReadUChar( nDummy );
427 const sal_uInt16 nCount = -nRunCount + 1;
428 for (sal_uInt16 i = 0;
i < nCount && m_rPSD.good(); ++
i)
430 mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat));
431 if ( ++nX == mpFileHeader->nColumns )
435 if ( nY == mpFileHeader->nRows )
442 const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
443 for (sal_uInt16 i = 0;
i < nCount && m_rPSD.good(); ++
i)
445 m_rPSD.ReadUChar( nDat );
446 if ( mpFileHeader->nDepth == 16 )
447 m_rPSD.ReadUChar( nDummy );
448 mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat));
449 if ( ++nX == mpFileHeader->nColumns )
453 if ( nY == mpFileHeader->nRows )
468 while (nY < mpFileHeader->nRows && m_rPSD.good())
473 m_rPSD.ReadChar(nTmp);
477 if ( nRunCount & 0x80 )
479 m_rPSD.ReadUChar( nRed );
480 if ( mpFileHeader->nDepth == 16 )
481 m_rPSD.ReadUChar( nDummy );
482 const sal_uInt16 nCount = -nRunCount + 1;
483 for (sal_uInt16 i = 0;
i < nCount && m_rPSD.good(); ++
i)
486 if ( ++nX == mpFileHeader->nColumns )
490 if ( nY == mpFileHeader->nRows )
497 const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
498 for (sal_uInt16 i = 0;
i < nCount && m_rPSD.good(); ++
i)
500 m_rPSD.ReadUChar( nRed );
501 if ( mpFileHeader->nDepth == 16 )
502 m_rPSD.ReadUChar( nDummy );
504 if ( ++nX == mpFileHeader->nColumns )
508 if ( nY == mpFileHeader->nRows )
515 while (nY < mpFileHeader->nRows && m_rPSD.good())
520 m_rPSD.ReadChar(nTmp);
524 if ( nRunCount & 0x80 )
526 m_rPSD.ReadUChar( nGreen );
527 if ( mpFileHeader->nDepth == 16 )
528 m_rPSD.ReadUChar( nDummy );
529 const sal_uInt16 nCount = -nRunCount + 1;
530 for (sal_uInt16 i = 0;
i < nCount && m_rPSD.good(); ++
i)
532 aBitmapColor =
mpBitmap->GetPixel( nY, nX );
534 if ( ++nX == mpFileHeader->nColumns )
538 if ( nY == mpFileHeader->nRows )
545 const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
546 for (sal_uInt16 i = 0;
i < nCount && m_rPSD.good(); ++
i)
548 m_rPSD.ReadUChar( nGreen );
549 if ( mpFileHeader->nDepth == 16 )
550 m_rPSD.ReadUChar( nDummy );
551 aBitmapColor =
mpBitmap->GetPixel( nY, nX );
553 if ( ++nX == mpFileHeader->nColumns )
557 if ( nY == mpFileHeader->nRows )
564 while (nY < mpFileHeader->nRows && m_rPSD.good())
569 m_rPSD.ReadChar(nTmp);
573 if ( nRunCount & 0x80 )
575 m_rPSD.ReadUChar( nBlue );
576 if ( mpFileHeader->nDepth == 16 )
577 m_rPSD.ReadUChar( nDummy );
578 const sal_uInt16 nCount = -nRunCount + 1;
579 for (sal_uInt16 i = 0;
i < nCount && m_rPSD.good(); ++
i)
581 aBitmapColor =
mpBitmap->GetPixel( nY, nX );
583 if ( ++nX == mpFileHeader->nColumns )
587 if ( nY == mpFileHeader->nRows )
594 const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
595 for (sal_uInt16 i = 0;
i < nCount && m_rPSD.good(); ++
i)
597 m_rPSD.ReadUChar( nBlue );
598 if ( mpFileHeader->nDepth == 16 )
599 m_rPSD.ReadUChar( nDummy );
600 aBitmapColor =
mpBitmap->GetPixel( nY, nX );
602 if ( ++nX == mpFileHeader->nColumns )
606 if ( nY == mpFileHeader->nRows )
612 if (mpFileHeader->nMode ==
PSD_CMYK && m_rPSD.good())
614 sal_uInt32 nBlack, nBlackMax = 0;
615 std::unique_ptr<sal_uInt8[]> pBlack(
new sal_uInt8[ mpFileHeader->nRows * mpFileHeader->nColumns ]);
617 while (nY < mpFileHeader->nRows && m_rPSD.good())
622 m_rPSD.ReadChar(nTmp);
626 if ( nRunCount & 0x80 )
628 m_rPSD.ReadUChar( nDat );
630 if ( mpFileHeader->nDepth == 16 )
631 m_rPSD.ReadUChar( nDummy );
633 for ( sal_uInt16 i = 0;
i < ( -nRunCount + 1 );
i++ )
635 nBlack =
mpBitmap->GetPixel( nY, nX ).GetRed() + nDat;
636 if ( nBlack > nBlackMax )
638 nBlack =
mpBitmap->GetPixel( nY, nX ).GetGreen() + nDat;
639 if ( nBlack > nBlackMax )
641 nBlack =
mpBitmap->GetPixel( nY, nX ).GetBlue() + nDat;
642 if ( nBlack > nBlackMax )
644 pBlack[ nX + nY * mpFileHeader->nColumns ] = nDat ^ 0xff;
645 if ( ++nX == mpFileHeader->nColumns )
649 if ( nY == mpFileHeader->nRows )
656 for ( sal_uInt16 i = 0;
i < ( ( nRunCount & 0x7f ) + 1 );
i++ )
658 m_rPSD.ReadUChar( nDat );
660 if ( mpFileHeader->nDepth == 16 )
661 m_rPSD.ReadUChar( nDummy );
662 nBlack =
mpBitmap->GetPixel( nY, nX ).GetRed() + nDat;
663 if ( nBlack > nBlackMax )
665 nBlack =
mpBitmap->GetPixel( nY, nX ).GetGreen() + nDat;
666 if ( nBlack > nBlackMax )
668 nBlack =
mpBitmap->GetPixel( nY, nX ).GetBlue() + nDat;
669 if ( nBlack > nBlackMax )
671 pBlack[ nX + nY * mpFileHeader->nColumns ] = nDat ^ 0xff;
672 if ( ++nX == mpFileHeader->nColumns )
676 if ( nY == mpFileHeader->nRows )
683 for ( nY = 0; nY < mpFileHeader->nRows; nY++ )
685 for ( nX = 0; nX < mpFileHeader->nColumns; nX++ )
687 sal_Int32 nDAT = pBlack[ nX + nY * mpFileHeader->nColumns ] * ( nBlackMax - 256 ) / 0x1ff;
689 aBitmapColor =
mpBitmap->GetPixel( nY, nX );
701 if (mbTransparent && m_rPSD.good())
706 while ( nY < mpFileHeader->nRows )
711 m_rPSD.ReadChar(nTmp);
715 if ( nRunCount & 0x80 )
717 m_rPSD.ReadUChar( nDat );
722 if ( mpFileHeader->nDepth == 16 )
723 m_rPSD.ReadUChar( nDummy );
724 for ( sal_uInt16 i = 0;
i < ( -nRunCount + 1 );
i++ )
726 mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat));
727 if ( ++nX == mpFileHeader->nColumns )
731 if ( nY == mpFileHeader->nRows )
738 for ( sal_uInt16 i = 0;
i < ( ( nRunCount & 0x7f ) + 1 );
i++ )
740 m_rPSD.ReadUChar( nDat );
745 if ( mpFileHeader->nDepth == 16 )
746 m_rPSD.ReadUChar( nDummy );
747 mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat));
748 if ( ++nX == mpFileHeader->nColumns )
752 if ( nY == mpFileHeader->nRows )
760 return m_rPSD.good();
767 PSDReader aPSDReader(rStream);
768 return aPSDReader.ReadPSD(rGraphic);
Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
void SetPrefMapMode(const MapMode &rPrefMapMode)
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.
sal_uInt8 GetBlue() const
bool ImportPsdGraphic(SvStream &rStream, Graphic &rGraphic)
std::enable_if< std::is_signed< T >::value, bool >::type checked_multiply(T a, T b, T &result)
Intended to be used to feed into CreateFromData to create a BitmapEx.
sal_uInt8 GetGreen() const
#define SAL_WARN_IF(condition, area, stream)
void SetPrefSize(const Size &rPrefSize)