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