1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ipsd.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_goodies.hxx"
34 #include <vcl/graph.hxx>
35 #include <vcl/bmpacc.hxx>
36 #include <svtools/fltcall.hxx>
38 //============================ PSDReader ==================================
41 #define PSD_GRAYSCALE 1
45 #define PSD_MULTICHANNEL 7
67 SvStream
* mpPSD
; // Die einzulesende PSD-Datei
68 PSDFileHeader
* mpFileHeader
;
70 sal_uInt32 mnXResFixed
;
71 sal_uInt32 mnYResFixed
;
74 sal_Bool mbTransparent
;
78 BitmapReadAccess
* mpReadAcc
;
79 BitmapWriteAccess
* mpWriteAcc
;
80 BitmapWriteAccess
* mpMaskWriteAcc
;
81 USHORT mnDestBitDepth
;
82 BOOL mbCompression
; // RLE decoding
86 BOOL
ImplReadHeader();
91 BOOL
ReadPSD( SvStream
& rPSD
, Graphic
& rGraphic
);
94 //=================== Methoden von PSDReader ==============================
96 PSDReader::PSDReader() :
97 mpFileHeader ( NULL
),
101 mbTransparent ( FALSE
),
104 mpMaskWriteAcc ( NULL
),
109 PSDReader::~PSDReader()
115 // ------------------------------------------------------------------------
117 BOOL
PSDReader::ReadPSD( SvStream
& rPSD
, Graphic
& rGraphic
)
119 if ( rPSD
.GetError() )
123 mpPSD
->SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN
);
127 if ( ImplReadHeader() == FALSE
)
130 Size
aBitmapSize( mpFileHeader
->nColumns
, mpFileHeader
->nRows
);
131 maBmp
= Bitmap( aBitmapSize
, mnDestBitDepth
);
132 if ( ( mpWriteAcc
= maBmp
.AcquireWriteAccess() ) == NULL
)
134 if ( ( mpReadAcc
= maBmp
.AcquireReadAccess() ) == NULL
)
136 if ( mbTransparent
&& mbStatus
)
138 maMaskBmp
= Bitmap( aBitmapSize
, 1 );
139 if ( ( mpMaskWriteAcc
= maMaskBmp
.AcquireWriteAccess() ) == NULL
)
142 if ( mpPalette
&& mbStatus
)
144 mpWriteAcc
->SetPaletteEntryCount( 256 );
145 for ( USHORT i
= 0; i
< 256; i
++ )
147 mpWriteAcc
->SetPaletteColor( i
, Color( mpPalette
[ i
], mpPalette
[ i
+ 256 ], mpPalette
[ i
+ 512 ] ) );
150 // Bitmap-Daten einlesen
151 if ( mbStatus
&& ImplReadBody() )
154 rGraphic
= Graphic( BitmapEx( maBmp
, maMaskBmp
) );
158 if ( mnXResFixed
&& mnYResFixed
)
161 Fraction
aFractX( 1, mnXResFixed
>> 16 );
162 Fraction
aFractY( 1, mnYResFixed
>> 16 );
163 MapMode
aMapMode( MAP_INCH
, aEmptyPoint
, aFractX
, aFractY
);
164 Size aPrefSize
= OutputDevice::LogicToLogic( aBitmapSize
, aMapMode
, MAP_100TH_MM
);
165 rGraphic
.SetPrefSize( aPrefSize
);
166 rGraphic
.SetPrefMapMode( MapMode( MAP_100TH_MM
) );
172 maBmp
.ReleaseAccess( mpWriteAcc
);
174 maBmp
.ReleaseAccess( mpReadAcc
);
175 if ( mpMaskWriteAcc
)
176 maMaskBmp
.ReleaseAccess( mpMaskWriteAcc
);
180 // ------------------------------------------------------------------------
182 BOOL
PSDReader::ImplReadHeader()
185 UINT32 nColorLength
, nResourceLength
, nLayerMaskLength
;
187 mpFileHeader
= new PSDFileHeader
;
192 *mpPSD
>> mpFileHeader
->nSignature
>> mpFileHeader
->nVersion
>> mpFileHeader
->nPad1
>>
193 mpFileHeader
->nPad2
>> mpFileHeader
->nChannels
>> mpFileHeader
->nRows
>>
194 mpFileHeader
->nColumns
>> mpFileHeader
->nDepth
>> mpFileHeader
->nMode
;
196 if ( ( mpFileHeader
->nSignature
!= 0x38425053 ) || ( mpFileHeader
->nVersion
!= 1 ) )
199 if ( mpFileHeader
->nRows
== 0 || mpFileHeader
->nColumns
== 0 )
202 if ( ( mpFileHeader
->nRows
> 30000 ) || ( mpFileHeader
->nColumns
> 30000 ) )
205 UINT16 nDepth
= mpFileHeader
->nDepth
;
206 if (!( ( nDepth
== 1 ) || ( nDepth
== 8 ) || ( nDepth
== 16 ) ) )
209 mnDestBitDepth
= ( nDepth
== 16 ) ? 8 : nDepth
;
211 *mpPSD
>> nColorLength
;
212 if ( mpFileHeader
->nMode
== PSD_CMYK
)
214 switch ( mpFileHeader
->nChannels
)
217 mbTransparent
= TRUE
;
225 else switch ( mpFileHeader
->nChannels
)
228 mbTransparent
= TRUE
;
232 mbTransparent
= TRUE
;
240 switch ( mpFileHeader
->nMode
)
244 if ( nColorLength
|| ( nDepth
!= 1 ) )
251 if ( nColorLength
!= 768 ) // we need the color map
253 mpPalette
= new BYTE
[ 768 ];
254 if ( mpPalette
== NULL
)
256 mpPSD
->Read( mpPalette
, 768 );
260 case PSD_DUOTONE
: // we'll handle the doutone color like a normal grayscale picture
261 mpPSD
->SeekRel( nColorLength
);
267 mpPalette
= new BYTE
[ 768 ];
268 if ( mpPalette
== NULL
)
270 for ( USHORT i
= 0; i
< 256; i
++ )
272 mpPalette
[ i
] = mpPalette
[ i
+ 256 ] = mpPalette
[ i
+ 512 ] = (BYTE
)i
;
279 case PSD_MULTICHANNEL
:
282 if ( nColorLength
) // color table is not supported by the other graphic modes
290 *mpPSD
>> nResourceLength
;
291 sal_uInt32 nLayerPos
= mpPSD
->Tell() + nResourceLength
;
293 // this is a loop over the resource entries to get the resolution info
294 while( mpPSD
->Tell() < nLayerPos
)
297 sal_uInt32 nType
, nPStringLen
, nResEntryLen
;
298 sal_uInt16 nUniqueID
;
300 *mpPSD
>> nType
>> nUniqueID
>> n8
;
302 if ( nType
!= 0x3842494d )
304 if ( ! ( nPStringLen
& 1 ) )
306 mpPSD
->SeekRel( nPStringLen
); // skipping the pstring
307 *mpPSD
>> nResEntryLen
;
308 if ( nResEntryLen
& 1 )
309 nResEntryLen
++; // the resource entries are padded
310 sal_uInt32 nCurrentPos
= mpPSD
->Tell();
311 if ( ( nResEntryLen
+ nCurrentPos
) > nLayerPos
) // check if size
312 break; // is possible
315 case 0x3ed : // UID for the resolution info
319 *mpPSD
>> mnXResFixed
>> nUnit
>> nUnit
320 >> mnYResFixed
>> nUnit
>> nUnit
;
324 mpPSD
->Seek( nCurrentPos
+ nResEntryLen
); // set the stream to the next
326 mpPSD
->Seek( nLayerPos
);
327 *mpPSD
>> nLayerMaskLength
;
328 mpPSD
->SeekRel( nLayerMaskLength
);
330 *mpPSD
>> nCompression
;
331 if ( nCompression
== 0 )
333 mbCompression
= FALSE
;
335 else if ( nCompression
== 1 )
337 mpPSD
->SeekRel( ( mpFileHeader
->nRows
* mpFileHeader
->nChannels
) << 1 );
338 mbCompression
= TRUE
;
346 // ------------------------------------------------------------------------
348 BOOL
PSDReader::ImplReadBody()
352 signed char nBitCount
= -1;
353 BYTE nDat
= 0, nDummy
, nRed
, nGreen
, nBlue
;
354 BitmapColor aBitmapColor
;
357 switch ( mnDestBitDepth
)
361 while ( nY
< mpFileHeader
->nRows
)
363 if ( nBitCount
== -1 )
365 if ( mbCompression
) // else nRunCount = 0 -> so we use only single raw packets
368 if ( nRunCount
& 0x80 ) // a run length packet
370 if ( nBitCount
== -1 ) // bits left in nDat ?
376 for ( USHORT i
= 0; i
< ( -nRunCount
+ 1 ); i
++ )
378 mpWriteAcc
->SetPixel( nY
, nX
, (BYTE
)nDat
>> nBitCount
-- );
379 if ( ++nX
== mpFileHeader
->nColumns
)
384 if ( nY
== mpFileHeader
->nRows
)
391 for ( USHORT i
= 0; i
< ( ( nRunCount
& 0x7f ) + 1 ); i
++ )
393 if ( nBitCount
== -1 ) // bits left in nDat ?
399 mpWriteAcc
->SetPixel( nY
, nX
, (BYTE
)nDat
>> nBitCount
-- );
400 if ( ++nX
== mpFileHeader
->nColumns
)
405 if ( nY
== mpFileHeader
->nRows
)
416 while ( nY
< mpFileHeader
->nRows
)
418 if ( mbCompression
) // else nRunCount = 0 -> so we use only single raw packets
421 if ( nRunCount
& 0x80 ) // a run length packet
424 if ( mpFileHeader
->nDepth
== 16 ) // 16 bit depth is to be skipped
426 for ( USHORT i
= 0; i
< ( -nRunCount
+ 1 ); i
++ )
428 mpWriteAcc
->SetPixel( nY
, nX
, (BYTE
)nDat
);
429 if ( ++nX
== mpFileHeader
->nColumns
)
433 if ( nY
== mpFileHeader
->nRows
)
440 for ( USHORT i
= 0; i
< ( ( nRunCount
& 0x7f ) + 1 ); i
++ )
443 if ( mpFileHeader
->nDepth
== 16 ) // 16 bit depth is to be skipped
445 mpWriteAcc
->SetPixel( nY
, nX
, (BYTE
)nDat
);
446 if ( ++nX
== mpFileHeader
->nColumns
)
450 if ( nY
== mpFileHeader
->nRows
)
462 // the psd format is in plain order (RRRR GGGG BBBB) so we have to set each pixel three times
463 // maybe the format is CCCC MMMM YYYY KKKK
465 while ( nY
< mpFileHeader
->nRows
)
467 if ( mbCompression
) // else nRunCount = 0 -> so we use only single raw packets
470 if ( nRunCount
& 0x80 ) // a run length packet
473 if ( mpFileHeader
->nDepth
== 16 ) // 16 bit depth is to be skipped
475 for ( USHORT i
= 0; i
< ( -nRunCount
+ 1 ); i
++ )
477 mpWriteAcc
->SetPixel( nY
, nX
, BitmapColor( nRed
, (BYTE
)0, (BYTE
)0 ) );
478 if ( ++nX
== mpFileHeader
->nColumns
)
482 if ( nY
== mpFileHeader
->nRows
)
489 for ( USHORT i
= 0; i
< ( ( nRunCount
& 0x7f ) + 1 ); i
++ )
492 if ( mpFileHeader
->nDepth
== 16 ) // 16 bit depth is to be skipped
494 mpWriteAcc
->SetPixel( nY
, nX
, BitmapColor( nRed
, (BYTE
)0, (BYTE
)0 ) );
495 if ( ++nX
== mpFileHeader
->nColumns
)
499 if ( nY
== mpFileHeader
->nRows
)
506 while ( nY
< mpFileHeader
->nRows
)
510 if ( nRunCount
& 0x80 ) // a run length packet
513 if ( mpFileHeader
->nDepth
== 16 ) // 16 bit depth is to be skipped
515 for ( USHORT i
= 0; i
< ( -nRunCount
+ 1 ); i
++ )
517 aBitmapColor
= mpReadAcc
->GetPixel( nY
, nX
);
518 mpWriteAcc
->SetPixel( nY
, nX
, BitmapColor( aBitmapColor
.GetRed(), nGreen
, aBitmapColor
.GetBlue() ) );
519 if ( ++nX
== mpFileHeader
->nColumns
)
523 if ( nY
== mpFileHeader
->nRows
)
530 for ( USHORT i
= 0; i
< ( ( nRunCount
& 0x7f ) + 1 ); i
++ )
533 if ( mpFileHeader
->nDepth
== 16 ) // 16 bit depth is to be skipped
535 aBitmapColor
= mpReadAcc
->GetPixel( nY
, nX
);
536 mpWriteAcc
->SetPixel( nY
, nX
, BitmapColor( aBitmapColor
.GetRed(), nGreen
, aBitmapColor
.GetBlue() ) );
537 if ( ++nX
== mpFileHeader
->nColumns
)
541 if ( nY
== mpFileHeader
->nRows
)
548 while ( nY
< mpFileHeader
->nRows
)
552 if ( nRunCount
& 0x80 ) // a run length packet
555 if ( mpFileHeader
->nDepth
== 16 ) // 16 bit depth is to be skipped
557 for ( USHORT i
= 0; i
< ( -nRunCount
+ 1 ); i
++ )
559 aBitmapColor
= mpReadAcc
->GetPixel( nY
, nX
);
560 mpWriteAcc
->SetPixel( nY
, nX
, BitmapColor( aBitmapColor
.GetRed(), aBitmapColor
.GetGreen(), nBlue
) );
561 if ( ++nX
== mpFileHeader
->nColumns
)
565 if ( nY
== mpFileHeader
->nRows
)
572 for ( USHORT i
= 0; i
< ( ( nRunCount
& 0x7f ) + 1 ); i
++ )
575 if ( mpFileHeader
->nDepth
== 16 ) // 16 bit depth is to be skipped
577 aBitmapColor
= mpReadAcc
->GetPixel( nY
, nX
);
578 mpWriteAcc
->SetPixel( nY
, nX
, BitmapColor( aBitmapColor
.GetRed(), aBitmapColor
.GetGreen(), nBlue
) );
579 if ( ++nX
== mpFileHeader
->nColumns
)
583 if ( nY
== mpFileHeader
->nRows
)
589 if ( mpFileHeader
->nMode
== PSD_CMYK
)
591 UINT32 nBlack
, nBlackMax
= 0;
592 BYTE
* pBlack
= new BYTE
[ mpFileHeader
->nRows
* mpFileHeader
->nColumns
];
594 while ( nY
< mpFileHeader
->nRows
)
596 if ( mbCompression
) // else nRunCount = 0 -> so we use only single raw packets
599 if ( nRunCount
& 0x80 ) // a run length packet
603 if ( mpFileHeader
->nDepth
== 16 ) // 16 bit depth is to be skipped
606 for ( USHORT i
= 0; i
< ( -nRunCount
+ 1 ); i
++ )
608 nBlack
= (BYTE
)mpReadAcc
->GetPixel( nY
, nX
).GetRed() + nDat
;
609 if ( nBlack
> nBlackMax
)
611 nBlack
= (BYTE
)mpReadAcc
->GetPixel( nY
, nX
).GetGreen() + nDat
;
612 if ( nBlack
> nBlackMax
)
614 nBlack
= (BYTE
)mpReadAcc
->GetPixel( nY
, nX
).GetBlue() + nDat
;
615 if ( nBlack
> nBlackMax
)
617 pBlack
[ nX
+ nY
* mpFileHeader
->nColumns
] = nDat
^ 0xff;
618 if ( ++nX
== mpFileHeader
->nColumns
)
622 if ( nY
== mpFileHeader
->nRows
)
629 for ( USHORT i
= 0; i
< ( ( nRunCount
& 0x7f ) + 1 ); i
++ )
633 if ( mpFileHeader
->nDepth
== 16 ) // 16 bit depth is to be skipped
635 nBlack
= (BYTE
)mpReadAcc
->GetPixel( nY
, nX
).GetRed() + nDat
;
636 if ( nBlack
> nBlackMax
)
638 nBlack
= (BYTE
)mpReadAcc
->GetPixel( nY
, nX
).GetGreen() + nDat
;
639 if ( nBlack
> nBlackMax
)
641 nBlack
= (BYTE
)mpReadAcc
->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 ( nY
= 0; nY
< mpFileHeader
->nRows
; nY
++ )
658 for ( nX
= 0; nX
< mpFileHeader
->nColumns
; nX
++ )
660 INT32 nDAT
= pBlack
[ nX
+ nY
* mpFileHeader
->nColumns
] * ( nBlackMax
- 256 ) / 0x1ff;
662 aBitmapColor
= mpReadAcc
->GetPixel( nY
, nX
);
663 BYTE cR
= (BYTE
) MinMax( aBitmapColor
.GetRed() - nDAT
, 0L, 255L );
664 BYTE cG
= (BYTE
) MinMax( aBitmapColor
.GetGreen() - nDAT
, 0L, 255L );
665 BYTE cB
= (BYTE
) MinMax( aBitmapColor
.GetBlue() - nDAT
, 0L, 255L );
666 mpWriteAcc
->SetPixel( nY
, nX
, BitmapColor( cR
, cG
, cB
) );
677 // the psd is 24 or 8 bit grafix + alphachannel
680 while ( nY
< mpFileHeader
->nRows
)
682 if ( mbCompression
) // else nRunCount = 0 -> so we use only single raw packets
685 if ( nRunCount
& 0x80 ) // a run length packet
692 if ( mpFileHeader
->nDepth
== 16 ) // 16 bit depth is to be skipped
694 for ( USHORT i
= 0; i
< ( -nRunCount
+ 1 ); i
++ )
696 mpMaskWriteAcc
->SetPixel( nY
, nX
, (BYTE
)nDat
);
697 if ( ++nX
== mpFileHeader
->nColumns
)
701 if ( nY
== mpFileHeader
->nRows
)
708 for ( USHORT i
= 0; i
< ( ( nRunCount
& 0x7f ) + 1 ); i
++ )
715 if ( mpFileHeader
->nDepth
== 16 ) // 16 bit depth is to be skipped
717 mpMaskWriteAcc
->SetPixel( nY
, nX
, (BYTE
)nDat
);
718 if ( ++nX
== mpFileHeader
->nColumns
)
722 if ( nY
== mpFileHeader
->nRows
)
732 //================== GraphicImport - die exportierte Funktion ================
734 extern "C" BOOL __LOADONCALLAPI
GraphicImport(SvStream
& rStream
, Graphic
& rGraphic
, FilterConfigItem
*, BOOL
)
736 PSDReader aPSDReader
;
738 return aPSDReader
.ReadPSD( rStream
, rGraphic
);
741 //================== ein bischen Muell fuer Windows ==========================
747 static HINSTANCE hDLLInst
= 0; // HANDLE der DLL
749 extern "C" int CALLBACK
LibMain( HINSTANCE hDLL
, WORD
, WORD nHeap
, LPSTR
)
761 extern "C" int CALLBACK
WEP( int )