Line data Source code
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/bmpacc.hxx>
23 : #include <vcl/outdev.hxx>
24 : #include <tools/fract.hxx>
25 : #include <boost/scoped_array.hpp>
26 :
27 : class FilterConfigItem;
28 :
29 : //============================ PSDReader ==================================
30 :
31 : #define PSD_BITMAP 0
32 : #define PSD_GRAYSCALE 1
33 : #define PSD_INDEXED 2
34 : #define PSD_RGB 3
35 : #define PSD_CMYK 4
36 : #define PSD_MULTICHANNEL 7
37 : #define PSD_DUOTONE 8
38 : #define PSD_LAB 9
39 :
40 : typedef struct
41 : {
42 : sal_uInt32 nSignature;
43 : sal_uInt16 nVersion;
44 : sal_uInt32 nPad1;
45 : sal_uInt16 nPad2;
46 : sal_uInt16 nChannels;
47 : sal_uInt32 nRows;
48 : sal_uInt32 nColumns;
49 : sal_uInt16 nDepth;
50 : sal_uInt16 nMode;
51 :
52 : } PSDFileHeader;
53 :
54 : class PSDReader {
55 :
56 : private:
57 :
58 : SvStream& m_rPSD; // Die einzulesende PSD-Datei
59 : PSDFileHeader* mpFileHeader;
60 :
61 : sal_uInt32 mnXResFixed;
62 : sal_uInt32 mnYResFixed;
63 :
64 : bool mbStatus;
65 : bool mbTransparent;
66 :
67 : Bitmap maBmp;
68 : Bitmap maMaskBmp;
69 : BitmapReadAccess* mpReadAcc;
70 : BitmapWriteAccess* mpWriteAcc;
71 : BitmapWriteAccess* mpMaskWriteAcc;
72 : sal_uInt16 mnDestBitDepth;
73 : bool mbCompression; // RLE decoding
74 : sal_uInt8* mpPalette;
75 :
76 : bool ImplReadBody();
77 : bool ImplReadHeader();
78 :
79 : public:
80 : PSDReader(SvStream &rStream);
81 : ~PSDReader();
82 : bool ReadPSD(Graphic & rGraphic);
83 : };
84 :
85 : //=================== Methods of PSDReader ==============================
86 :
87 3 : PSDReader::PSDReader(SvStream &rStream)
88 : : m_rPSD(rStream)
89 : , mpFileHeader(NULL)
90 : , mnXResFixed(0)
91 : , mnYResFixed(0)
92 : , mbStatus(true)
93 : , mbTransparent(false)
94 : , mpReadAcc(NULL)
95 : , mpWriteAcc(NULL)
96 : , mpMaskWriteAcc(NULL)
97 : , mnDestBitDepth(0)
98 : , mbCompression(false)
99 3 : , mpPalette(NULL)
100 : {
101 3 : }
102 :
103 6 : PSDReader::~PSDReader()
104 : {
105 3 : delete[] mpPalette;
106 3 : delete mpFileHeader;
107 3 : }
108 :
109 3 : bool PSDReader::ReadPSD(Graphic & rGraphic )
110 : {
111 3 : if (m_rPSD.GetError())
112 0 : return false;
113 :
114 3 : m_rPSD.SetEndian( SvStreamEndian::BIG );
115 :
116 : // read header:
117 :
118 3 : if ( !ImplReadHeader() )
119 1 : return false;
120 :
121 2 : Size aBitmapSize( mpFileHeader->nColumns, mpFileHeader->nRows );
122 2 : maBmp = Bitmap( aBitmapSize, mnDestBitDepth );
123 2 : if ( ( mpWriteAcc = maBmp.AcquireWriteAccess() ) == NULL )
124 0 : mbStatus = false;
125 2 : if ( ( mpReadAcc = maBmp.AcquireReadAccess() ) == NULL )
126 0 : mbStatus = false;
127 2 : if ( mbTransparent && mbStatus )
128 : {
129 0 : maMaskBmp = Bitmap( aBitmapSize, 1 );
130 0 : if ( ( mpMaskWriteAcc = maMaskBmp.AcquireWriteAccess() ) == NULL )
131 0 : mbStatus = false;
132 : }
133 2 : if ( mpPalette && mbStatus )
134 : {
135 0 : mpWriteAcc->SetPaletteEntryCount( 256 );
136 0 : for ( sal_uInt16 i = 0; i < 256; i++ )
137 : {
138 0 : mpWriteAcc->SetPaletteColor( i, Color( mpPalette[ i ], mpPalette[ i + 256 ], mpPalette[ i + 512 ] ) );
139 : }
140 : }
141 : // read bitmap data
142 2 : if ( mbStatus && ImplReadBody() )
143 : {
144 2 : if ( mbTransparent )
145 0 : rGraphic = Graphic( BitmapEx( maBmp, maMaskBmp ) );
146 : else
147 2 : rGraphic = maBmp;
148 :
149 2 : if ( mnXResFixed && mnYResFixed )
150 : {
151 2 : Point aEmptyPoint;
152 2 : Fraction aFractX( 1, mnXResFixed >> 16 );
153 4 : Fraction aFractY( 1, mnYResFixed >> 16 );
154 4 : MapMode aMapMode( MAP_INCH, aEmptyPoint, aFractX, aFractY );
155 2 : Size aPrefSize = OutputDevice::LogicToLogic( aBitmapSize, aMapMode, MAP_100TH_MM );
156 2 : rGraphic.SetPrefSize( aPrefSize );
157 4 : rGraphic.SetPrefMapMode( MapMode( MAP_100TH_MM ) );
158 : }
159 : }
160 : else
161 0 : mbStatus = false;
162 2 : if ( mpWriteAcc )
163 2 : Bitmap::ReleaseAccess( mpWriteAcc );
164 2 : if ( mpReadAcc )
165 2 : Bitmap::ReleaseAccess( mpReadAcc );
166 2 : if ( mpMaskWriteAcc )
167 0 : Bitmap::ReleaseAccess( mpMaskWriteAcc );
168 2 : return mbStatus;
169 : }
170 :
171 :
172 :
173 3 : bool PSDReader::ImplReadHeader()
174 : {
175 : sal_uInt16 nCompression;
176 : sal_uInt32 nColorLength, nResourceLength, nLayerMaskLength;
177 :
178 3 : mpFileHeader = new PSDFileHeader;
179 :
180 3 : 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 );
181 :
182 3 : if ( ( mpFileHeader->nSignature != 0x38425053 ) || ( mpFileHeader->nVersion != 1 ) )
183 0 : return false;
184 :
185 3 : if ( mpFileHeader->nRows == 0 || mpFileHeader->nColumns == 0 )
186 0 : return false;
187 :
188 3 : if ( ( mpFileHeader->nRows > 30000 ) || ( mpFileHeader->nColumns > 30000 ) )
189 0 : return false;
190 :
191 3 : sal_uInt16 nDepth = mpFileHeader->nDepth;
192 3 : if (!( ( nDepth == 1 ) || ( nDepth == 8 ) || ( nDepth == 16 ) ) )
193 0 : return false;
194 :
195 3 : mnDestBitDepth = ( nDepth == 16 ) ? 8 : nDepth;
196 :
197 3 : m_rPSD.ReadUInt32( nColorLength );
198 3 : if ( mpFileHeader->nMode == PSD_CMYK )
199 : {
200 0 : switch ( mpFileHeader->nChannels )
201 : {
202 : case 5 :
203 0 : mbTransparent = true;
204 : case 4 :
205 0 : mnDestBitDepth = 24;
206 0 : break;
207 : default :
208 0 : return false;
209 : }
210 : }
211 3 : else switch ( mpFileHeader->nChannels )
212 : {
213 : case 2 :
214 0 : mbTransparent = true;
215 : case 1 :
216 0 : break;
217 : case 4 :
218 1 : mbTransparent = true;
219 : case 3 :
220 3 : mnDestBitDepth = 24;
221 3 : break;
222 : default:
223 0 : return false;
224 : }
225 :
226 3 : switch ( mpFileHeader->nMode )
227 : {
228 : case PSD_BITMAP :
229 : {
230 0 : if ( nColorLength || ( nDepth != 1 ) )
231 0 : return false;
232 : }
233 0 : break;
234 :
235 : case PSD_INDEXED :
236 : {
237 0 : if ( nColorLength != 768 ) // we need the color map
238 0 : return false;
239 0 : mpPalette = new sal_uInt8[ 768 ];
240 0 : m_rPSD.Read( mpPalette, 768 );
241 : }
242 0 : break;
243 :
244 : case PSD_DUOTONE : // we'll handle the duotone color like a normal grayscale picture
245 0 : m_rPSD.SeekRel( nColorLength );
246 0 : nColorLength = 0;
247 : /* Fall through */
248 : case PSD_GRAYSCALE :
249 : {
250 0 : if ( nColorLength )
251 0 : return false;
252 0 : mpPalette = new sal_uInt8[ 768 ];
253 0 : for ( sal_uInt16 i = 0; i < 256; i++ )
254 : {
255 0 : mpPalette[ i ] = mpPalette[ i + 256 ] = mpPalette[ i + 512 ] = (sal_uInt8)i;
256 : }
257 : }
258 0 : break;
259 :
260 : case PSD_CMYK :
261 : case PSD_RGB :
262 : case PSD_MULTICHANNEL :
263 : case PSD_LAB :
264 : {
265 3 : if ( nColorLength ) // color table is not supported by the other graphic modes
266 0 : return false;
267 : }
268 3 : break;
269 :
270 : default:
271 0 : return false;
272 : }
273 3 : m_rPSD.ReadUInt32( nResourceLength );
274 3 : sal_uInt32 nLayerPos = m_rPSD.Tell() + nResourceLength;
275 :
276 : // this is a loop over the resource entries to get the resolution info
277 48 : while( m_rPSD.Tell() < nLayerPos )
278 : {
279 : sal_uInt8 n8;
280 : sal_uInt32 nType, nPStringLen, nResEntryLen;
281 : sal_uInt16 nUniqueID;
282 :
283 43 : m_rPSD.ReadUInt32( nType ).ReadUInt16( nUniqueID ).ReadUChar( n8 );
284 43 : nPStringLen = n8;
285 43 : if ( nType != 0x3842494d )
286 2 : break;
287 42 : if ( ! ( nPStringLen & 1 ) )
288 42 : nPStringLen++;
289 42 : m_rPSD.SeekRel( nPStringLen ); // skipping the pstring
290 42 : m_rPSD.ReadUInt32( nResEntryLen );
291 42 : if ( nResEntryLen & 1 )
292 8 : nResEntryLen++; // the resource entries are padded
293 42 : sal_uInt32 nCurrentPos = m_rPSD.Tell();
294 42 : if ( ( nResEntryLen + nCurrentPos ) > nLayerPos ) // check if size
295 0 : break; // is possible
296 42 : switch( nUniqueID )
297 : {
298 : case 0x3ed : // UID for the resolution info
299 : {
300 : sal_Int16 nUnit;
301 :
302 2 : m_rPSD.ReadUInt32( mnXResFixed ).ReadInt16( nUnit ).ReadInt16( nUnit )
303 4 : .ReadUInt32( mnYResFixed ).ReadInt16( nUnit ).ReadInt16( nUnit );
304 : }
305 2 : break;
306 : }
307 42 : m_rPSD.Seek( nCurrentPos + nResEntryLen ); // set the stream to the next
308 : } // resource entry
309 3 : m_rPSD.Seek( nLayerPos );
310 3 : m_rPSD.ReadUInt32( nLayerMaskLength );
311 3 : m_rPSD.SeekRel( nLayerMaskLength );
312 :
313 3 : m_rPSD.ReadUInt16( nCompression );
314 3 : if ( nCompression == 0 )
315 : {
316 0 : mbCompression = false;
317 : }
318 3 : else if ( nCompression == 1 )
319 : {
320 2 : m_rPSD.SeekRel( ( mpFileHeader->nRows * mpFileHeader->nChannels ) << 1 );
321 2 : mbCompression = true;
322 : }
323 : else
324 1 : return false;
325 :
326 2 : return true;
327 : }
328 :
329 :
330 :
331 2 : bool PSDReader::ImplReadBody()
332 : {
333 : sal_uLong nX, nY;
334 2 : char nRunCount = 0;
335 2 : sal_uInt8 nDat = 0, nDummy, nRed, nGreen, nBlue;
336 2 : BitmapColor aBitmapColor;
337 2 : nX = nY = 0;
338 :
339 2 : switch ( mnDestBitDepth )
340 : {
341 : case 1 :
342 : {
343 0 : signed char nBitCount = -1;
344 0 : while ( nY < mpFileHeader->nRows )
345 : {
346 0 : if ( nBitCount == -1 )
347 : {
348 0 : if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
349 0 : m_rPSD.ReadChar( nRunCount );
350 : }
351 0 : if ( nRunCount & 0x80 ) // a run length packet
352 : {
353 0 : for ( sal_uInt16 i = 0; i < ( -nRunCount + 1 ); i++ )
354 : {
355 0 : if ( nBitCount == -1 ) // bits left in nDat?
356 : {
357 0 : m_rPSD.ReadUChar( nDat );
358 0 : nDat ^= 0xff;
359 0 : nBitCount = 7;
360 : }
361 0 : mpWriteAcc->SetPixelIndex( nY, nX, nDat >> nBitCount-- );
362 0 : if ( ++nX == mpFileHeader->nColumns )
363 : {
364 0 : nX = 0;
365 0 : nY++;
366 0 : nBitCount = -1;
367 0 : if ( nY == mpFileHeader->nRows )
368 0 : break;
369 : }
370 : }
371 : }
372 : else // a raw packet
373 : {
374 0 : for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
375 : {
376 0 : if ( nBitCount == -1 ) // bits left in nDat ?
377 : {
378 0 : m_rPSD.ReadUChar( nDat );
379 0 : nDat ^= 0xff;
380 0 : nBitCount = 7;
381 : }
382 0 : mpWriteAcc->SetPixelIndex( nY, nX, nDat >> nBitCount-- );
383 0 : if ( ++nX == mpFileHeader->nColumns )
384 : {
385 0 : nX = 0;
386 0 : nY++;
387 0 : nBitCount = -1;
388 0 : if ( nY == mpFileHeader->nRows )
389 0 : break;
390 : }
391 : }
392 : }
393 : }
394 : }
395 0 : break;
396 :
397 : case 8 :
398 : {
399 0 : while ( nY < mpFileHeader->nRows )
400 : {
401 0 : if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
402 0 : m_rPSD.ReadChar( nRunCount );
403 :
404 0 : if ( nRunCount & 0x80 ) // a run length packet
405 : {
406 0 : m_rPSD.ReadUChar( nDat );
407 0 : if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
408 0 : m_rPSD.ReadUChar( nDummy );
409 0 : for ( sal_uInt16 i = 0; i < ( -nRunCount + 1 ); i++ )
410 : {
411 0 : mpWriteAcc->SetPixelIndex( nY, nX, nDat );
412 0 : if ( ++nX == mpFileHeader->nColumns )
413 : {
414 0 : nX = 0;
415 0 : nY++;
416 0 : if ( nY == mpFileHeader->nRows )
417 0 : break;
418 : }
419 : }
420 : }
421 : else // a raw packet
422 : {
423 0 : for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
424 : {
425 0 : m_rPSD.ReadUChar( nDat );
426 0 : if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
427 0 : m_rPSD.ReadUChar( nDummy );
428 0 : mpWriteAcc->SetPixelIndex( nY, nX, nDat );
429 0 : if ( ++nX == mpFileHeader->nColumns )
430 : {
431 0 : nX = 0;
432 0 : nY++;
433 0 : if ( nY == mpFileHeader->nRows )
434 0 : break;
435 : }
436 : }
437 : }
438 : }
439 : }
440 0 : break;
441 :
442 : case 24 :
443 : {
444 :
445 : // the psd format is in plain order (RRRR GGGG BBBB) so we have to set each pixel three times
446 : // maybe the format is CCCC MMMM YYYY KKKK
447 :
448 30301 : while ( nY < mpFileHeader->nRows )
449 : {
450 30297 : if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
451 30297 : m_rPSD.ReadChar( nRunCount );
452 :
453 30297 : if ( nRunCount & 0x80 ) // a run length packet
454 : {
455 19723 : m_rPSD.ReadUChar( nRed );
456 19723 : if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
457 0 : m_rPSD.ReadUChar( nDummy );
458 731655 : for ( sal_uInt16 i = 0; i < ( -nRunCount + 1 ); i++ )
459 : {
460 711934 : mpWriteAcc->SetPixel( nY, nX, BitmapColor( nRed, (sal_uInt8)0, (sal_uInt8)0 ) );
461 711934 : if ( ++nX == mpFileHeader->nColumns )
462 : {
463 753 : nX = 0;
464 753 : nY++;
465 753 : if ( nY == mpFileHeader->nRows )
466 2 : break;
467 : }
468 : }
469 : }
470 : else // a raw packet
471 : {
472 69848 : for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
473 : {
474 59274 : m_rPSD.ReadUChar( nRed );
475 59274 : if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
476 0 : m_rPSD.ReadUChar( nDummy );
477 59274 : mpWriteAcc->SetPixel( nY, nX, BitmapColor( nRed, (sal_uInt8)0, (sal_uInt8)0 ) );
478 59274 : if ( ++nX == mpFileHeader->nColumns )
479 : {
480 264 : nX = 0;
481 264 : nY++;
482 264 : if ( nY == mpFileHeader->nRows )
483 0 : break;
484 : }
485 : }
486 : }
487 : }
488 2 : nY = 0;
489 30602 : while ( nY < mpFileHeader->nRows )
490 : {
491 30598 : if ( mbCompression )
492 30598 : m_rPSD.ReadChar( nRunCount );
493 30598 : if ( nRunCount & 0x80 ) // a run length packet
494 : {
495 19879 : m_rPSD.ReadUChar( nGreen );
496 19879 : if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
497 0 : m_rPSD.ReadUChar( nDummy );
498 730788 : for ( sal_uInt16 i = 0; i < ( -nRunCount + 1 ); i++ )
499 : {
500 710911 : aBitmapColor = mpReadAcc->GetPixel( nY, nX );
501 710911 : mpWriteAcc->SetPixel( nY, nX, BitmapColor( aBitmapColor.GetRed(), nGreen, aBitmapColor.GetBlue() ) );
502 710911 : if ( ++nX == mpFileHeader->nColumns )
503 : {
504 730 : nX = 0;
505 730 : nY++;
506 730 : if ( nY == mpFileHeader->nRows )
507 2 : break;
508 : }
509 : }
510 : }
511 : else // a raw packet
512 : {
513 71016 : for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
514 : {
515 60297 : m_rPSD.ReadUChar( nGreen );
516 60297 : if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
517 0 : m_rPSD.ReadUChar( nDummy );
518 60297 : aBitmapColor = mpReadAcc->GetPixel( nY, nX );
519 60297 : mpWriteAcc->SetPixel( nY, nX, BitmapColor( aBitmapColor.GetRed(), nGreen, aBitmapColor.GetBlue() ) );
520 60297 : if ( ++nX == mpFileHeader->nColumns )
521 : {
522 287 : nX = 0;
523 287 : nY++;
524 287 : if ( nY == mpFileHeader->nRows )
525 0 : break;
526 : }
527 : }
528 : }
529 : }
530 2 : nY = 0;
531 30706 : while ( nY < mpFileHeader->nRows )
532 : {
533 30702 : if ( mbCompression )
534 30702 : m_rPSD.ReadChar( nRunCount );
535 30702 : if ( nRunCount & 0x80 ) // a run length packet
536 : {
537 19973 : m_rPSD.ReadUChar( nBlue );
538 19973 : if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
539 0 : m_rPSD.ReadUChar( nDummy );
540 731348 : for ( sal_uInt16 i = 0; i < ( -nRunCount + 1 ); i++ )
541 : {
542 711377 : aBitmapColor = mpReadAcc->GetPixel( nY, nX );
543 711377 : mpWriteAcc->SetPixel( nY, nX, BitmapColor( aBitmapColor.GetRed(), aBitmapColor.GetGreen(), nBlue ) );
544 711377 : if ( ++nX == mpFileHeader->nColumns )
545 : {
546 744 : nX = 0;
547 744 : nY++;
548 744 : if ( nY == mpFileHeader->nRows )
549 2 : break;
550 : }
551 : }
552 : }
553 : else // a raw packet
554 : {
555 70560 : for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
556 : {
557 59831 : m_rPSD.ReadUChar( nBlue );
558 59831 : if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
559 0 : m_rPSD.ReadUChar( nDummy );
560 59831 : aBitmapColor = mpReadAcc->GetPixel( nY, nX );
561 59831 : mpWriteAcc->SetPixel( nY, nX, BitmapColor( aBitmapColor.GetRed(), aBitmapColor.GetGreen(), nBlue ) );
562 59831 : if ( ++nX == mpFileHeader->nColumns )
563 : {
564 273 : nX = 0;
565 273 : nY++;
566 273 : if ( nY == mpFileHeader->nRows )
567 0 : break;
568 : }
569 : }
570 : }
571 : }
572 2 : if ( mpFileHeader->nMode == PSD_CMYK )
573 : {
574 0 : sal_uInt32 nBlack, nBlackMax = 0;
575 0 : boost::scoped_array<sal_uInt8> pBlack(new sal_uInt8[ mpFileHeader->nRows * mpFileHeader->nColumns ]);
576 0 : nY = 0;
577 0 : while ( nY < mpFileHeader->nRows )
578 : {
579 0 : if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
580 0 : m_rPSD.ReadChar( nRunCount );
581 :
582 0 : if ( nRunCount & 0x80 ) // a run length packet
583 : {
584 0 : m_rPSD.ReadUChar( nDat );
585 :
586 0 : if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
587 0 : m_rPSD.ReadUChar( nDummy );
588 :
589 0 : for ( sal_uInt16 i = 0; i < ( -nRunCount + 1 ); i++ )
590 : {
591 0 : nBlack = (sal_uInt8)mpReadAcc->GetPixel( nY, nX ).GetRed() + nDat;
592 0 : if ( nBlack > nBlackMax )
593 0 : nBlackMax = nBlack;
594 0 : nBlack = (sal_uInt8)mpReadAcc->GetPixel( nY, nX ).GetGreen() + nDat;
595 0 : if ( nBlack > nBlackMax )
596 0 : nBlackMax = nBlack;
597 0 : nBlack = (sal_uInt8)mpReadAcc->GetPixel( nY, nX ).GetBlue() + nDat;
598 0 : if ( nBlack > nBlackMax )
599 0 : nBlackMax = nBlack;
600 0 : pBlack[ nX + nY * mpFileHeader->nColumns ] = nDat ^ 0xff;
601 0 : if ( ++nX == mpFileHeader->nColumns )
602 : {
603 0 : nX = 0;
604 0 : nY++;
605 0 : if ( nY == mpFileHeader->nRows )
606 0 : break;
607 : }
608 : }
609 : }
610 : else // a raw packet
611 : {
612 0 : for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
613 : {
614 0 : m_rPSD.ReadUChar( nDat );
615 :
616 0 : if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
617 0 : m_rPSD.ReadUChar( nDummy );
618 0 : nBlack = (sal_uInt8)mpReadAcc->GetPixel( nY, nX ).GetRed() + nDat;
619 0 : if ( nBlack > nBlackMax )
620 0 : nBlackMax = nBlack;
621 0 : nBlack = (sal_uInt8)mpReadAcc->GetPixel( nY, nX ).GetGreen() + nDat;
622 0 : if ( nBlack > nBlackMax )
623 0 : nBlackMax = nBlack;
624 0 : nBlack = (sal_uInt8)mpReadAcc->GetPixel( nY, nX ).GetBlue() + nDat;
625 0 : if ( nBlack > nBlackMax )
626 0 : nBlackMax = nBlack;
627 0 : pBlack[ nX + nY * mpFileHeader->nColumns ] = nDat ^ 0xff;
628 0 : if ( ++nX == mpFileHeader->nColumns )
629 : {
630 0 : nX = 0;
631 0 : nY++;
632 0 : if ( nY == mpFileHeader->nRows )
633 0 : break;
634 : }
635 : }
636 : }
637 : }
638 :
639 0 : for ( nY = 0; nY < mpFileHeader->nRows; nY++ )
640 : {
641 0 : for ( nX = 0; nX < mpFileHeader->nColumns; nX++ )
642 : {
643 0 : sal_Int32 nDAT = pBlack[ nX + nY * mpFileHeader->nColumns ] * ( nBlackMax - 256 ) / 0x1ff;
644 :
645 0 : aBitmapColor = mpReadAcc->GetPixel( nY, nX );
646 0 : sal_uInt8 cR = (sal_uInt8) MinMax( aBitmapColor.GetRed() - nDAT, 0L, 255L );
647 0 : sal_uInt8 cG = (sal_uInt8) MinMax( aBitmapColor.GetGreen() - nDAT, 0L, 255L );
648 0 : sal_uInt8 cB = (sal_uInt8) MinMax( aBitmapColor.GetBlue() - nDAT, 0L, 255L );
649 0 : mpWriteAcc->SetPixel( nY, nX, BitmapColor( cR, cG, cB ) );
650 : }
651 0 : }
652 : }
653 : }
654 2 : break;
655 : }
656 :
657 2 : if ( mbTransparent )
658 : {
659 : // the psd is 24 or 8 bit grafix + alphachannel
660 :
661 0 : nY = nX = 0;
662 0 : while ( nY < mpFileHeader->nRows )
663 : {
664 0 : if ( mbCompression ) // else nRunCount = 0 -> so we use only single raw packets
665 0 : m_rPSD.ReadChar( nRunCount );
666 :
667 0 : if ( nRunCount & 0x80 ) // a run length packet
668 : {
669 0 : m_rPSD.ReadUChar( nDat );
670 0 : if ( nDat )
671 0 : nDat = 0;
672 : else
673 0 : nDat = 1;
674 0 : if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
675 0 : m_rPSD.ReadUChar( nDummy );
676 0 : for ( sal_uInt16 i = 0; i < ( -nRunCount + 1 ); i++ )
677 : {
678 0 : mpMaskWriteAcc->SetPixelIndex( nY, nX, nDat );
679 0 : if ( ++nX == mpFileHeader->nColumns )
680 : {
681 0 : nX = 0;
682 0 : nY++;
683 0 : if ( nY == mpFileHeader->nRows )
684 0 : break;
685 : }
686 : }
687 : }
688 : else // a raw packet
689 : {
690 0 : for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
691 : {
692 0 : m_rPSD.ReadUChar( nDat );
693 0 : if ( nDat )
694 0 : nDat = 0;
695 : else
696 0 : nDat = 1;
697 0 : if ( mpFileHeader->nDepth == 16 ) // 16 bit depth is to be skipped
698 0 : m_rPSD.ReadUChar( nDummy );
699 0 : mpMaskWriteAcc->SetPixelIndex( nY, nX, nDat );
700 0 : if ( ++nX == mpFileHeader->nColumns )
701 : {
702 0 : nX = 0;
703 0 : nY++;
704 0 : if ( nY == mpFileHeader->nRows )
705 0 : break;
706 : }
707 : }
708 : }
709 : }
710 : }
711 2 : return true;
712 : }
713 :
714 : //================== GraphicImport - the exported function ================
715 :
716 : // this needs to be kept in sync with
717 : // ImpFilterLibCacheEntry::GetImportFunction() from
718 : // vcl/source/filter/graphicfilter.cxx
719 : #if defined(DISABLE_DYNLOADING)
720 : #define GraphicImport ipdGraphicImport
721 : #endif
722 :
723 : extern "C" SAL_DLLPUBLIC_EXPORT bool SAL_CALL
724 3 : GraphicImport( SvStream & rStream, Graphic & rGraphic, FilterConfigItem* )
725 : {
726 3 : PSDReader aPSDReader(rStream);
727 :
728 3 : return aPSDReader.ReadPSD(rGraphic);
729 : }
730 :
731 :
732 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|