cid#1606940 Check of thread-shared field evades lock acquisition
[LibreOffice.git] / vcl / source / filter / ipsd / ipsd.cxx
blob887dccce1bf3f6dafb71518992a24dfef5cc63cb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
32 class FilterConfigItem;
34 //============================ PSDReader ==================================
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
45 namespace {
47 struct PSDFileHeader
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;
60 class PSDReader {
62 private:
64 SvStream& m_rPSD; // the PSD file to be read in
65 std::unique_ptr<PSDFileHeader>
66 mpFileHeader;
68 sal_uInt32 mnXResFixed;
69 sal_uInt32 mnYResFixed;
71 bool mbStatus;
72 bool mbTransparent;
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;
81 bool ImplReadBody();
82 bool ImplReadHeader();
84 public:
85 explicit PSDReader(SvStream &rStream);
86 bool ReadPSD(Graphic & rGraphic);
91 //=================== Methods of PSDReader ==============================
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)
104 bool PSDReader::ReadPSD(Graphic & rGraphic )
106 if (m_rPSD.GetError())
107 return false;
109 m_rPSD.SetEndian( SvStreamEndian::BIG );
111 // read header:
113 if ( !ImplReadHeader() )
114 return false;
116 if (mbStatus)
118 sal_uInt32 nResult;
119 if (o3tl::checked_multiply(mpFileHeader->nColumns, mpFileHeader->nRows, nResult) || nResult > SAL_MAX_INT32/2/3)
120 return false;
123 Size aBitmapSize( mpFileHeader->nColumns, mpFileHeader->nRows );
124 mpBitmap.reset( new vcl::bitmap::RawBitmap( aBitmapSize, mbTransparent ? 32 : 24 ) );
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) && mvPalette.empty())
136 SAL_WARN("vcl", "no palette, but bit depth is " << mnDestBitDepth);
137 mbStatus = false;
138 return mbStatus;
141 // read bitmap data
142 if ( mbStatus && ImplReadBody() )
144 rGraphic = Graphic( vcl::bitmap::CreateFromData( std::move(*mpBitmap) ) );
146 if ( mnXResFixed && mnYResFixed )
148 Fraction aFractX( 1, mnXResFixed >> 16 );
149 Fraction aFractY( 1, mnYResFixed >> 16 );
150 MapMode aMapMode( MapUnit::MapInch, Point(), aFractX, aFractY );
151 Size aPrefSize = OutputDevice::LogicToLogic(aBitmapSize, aMapMode, MapMode(MapUnit::Map100thMM));
152 rGraphic.SetPrefSize( aPrefSize );
153 rGraphic.SetPrefMapMode( MapMode( MapUnit::Map100thMM ) );
156 else
157 mbStatus = false;
158 return mbStatus;
162 bool PSDReader::ImplReadHeader()
164 mpFileHeader.reset( new PSDFileHeader );
166 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 );
168 if (!m_rPSD.good())
169 return false;
171 if ( ( mpFileHeader->nSignature != 0x38425053 ) || ( mpFileHeader->nVersion != 1 ) )
172 return false;
174 if ( mpFileHeader->nRows == 0 || mpFileHeader->nColumns == 0 )
175 return false;
177 if ( ( mpFileHeader->nRows > 30000 ) || ( mpFileHeader->nColumns > 30000 ) )
178 return false;
180 sal_uInt16 nDepth = mpFileHeader->nDepth;
181 if (!( ( nDepth == 1 ) || ( nDepth == 8 ) || ( nDepth == 16 ) ) )
182 return false;
184 mnDestBitDepth = ( nDepth == 16 ) ? 8 : nDepth;
186 sal_uInt32 nColorLength(0);
187 m_rPSD.ReadUInt32( nColorLength );
188 if ( mpFileHeader->nMode == PSD_CMYK )
190 switch ( mpFileHeader->nChannels )
192 case 5 :
193 mbTransparent = true;
194 [[fallthrough]];
195 case 4 :
196 mnDestBitDepth = 24;
197 break;
198 default :
199 return false;
202 else switch ( mpFileHeader->nChannels )
204 case 2 :
205 mbTransparent = true;
206 break;
207 case 1 :
208 break;
209 case 4 :
210 mbTransparent = true;
211 [[fallthrough]];
212 case 3 :
213 mnDestBitDepth = 24;
214 break;
215 default:
216 return false;
219 switch ( mpFileHeader->nMode )
221 case PSD_BITMAP :
223 if ( nColorLength || ( nDepth != 1 ) )
224 return false;
226 break;
228 case PSD_INDEXED :
230 if ( nColorLength != 768 ) // we need the color map
231 return false;
232 mpPalette.reset( new sal_uInt8[ 768 ] );
233 m_rPSD.ReadBytes(mpPalette.get(), 768);
235 break;
237 case PSD_DUOTONE : // we'll handle the duotone color like a normal grayscale picture
238 m_rPSD.SeekRel( nColorLength );
239 nColorLength = 0;
240 [[fallthrough]];
241 case PSD_GRAYSCALE :
243 if ( nColorLength )
244 return false;
245 mpPalette.reset( new sal_uInt8[ 768 ] );
246 for ( sal_uInt16 i = 0; i < 256; i++ )
248 mpPalette[ i ] = mpPalette[ i + 256 ] = mpPalette[ i + 512 ] = static_cast<sal_uInt8>(i);
251 break;
253 case PSD_CMYK :
254 case PSD_RGB :
255 case PSD_MULTICHANNEL :
256 case PSD_LAB :
258 if ( nColorLength ) // color table is not supported by the other graphic modes
259 return false;
261 break;
263 default:
264 return false;
266 sal_uInt32 nResourceLength(0);
267 m_rPSD.ReadUInt32(nResourceLength);
268 if (nResourceLength > m_rPSD.remainingSize())
269 return false;
270 sal_uInt64 nLayerPos = m_rPSD.Tell() + nResourceLength;
272 // this is a loop over the resource entries to get the resolution info
273 while( m_rPSD.Tell() < nLayerPos )
275 sal_uInt32 nType(0);
276 sal_uInt16 nUniqueID(0);
277 sal_uInt8 n8(0);
278 m_rPSD.ReadUInt32(nType).ReadUInt16(nUniqueID).ReadUChar(n8);
279 if (nType != 0x3842494d)
280 break;
281 sal_uInt32 nPStringLen = n8;
282 if ( ! ( nPStringLen & 1 ) )
283 nPStringLen++;
284 m_rPSD.SeekRel( nPStringLen ); // skipping the pstring
285 sal_uInt32 nResEntryLen(0);
286 m_rPSD.ReadUInt32( nResEntryLen );
287 if ( nResEntryLen & 1 )
288 nResEntryLen++; // the resource entries are padded
289 sal_uInt64 nCurrentPos = m_rPSD.Tell();
290 if (nCurrentPos > nLayerPos || nResEntryLen > (nLayerPos - nCurrentPos)) // check if size
291 break; // is possible
292 switch( nUniqueID )
294 case 0x3ed : // UID for the resolution info
296 sal_Int16 nUnit;
298 m_rPSD.ReadUInt32( mnXResFixed ).ReadInt16( nUnit ).ReadInt16( nUnit )
299 .ReadUInt32( mnYResFixed ).ReadInt16( nUnit ).ReadInt16( nUnit );
301 break;
303 m_rPSD.Seek( nCurrentPos + nResEntryLen ); // set the stream to the next
304 } // resource entry
305 m_rPSD.Seek( nLayerPos );
306 sal_uInt32 nLayerMaskLength(0);
307 m_rPSD.ReadUInt32( nLayerMaskLength );
308 m_rPSD.SeekRel( nLayerMaskLength );
310 sal_uInt16 nCompression(0);
311 m_rPSD.ReadUInt16(nCompression);
312 if ( nCompression == 0 )
314 mbCompression = false;
316 else if ( nCompression == 1 )
318 m_rPSD.SeekRel( ( mpFileHeader->nRows * mpFileHeader->nChannels ) << 1 );
319 mbCompression = true;
321 else
322 return false;
324 return true;
327 namespace
329 const Color& SanitizePaletteIndex(std::vector<Color> const & rvPalette, sal_uInt8 nIndex)
331 if (nIndex >= rvPalette.size())
333 auto nSanitizedIndex = nIndex % rvPalette.size();
334 SAL_WARN_IF(nIndex != nSanitizedIndex, "filter.psd", "invalid colormap index: "
335 << static_cast<unsigned int>(nIndex) << ", colormap len is: "
336 << rvPalette.size());
337 nIndex = nSanitizedIndex;
339 return rvPalette[nIndex];
343 bool PSDReader::ImplReadBody()
345 sal_uInt32 nX, nY;
346 signed char nRunCount = 0;
347 sal_uInt8 nDat = 0, nDummy, nRed, nGreen, nBlue;
348 BitmapColor aBitmapColor;
349 nX = nY = 0;
351 switch ( mnDestBitDepth )
353 case 1 :
355 signed char nBitCount = -1;
356 while (nY < mpFileHeader->nRows && m_rPSD.good())
358 if ( nBitCount == -1 )
360 if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
362 char nTmp(0);
363 m_rPSD.ReadChar(nTmp);
364 nRunCount = nTmp;
367 if ( nRunCount & 0x80 ) // a run length packet
369 const sal_uInt16 nCount = -nRunCount + 1;
370 for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
372 if ( nBitCount == -1 ) // bits left in nDat?
374 m_rPSD.ReadUChar( nDat );
375 nDat ^= 0xff;
376 nBitCount = 7;
378 mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat >> nBitCount--));
379 if ( ++nX == mpFileHeader->nColumns )
381 nX = 0;
382 nY++;
383 nBitCount = -1;
384 if ( nY == mpFileHeader->nRows )
385 break;
389 else // a raw packet
391 const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
392 for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
394 if ( nBitCount == -1 ) // bits left in nDat ?
396 m_rPSD.ReadUChar( nDat );
397 nDat ^= 0xff;
398 nBitCount = 7;
400 mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat >> nBitCount--));
401 if ( ++nX == mpFileHeader->nColumns )
403 nX = 0;
404 nY++;
405 nBitCount = -1;
406 if ( nY == mpFileHeader->nRows )
407 break;
413 break;
415 case 8 :
417 while (nY < mpFileHeader->nRows && m_rPSD.good())
419 if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
421 char nTmp(0);
422 m_rPSD.ReadChar(nTmp);
423 nRunCount = nTmp;
426 if ( nRunCount & 0x80 ) // a run length packet
428 m_rPSD.ReadUChar( nDat );
429 if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
430 m_rPSD.ReadUChar( nDummy );
431 const sal_uInt16 nCount = -nRunCount + 1;
432 for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
434 mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat));
435 if ( ++nX == mpFileHeader->nColumns )
437 nX = 0;
438 nY++;
439 if ( nY == mpFileHeader->nRows )
440 break;
444 else // a raw packet
446 const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
447 for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
449 m_rPSD.ReadUChar( nDat );
450 if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
451 m_rPSD.ReadUChar( nDummy );
452 mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat));
453 if ( ++nX == mpFileHeader->nColumns )
455 nX = 0;
456 nY++;
457 if ( nY == mpFileHeader->nRows )
458 break;
464 break;
466 case 24 :
469 // the psd format is in plain order (RRRR GGGG BBBB) so we have to set each pixel three times
470 // maybe the format is CCCC MMMM YYYY KKKK
472 while (nY < mpFileHeader->nRows && m_rPSD.good())
474 if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
476 char nTmp(0);
477 m_rPSD.ReadChar(nTmp);
478 nRunCount = nTmp;
481 if ( nRunCount & 0x80 ) // a run length packet
483 m_rPSD.ReadUChar( nRed );
484 if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
485 m_rPSD.ReadUChar( nDummy );
486 const sal_uInt16 nCount = -nRunCount + 1;
487 for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
489 mpBitmap->SetPixel( nY, nX, Color( nRed, sal_uInt8(0), sal_uInt8(0) ) );
490 if ( ++nX == mpFileHeader->nColumns )
492 nX = 0;
493 nY++;
494 if ( nY == mpFileHeader->nRows )
495 break;
499 else // a raw packet
501 const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
502 for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
504 m_rPSD.ReadUChar( nRed );
505 if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
506 m_rPSD.ReadUChar( nDummy );
507 mpBitmap->SetPixel( nY, nX, Color( nRed, sal_uInt8(0), sal_uInt8(0) ) );
508 if ( ++nX == mpFileHeader->nColumns )
510 nX = 0;
511 nY++;
512 if ( nY == mpFileHeader->nRows )
513 break;
518 nY = 0;
519 while (nY < mpFileHeader->nRows && m_rPSD.good())
521 if ( mbCompression )
523 char nTmp(0);
524 m_rPSD.ReadChar(nTmp);
525 nRunCount = nTmp;
528 if ( nRunCount & 0x80 ) // a run length packet
530 m_rPSD.ReadUChar( nGreen );
531 if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
532 m_rPSD.ReadUChar( nDummy );
533 const sal_uInt16 nCount = -nRunCount + 1;
534 for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
536 aBitmapColor = mpBitmap->GetPixel( nY, nX );
537 mpBitmap->SetPixel( nY, nX, Color( aBitmapColor.GetRed(), nGreen, aBitmapColor.GetBlue() ) );
538 if ( ++nX == mpFileHeader->nColumns )
540 nX = 0;
541 nY++;
542 if ( nY == mpFileHeader->nRows )
543 break;
547 else // a raw packet
549 const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
550 for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
552 m_rPSD.ReadUChar( nGreen );
553 if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
554 m_rPSD.ReadUChar( nDummy );
555 aBitmapColor = mpBitmap->GetPixel( nY, nX );
556 mpBitmap->SetPixel( nY, nX, Color( aBitmapColor.GetRed(), nGreen, aBitmapColor.GetBlue() ) );
557 if ( ++nX == mpFileHeader->nColumns )
559 nX = 0;
560 nY++;
561 if ( nY == mpFileHeader->nRows )
562 break;
567 nY = 0;
568 while (nY < mpFileHeader->nRows && m_rPSD.good())
570 if ( mbCompression )
572 char nTmp(0);
573 m_rPSD.ReadChar(nTmp);
574 nRunCount = nTmp;
577 if ( nRunCount & 0x80 ) // a run length packet
579 m_rPSD.ReadUChar( nBlue );
580 if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
581 m_rPSD.ReadUChar( nDummy );
582 const sal_uInt16 nCount = -nRunCount + 1;
583 for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
585 aBitmapColor = mpBitmap->GetPixel( nY, nX );
586 mpBitmap->SetPixel( nY, nX, Color( aBitmapColor.GetRed(), aBitmapColor.GetGreen(), nBlue ) );
587 if ( ++nX == mpFileHeader->nColumns )
589 nX = 0;
590 nY++;
591 if ( nY == mpFileHeader->nRows )
592 break;
596 else // a raw packet
598 const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
599 for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
601 m_rPSD.ReadUChar( nBlue );
602 if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
603 m_rPSD.ReadUChar( nDummy );
604 aBitmapColor = mpBitmap->GetPixel( nY, nX );
605 mpBitmap->SetPixel( nY, nX, Color( aBitmapColor.GetRed(), aBitmapColor.GetGreen(), nBlue ) );
606 if ( ++nX == mpFileHeader->nColumns )
608 nX = 0;
609 nY++;
610 if ( nY == mpFileHeader->nRows )
611 break;
616 if (mpFileHeader->nMode == PSD_CMYK && m_rPSD.good())
618 sal_uInt32 nBlack, nBlackMax = 0;
619 std::vector<sal_uInt8> aBlack(mpFileHeader->nRows * mpFileHeader->nColumns, 0);
620 nY = 0;
621 while (nY < mpFileHeader->nRows && m_rPSD.good())
623 if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
625 char nTmp(0);
626 m_rPSD.ReadChar(nTmp);
627 nRunCount = nTmp;
630 if ( nRunCount & 0x80 ) // a run length packet
632 m_rPSD.ReadUChar( nDat );
634 if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
635 m_rPSD.ReadUChar( nDummy );
637 for ( sal_uInt16 i = 0; i < ( -nRunCount + 1 ); i++ )
639 nBlack = mpBitmap->GetPixel( nY, nX ).GetRed() + nDat;
640 if ( nBlack > nBlackMax )
641 nBlackMax = nBlack;
642 nBlack = mpBitmap->GetPixel( nY, nX ).GetGreen() + nDat;
643 if ( nBlack > nBlackMax )
644 nBlackMax = nBlack;
645 nBlack = mpBitmap->GetPixel( nY, nX ).GetBlue() + nDat;
646 if ( nBlack > nBlackMax )
647 nBlackMax = nBlack;
648 aBlack[ nX + nY * mpFileHeader->nColumns ] = nDat ^ 0xff;
649 if ( ++nX == mpFileHeader->nColumns )
651 nX = 0;
652 nY++;
653 if ( nY == mpFileHeader->nRows )
654 break;
658 else // a raw packet
660 for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
662 m_rPSD.ReadUChar( nDat );
664 if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
665 m_rPSD.ReadUChar( nDummy );
666 nBlack = mpBitmap->GetPixel( nY, nX ).GetRed() + nDat;
667 if ( nBlack > nBlackMax )
668 nBlackMax = nBlack;
669 nBlack = mpBitmap->GetPixel( nY, nX ).GetGreen() + nDat;
670 if ( nBlack > nBlackMax )
671 nBlackMax = nBlack;
672 nBlack = mpBitmap->GetPixel( nY, nX ).GetBlue() + nDat;
673 if ( nBlack > nBlackMax )
674 nBlackMax = nBlack;
675 aBlack[ nX + nY * mpFileHeader->nColumns ] = nDat ^ 0xff;
676 if ( ++nX == mpFileHeader->nColumns )
678 nX = 0;
679 nY++;
680 if ( nY == mpFileHeader->nRows )
681 break;
687 for ( nY = 0; nY < mpFileHeader->nRows; nY++ )
689 for ( nX = 0; nX < mpFileHeader->nColumns; nX++ )
691 sal_Int32 nDAT = aBlack[ nX + nY * mpFileHeader->nColumns ] * ( nBlackMax - 256 ) / 0x1ff;
693 aBitmapColor = mpBitmap->GetPixel( nY, nX );
694 sal_uInt8 cR = static_cast<sal_uInt8>(std::clamp( aBitmapColor.GetRed() - nDAT, sal_Int32(0), sal_Int32(255) ));
695 sal_uInt8 cG = static_cast<sal_uInt8>(std::clamp( aBitmapColor.GetGreen() - nDAT, sal_Int32(0), sal_Int32(255) ));
696 sal_uInt8 cB = static_cast<sal_uInt8>(std::clamp( aBitmapColor.GetBlue() - nDAT, sal_Int32(0), sal_Int32(255) ));
697 mpBitmap->SetPixel( nY, nX, Color( cR, cG, cB ) );
702 break;
705 if (mbTransparent && m_rPSD.good())
707 // the psd is 24 or 8 bit grafix + alpha channel
709 nY = nX = 0;
710 while ( nY < mpFileHeader->nRows )
712 if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
714 char nTmp(0);
715 m_rPSD.ReadChar(nTmp);
716 nRunCount = nTmp;
719 if ( nRunCount & 0x80 ) // a run length packet
721 m_rPSD.ReadUChar( nDat );
722 if ( nDat )
723 nDat = 0;
724 else
725 nDat = 1;
726 if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
727 m_rPSD.ReadUChar( nDummy );
728 for ( sal_uInt16 i = 0; i < ( -nRunCount + 1 ); i++ )
730 mpBitmap->SetAlpha(nY, nX, nDat ? 255 : 0);
731 if ( ++nX == mpFileHeader->nColumns )
733 nX = 0;
734 nY++;
735 if ( nY == mpFileHeader->nRows )
736 break;
740 else // a raw packet
742 for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
744 m_rPSD.ReadUChar( nDat );
745 if ( nDat )
746 nDat = 0;
747 else
748 nDat = 1;
749 if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
750 m_rPSD.ReadUChar( nDummy );
751 mpBitmap->SetAlpha(nY, nX, nDat ? 255 : 0);
752 if ( ++nX == mpFileHeader->nColumns )
754 nX = 0;
755 nY++;
756 if ( nY == mpFileHeader->nRows )
757 break;
764 return m_rPSD.good();
767 //================== GraphicImport - the exported function ================
769 bool ImportPsdGraphic(SvStream& rStream, Graphic& rGraphic)
771 PSDReader aPSDReader(rStream);
772 return aPSDReader.ReadPSD(rGraphic);
776 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */