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
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
45namespace {
46
47struct 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
60class PSDReader {
61
62private:
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
84public:
85 explicit PSDReader(SvStream &rStream);
86 bool ReadPSD(Graphic & rGraphic);
87};
88
89}
90
91//=================== Methods of PSDReader ==============================
92
93PSDReader::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
104bool 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, mbTransparent ? 32 : 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) && mvPalette.empty())
135 {
136 SAL_WARN("vcl", "no palette, but bit depth is " << mnDestBitDepth);
137 mbStatus = false;
138 return mbStatus;
139 }
140
141 // read bitmap data
142 if ( mbStatus && ImplReadBody() )
143 {
144 rGraphic = Graphic( vcl::bitmap::CreateFromData( std::move(*mpBitmap) ) );
145
146 if ( mnXResFixed && mnYResFixed )
147 {
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 ) );
154 }
155 }
156 else
157 mbStatus = false;
158 return mbStatus;
159}
160
161
162bool PSDReader::ImplReadHeader()
163{
164 mpFileHeader.reset( new PSDFileHeader );
165
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 );
167
168 if (!m_rPSD.good())
169 return false;
170
171 if ( ( mpFileHeader->nSignature != 0x38425053 ) || ( mpFileHeader->nVersion != 1 ) )
172 return false;
173
174 if ( mpFileHeader->nRows == 0 || mpFileHeader->nColumns == 0 )
175 return false;
176
177 if ( ( mpFileHeader->nRows > 30000 ) || ( mpFileHeader->nColumns > 30000 ) )
178 return false;
179
180 sal_uInt16 nDepth = mpFileHeader->nDepth;
181 if (!( ( nDepth == 1 ) || ( nDepth == 8 ) || ( nDepth == 16 ) ) )
182 return false;
183
184 mnDestBitDepth = ( nDepth == 16 ) ? 8 : nDepth;
185
186 sal_uInt32 nColorLength(0);
187 m_rPSD.ReadUInt32( nColorLength );
188 if ( mpFileHeader->nMode == PSD_CMYK )
189 {
190 switch ( mpFileHeader->nChannels )
191 {
192 case 5 :
193 mbTransparent = true;
194 [[fallthrough]];
195 case 4 :
196 mnDestBitDepth = 24;
197 break;
198 default :
199 return false;
200 }
201 }
202 else switch ( mpFileHeader->nChannels )
203 {
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;
217 }
218
219 switch ( mpFileHeader->nMode )
220 {
221 case PSD_BITMAP :
222 {
223 if ( nColorLength || ( nDepth != 1 ) )
224 return false;
225 }
226 break;
227
228 case PSD_INDEXED :
229 {
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);
234 }
235 break;
236
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 :
242 {
243 if ( nColorLength )
244 return false;
245 mpPalette.reset( new sal_uInt8[ 768 ] );
246 for ( sal_uInt16 i = 0; i < 256; i++ )
247 {
248 mpPalette[ i ] = mpPalette[ i + 256 ] = mpPalette[ i + 512 ] = static_cast<sal_uInt8>(i);
249 }
250 }
251 break;
252
253 case PSD_CMYK :
254 case PSD_RGB :
255 case PSD_MULTICHANNEL :
256 case PSD_LAB :
257 {
258 if ( nColorLength ) // color table is not supported by the other graphic modes
259 return false;
260 }
261 break;
262
263 default:
264 return false;
265 }
266 sal_uInt32 nResourceLength(0);
267 m_rPSD.ReadUInt32(nResourceLength);
268 if (nResourceLength > m_rPSD.remainingSize())
269 return false;
270 sal_uInt32 nLayerPos = m_rPSD.Tell() + nResourceLength;
271
272 // this is a loop over the resource entries to get the resolution info
273 while( m_rPSD.Tell() < nLayerPos )
274 {
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_uInt32 nCurrentPos = m_rPSD.Tell();
290 if (nCurrentPos > nLayerPos || nResEntryLen > (nLayerPos - nCurrentPos)) // check if size
291 break; // is possible
292 switch( nUniqueID )
293 {
294 case 0x3ed : // UID for the resolution info
295 {
296 sal_Int16 nUnit;
297
298 m_rPSD.ReadUInt32( mnXResFixed ).ReadInt16( nUnit ).ReadInt16( nUnit )
299 .ReadUInt32( mnYResFixed ).ReadInt16( nUnit ).ReadInt16( nUnit );
300 }
301 break;
302 }
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 );
309
310 sal_uInt16 nCompression(0);
311 m_rPSD.ReadUInt16(nCompression);
312 if ( nCompression == 0 )
313 {
314 mbCompression = false;
315 }
316 else if ( nCompression == 1 )
317 {
318 m_rPSD.SeekRel( ( mpFileHeader->nRows * mpFileHeader->nChannels ) << 1 );
319 mbCompression = true;
320 }
321 else
322 return false;
323
324 return true;
325}
326
327namespace
328{
329 const Color& SanitizePaletteIndex(std::vector<Color> const & rvPalette, sal_uInt8 nIndex)
330 {
331 if (nIndex >= rvPalette.size())
332 {
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;
338 }
339 return rvPalette[nIndex];
340 }
341}
342
343bool PSDReader::ImplReadBody()
344{
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;
350
351 switch ( mnDestBitDepth )
352 {
353 case 1 :
354 {
355 signed char nBitCount = -1;
356 while (nY < mpFileHeader->nRows && m_rPSD.good())
357 {
358 if ( nBitCount == -1 )
359 {
360 if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
361 {
362 char nTmp(0);
363 m_rPSD.ReadChar(nTmp);
364 nRunCount = nTmp;
365 }
366 }
367 if ( nRunCount & 0x80 ) // a run length packet
368 {
369 const sal_uInt16 nCount = -nRunCount + 1;
370 for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
371 {
372 if ( nBitCount == -1 ) // bits left in nDat?
373 {
374 m_rPSD.ReadUChar( nDat );
375 nDat ^= 0xff;
376 nBitCount = 7;
377 }
378 mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat >> nBitCount--));
379 if ( ++nX == mpFileHeader->nColumns )
380 {
381 nX = 0;
382 nY++;
383 nBitCount = -1;
384 if ( nY == mpFileHeader->nRows )
385 break;
386 }
387 }
388 }
389 else // a raw packet
390 {
391 const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
392 for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
393 {
394 if ( nBitCount == -1 ) // bits left in nDat ?
395 {
396 m_rPSD.ReadUChar( nDat );
397 nDat ^= 0xff;
398 nBitCount = 7;
399 }
400 mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat >> nBitCount--));
401 if ( ++nX == mpFileHeader->nColumns )
402 {
403 nX = 0;
404 nY++;
405 nBitCount = -1;
406 if ( nY == mpFileHeader->nRows )
407 break;
408 }
409 }
410 }
411 }
412 }
413 break;
414
415 case 8 :
416 {
417 while (nY < mpFileHeader->nRows && m_rPSD.good())
418 {
419 if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
420 {
421 char nTmp(0);
422 m_rPSD.ReadChar(nTmp);
423 nRunCount = nTmp;
424 }
425
426 if ( nRunCount & 0x80 ) // a run length packet
427 {
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)
433 {
434 mpBitmap->SetPixel(nY, nX, SanitizePaletteIndex(mvPalette, nDat));
435 if ( ++nX == mpFileHeader->nColumns )
436 {
437 nX = 0;
438 nY++;
439 if ( nY == mpFileHeader->nRows )
440 break;
441 }
442 }
443 }
444 else // a raw packet
445 {
446 const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
447 for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
448 {
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 )
454 {
455 nX = 0;
456 nY++;
457 if ( nY == mpFileHeader->nRows )
458 break;
459 }
460 }
461 }
462 }
463 }
464 break;
465
466 case 24 :
467 {
468
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
471
472 while (nY < mpFileHeader->nRows && m_rPSD.good())
473 {
474 if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
475 {
476 char nTmp(0);
477 m_rPSD.ReadChar(nTmp);
478 nRunCount = nTmp;
479 }
480
481 if ( nRunCount & 0x80 ) // a run length packet
482 {
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)
488 {
489 mpBitmap->SetPixel( nY, nX, Color( nRed, sal_uInt8(0), sal_uInt8(0) ) );
490 if ( ++nX == mpFileHeader->nColumns )
491 {
492 nX = 0;
493 nY++;
494 if ( nY == mpFileHeader->nRows )
495 break;
496 }
497 }
498 }
499 else // a raw packet
500 {
501 const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
502 for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
503 {
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 )
509 {
510 nX = 0;
511 nY++;
512 if ( nY == mpFileHeader->nRows )
513 break;
514 }
515 }
516 }
517 }
518 nY = 0;
519 while (nY < mpFileHeader->nRows && m_rPSD.good())
520 {
521 if ( mbCompression )
522 {
523 char nTmp(0);
524 m_rPSD.ReadChar(nTmp);
525 nRunCount = nTmp;
526 }
527
528 if ( nRunCount & 0x80 ) // a run length packet
529 {
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)
535 {
536 aBitmapColor = mpBitmap->GetPixel( nY, nX );
537 mpBitmap->SetPixel( nY, nX, Color( aBitmapColor.GetRed(), nGreen, aBitmapColor.GetBlue() ) );
538 if ( ++nX == mpFileHeader->nColumns )
539 {
540 nX = 0;
541 nY++;
542 if ( nY == mpFileHeader->nRows )
543 break;
544 }
545 }
546 }
547 else // a raw packet
548 {
549 const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
550 for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
551 {
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 )
558 {
559 nX = 0;
560 nY++;
561 if ( nY == mpFileHeader->nRows )
562 break;
563 }
564 }
565 }
566 }
567 nY = 0;
568 while (nY < mpFileHeader->nRows && m_rPSD.good())
569 {
570 if ( mbCompression )
571 {
572 char nTmp(0);
573 m_rPSD.ReadChar(nTmp);
574 nRunCount = nTmp;
575 }
576
577 if ( nRunCount & 0x80 ) // a run length packet
578 {
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)
584 {
585 aBitmapColor = mpBitmap->GetPixel( nY, nX );
586 mpBitmap->SetPixel( nY, nX, Color( aBitmapColor.GetRed(), aBitmapColor.GetGreen(), nBlue ) );
587 if ( ++nX == mpFileHeader->nColumns )
588 {
589 nX = 0;
590 nY++;
591 if ( nY == mpFileHeader->nRows )
592 break;
593 }
594 }
595 }
596 else // a raw packet
597 {
598 const sal_uInt16 nCount = (nRunCount & 0x7f) + 1;
599 for (sal_uInt16 i = 0; i < nCount && m_rPSD.good(); ++i)
600 {
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 )
607 {
608 nX = 0;
609 nY++;
610 if ( nY == mpFileHeader->nRows )
611 break;
612 }
613 }
614 }
615 }
616 if (mpFileHeader->nMode == PSD_CMYK && m_rPSD.good())
617 {
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())
622 {
623 if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
624 {
625 char nTmp(0);
626 m_rPSD.ReadChar(nTmp);
627 nRunCount = nTmp;
628 }
629
630 if ( nRunCount & 0x80 ) // a run length packet
631 {
632 m_rPSD.ReadUChar( nDat );
633
634 if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
635 m_rPSD.ReadUChar( nDummy );
636
637 for ( sal_uInt16 i = 0; i < ( -nRunCount + 1 ); i++ )
638 {
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 )
650 {
651 nX = 0;
652 nY++;
653 if ( nY == mpFileHeader->nRows )
654 break;
655 }
656 }
657 }
658 else // a raw packet
659 {
660 for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
661 {
662 m_rPSD.ReadUChar( nDat );
663
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 )
677 {
678 nX = 0;
679 nY++;
680 if ( nY == mpFileHeader->nRows )
681 break;
682 }
683 }
684 }
685 }
686
687 for ( nY = 0; nY < mpFileHeader->nRows; nY++ )
688 {
689 for ( nX = 0; nX < mpFileHeader->nColumns; nX++ )
690 {
691 sal_Int32 nDAT = aBlack[ nX + nY * mpFileHeader->nColumns ] * ( nBlackMax - 256 ) / 0x1ff;
692
693 aBitmapColor = mpBitmap->GetPixel( nY, nX );
694 sal_uInt8 cR = static_cast<sal_uInt8>(MinMax( aBitmapColor.GetRed() - nDAT, 0, 255L ));
695 sal_uInt8 cG = static_cast<sal_uInt8>(MinMax( aBitmapColor.GetGreen() - nDAT, 0, 255L ));
696 sal_uInt8 cB = static_cast<sal_uInt8>(MinMax( aBitmapColor.GetBlue() - nDAT, 0, 255L ));
697 mpBitmap->SetPixel( nY, nX, Color( cR, cG, cB ) );
698 }
699 }
700 }
701 }
702 break;
703 }
704
705 if (mbTransparent && m_rPSD.good())
706 {
707 // the psd is 24 or 8 bit grafix + alpha channel
708
709 nY = nX = 0;
710 while ( nY < mpFileHeader->nRows )
711 {
712 if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
713 {
714 char nTmp(0);
715 m_rPSD.ReadChar(nTmp);
716 nRunCount = nTmp;
717 }
718
719 if ( nRunCount & 0x80 ) // a run length packet
720 {
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++ )
729 {
730 mpBitmap->SetAlpha(nY, nX, nDat ? 255 : 0);
731 if ( ++nX == mpFileHeader->nColumns )
732 {
733 nX = 0;
734 nY++;
735 if ( nY == mpFileHeader->nRows )
736 break;
737 }
738 }
739 }
740 else // a raw packet
741 {
742 for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
743 {
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 )
753 {
754 nX = 0;
755 nY++;
756 if ( nY == mpFileHeader->nRows )
757 break;
758 }
759 }
760 }
761 }
762 }
763
764 return m_rPSD.good();
765}
766
767//================== GraphicImport - the exported function ================
768
769bool ImportPsdGraphic(SvStream& rStream, Graphic& rGraphic)
770{
771 PSDReader aPSDReader(rStream);
772 return aPSDReader.ReadPSD(rGraphic);
773}
774
775
776/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
FPDF_BITMAP mpBitmap
sal_uInt8 GetBlue() const
sal_uInt8 GetRed() const
sal_uInt8 GetGreen() const
void SetPrefMapMode(const MapMode &rPrefMapMode)
Definition: graph.cxx:380
void SetPrefSize(const Size &rPrefSize)
Definition: graph.cxx:369
SAL_WARN_UNUSED_RESULT Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
Definition: map.cxx:1580
Intended to be used to feed into CreateFromData to create a BitmapEx.
Definition: RawBitmap.hxx:22
int nCount
sal_Int16 nVersion
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)
sal_Int32 nIndex
short nBitCount
Definition: ipict.cxx:80
bool ImportPsdGraphic(SvStream &rStream, Graphic &rGraphic)
Definition: ipsd.cxx:769
#define PSD_LAB
Definition: ipsd.cxx:43
#define PSD_MULTICHANNEL
Definition: ipsd.cxx:41
#define PSD_GRAYSCALE
Definition: ipsd.cxx:37
#define PSD_RGB
Definition: ipsd.cxx:39
#define PSD_DUOTONE
Definition: ipsd.cxx:42
#define PSD_CMYK
Definition: ipsd.cxx:40
#define PSD_INDEXED
Definition: ipsd.cxx:38
#define PSD_BITMAP
Definition: ipsd.cxx:36
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
int i
std::enable_if< std::is_signed< T >::value, bool >::type checked_multiply(T a, T b, T &result)
BitmapEx CreateFromData(sal_uInt8 const *pData, sal_Int32 nWidth, sal_Int32 nHeight, sal_Int32 nStride, sal_Int8 nBitCount, bool bReversColors, bool bReverseAlpha)
Copy block of image data into the bitmap.
QPRO_FUNC_TYPE nType
unsigned char sal_uInt8