1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_filter.hxx"
26 
27 #include "rtl/alloc.h"
28 #include <vcl/graph.hxx>
29 #include <vcl/bmpacc.hxx>
30 #include <vcl/svapp.hxx>
31 #include <svtools/fltcall.hxx>
32 #include <svl/solar.hrc>
33 #include <svtools/FilterConfigItem.hxx>
34 
35 //============================ PCDReader ==================================
36 
37 // Diese Aufloesungen sind in einer PCD-Datei enthalten:
38 enum PCDResolution {
39 	PCDRES_BASE16,  //  192 x  128
40 	PCDRES_BASE4,   //  384 x  256
41 	PCDRES_BASE,    //  768 x  512
42 	// Die folgenden sind komprimiert und koennen
43 	// von uns NICHT gelesen werden:
44 	PCDRES_4BASE,   // 1536 x 1024
45 	PCDRES_16BASE   // 3072 x 3072
46 };
47 
48 class PCDReader {
49 
50 private:
51 
52 	sal_Bool bStatus;
53 
54 	sal_uLong				nLastPercent;
55 
56 	SvStream*			pPCD;
57 	BitmapWriteAccess*	mpAcc;
58 
59 	sal_uInt8				nOrientation;	// Ausrichtung des Bildes in der PCD-Datei:
60 										// 0 - Turmspitze zeigt nach oben
61 										// 1 - Turmspitze zeigt nach rechts
62 										// 2 - Turmspitze zeigt nach unten
63 										// 3 - Turmspitze zeigt nach links
64 
65 	PCDResolution		eResolution;	// Welche Aufloesung wir haben wollen
66 
67 	sal_uLong				nWidth;			// Breite des PCD-Bildes
68 	sal_uLong				nHeight;		// Hoehe des PCD-Bildes
69 	sal_uLong				nImagePos;		// Position des Bildes in der PCD-Datei
70 
71 	// Temporare BLue-Green-Red-Bitmap
72 	sal_uLong				nBMPWidth;
73 	sal_uLong				nBMPHeight;
74 
75 	void	MayCallback(sal_uLong nPercent);
76 
77 	void	CheckPCDImagePacFile();
78 		// Prueft, ob es eine Photo-CD-Datei mit 'Image Pac' ist.
79 
80 	void	ReadOrientation();
81 		// Liest die Ausrichtung und setzt nOrientation
82 
83 	void	ReadImage(sal_uLong nMinPercent, sal_uLong nMaxPercent);
84 
85 public:
86 
PCDReader()87 	PCDReader() {}
~PCDReader()88 	~PCDReader() {}
89 
90 	sal_Bool ReadPCD( SvStream & rPCD, Graphic & rGraphic, FilterConfigItem* pConfigItem );
91 };
92 
93 //=================== Methoden von PCDReader ==============================
94 
ReadPCD(SvStream & rPCD,Graphic & rGraphic,FilterConfigItem * pConfigItem)95 sal_Bool PCDReader::ReadPCD( SvStream & rPCD, Graphic & rGraphic, FilterConfigItem* pConfigItem )
96 {
97 	Bitmap		 aBmp;
98 
99 	bStatus      = sal_True;
100 	nLastPercent = 0;
101 	pPCD         = &rPCD;
102 
103 	MayCallback( 0 );
104 
105 	// Ist es eine PCD-Datei mit Bild ? ( setzt bStatus == sal_False, wenn nicht ):
106 	CheckPCDImagePacFile();
107 
108 	// Orientierung des Bildes einlesen:
109 	ReadOrientation();
110 
111 	// Welche Aufloesung wollen wir ?:
112 	eResolution = PCDRES_BASE;
113 	if ( pConfigItem )
114 	{
115 		sal_Int32 nResolution = pConfigItem->ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( "Resolution" ) ), 2 );
116 		if ( nResolution == 1 )
117 			eResolution = PCDRES_BASE4;
118 		else if ( nResolution == 0 )
119 			eResolution = PCDRES_BASE16;
120 	}
121 	// Groesse und Position (Position in PCD-Datei) des Bildes bestimmen:
122 	switch (eResolution)
123 	{
124 		case PCDRES_BASE16 :
125 			nWidth = 192;
126 			nHeight = 128;
127 			nImagePos = 8192;
128 			break;
129 
130 		case PCDRES_BASE4 :
131 			nWidth = 384;
132 			nHeight = 256;
133 			nImagePos = 47104;
134 			break;
135 
136 		case PCDRES_BASE :
137 			nWidth = 768;
138 			nHeight = 512;
139 			nImagePos = 196608;
140 			break;
141 
142 		default:
143 			bStatus = sal_False;
144 	}
145 	if ( bStatus )
146 	{
147 		if ( ( nOrientation & 0x01 ) == 0 )
148 		{
149 			nBMPWidth = nWidth;
150 			nBMPHeight = nHeight;
151 		}
152 		else
153 		{
154 			nBMPWidth = nHeight;
155 			nBMPHeight = nWidth;
156 		}
157 		aBmp = Bitmap( Size( nBMPWidth, nBMPHeight ), 24 );
158 		mpAcc = aBmp.AcquireWriteAccess();
159 		if ( !mpAcc )
160 			return sal_False;
161 
162 		ReadImage( 5 ,65 );
163 
164 		aBmp.ReleaseAccess( mpAcc ), mpAcc = NULL;
165 		rGraphic = aBmp;
166 	}
167 	return bStatus;
168 }
169 
170 // -------------------------------------------------------------------------------------------
171 
MayCallback(sal_uLong)172 void PCDReader::MayCallback(sal_uLong /*nPercent*/)
173 {
174 /*
175 	if ( nPercent >= nLastPercent + 3 )
176 	{
177 		nLastPercent=nPercent;
178 		if ( pCallback != NULL && nPercent <= 100 && bStatus == sal_True )
179 		{
180 			if ( ( (*pCallback)( pCallerData, (sal_uInt16)nPercent ) ) == sal_True )
181 				bStatus = sal_False;
182 		}
183 	}
184 */
185 }
186 
187 // -------------------------------------------------------------------------------------------
188 
CheckPCDImagePacFile()189 void PCDReader::CheckPCDImagePacFile()
190 {
191 	char Buf[ 8 ];
192 
193 	pPCD->Seek( 2048 );
194 	pPCD->Read( Buf, 7 );
195 	Buf[ 7 ] = 0;
196 	if ( ByteString( Buf ).CompareTo( "PCD_IPI" ) != COMPARE_EQUAL )
197 		bStatus = sal_False;
198 }
199 
200 // -------------------------------------------------------------------------------------------
201 
ReadOrientation()202 void PCDReader::ReadOrientation()
203 {
204 	if ( bStatus == sal_False )
205 		return;
206 	pPCD->Seek( 194635 );
207 	*pPCD >> nOrientation;
208 	nOrientation &= 0x03;
209 }
210 
211 // -------------------------------------------------------------------------------------------
212 
ReadImage(sal_uLong nMinPercent,sal_uLong nMaxPercent)213 void PCDReader::ReadImage(sal_uLong nMinPercent, sal_uLong nMaxPercent)
214 {
215 	sal_uLong  nx,ny,nW2,nH2,nYPair,ndy,nXPair;
216 	long   nL,nCb,nCr,nRed,nGreen,nBlue;
217 	sal_uInt8 * pt;
218 	sal_uInt8 * pL0; // Luminanz fuer jeden Pixel der 1. Zeile des aktuellen Zeilen-Paars
219 	sal_uInt8 * pL1; // Luminanz fuer jeden Pixel der 2. Zeile des aktuellen Zeilen-Paars
220 	sal_uInt8 * pCb; // Blau-Chrominanz fuer je 2x2 Pixel des aktuellen Zeilen-Paars
221 	sal_uInt8 * pCr; // Rot-Chrominanz fuer je 2x2 Pixel des aktuellen Zeilen-Paars
222 	sal_uInt8 * pL0N, * pL1N, * pCbN, * pCrN; // wie oben, nur fuer das naechste Zeilen-Paar
223 
224 	if ( bStatus == sal_False )
225 		return;
226 
227 	nW2=nWidth>>1;
228 	nH2=nHeight>>1;
229 
230 	pL0 =(sal_uInt8*)rtl_allocateMemory( nWidth );
231 	pL1 =(sal_uInt8*)rtl_allocateMemory( nWidth );
232 	pCb =(sal_uInt8*)rtl_allocateMemory( nW2+1 );
233 	pCr =(sal_uInt8*)rtl_allocateMemory( nW2+1 );
234 	pL0N=(sal_uInt8*)rtl_allocateMemory( nWidth );
235 	pL1N=(sal_uInt8*)rtl_allocateMemory( nWidth );
236 	pCbN=(sal_uInt8*)rtl_allocateMemory( nW2+1 );
237 	pCrN=(sal_uInt8*)rtl_allocateMemory( nW2+1 );
238 
239 	if ( pL0 == NULL || pL1 == NULL || pCb == NULL || pCr == NULL ||
240 		pL0N == NULL || pL1N == NULL || pCbN == NULL || pCrN == NULL)
241 	{
242 		rtl_freeMemory((void*)pL0 );
243 		rtl_freeMemory((void*)pL1 );
244 		rtl_freeMemory((void*)pCb );
245 		rtl_freeMemory((void*)pCr );
246 		rtl_freeMemory((void*)pL0N);
247 		rtl_freeMemory((void*)pL1N);
248 		rtl_freeMemory((void*)pCbN);
249 		rtl_freeMemory((void*)pCrN);
250 		bStatus = sal_False;
251 		return;
252 	}
253 
254 	pPCD->Seek( nImagePos );
255 
256 	// naechstes Zeilen-Paar := erstes Zeile-Paar:
257 	pPCD->Read( pL0N, nWidth );
258 	pPCD->Read( pL1N, nWidth );
259 	pPCD->Read( pCbN, nW2 );
260 	pPCD->Read( pCrN, nW2 );
261 	pCbN[ nW2 ] = pCbN[ nW2 - 1 ];
262 	pCrN[ nW2 ] = pCrN[ nW2 - 1 ];
263 
264 	for ( nYPair = 0; nYPair < nH2; nYPair++ )
265 	{
266 		// aktuelles Zeilen-Paar := naechstes Zeilen-Paar
267 		pt=pL0; pL0=pL0N; pL0N=pt;
268 		pt=pL1; pL1=pL1N; pL1N=pt;
269 		pt=pCb; pCb=pCbN; pCbN=pt;
270 		pt=pCr; pCr=pCrN; pCrN=pt;
271 
272 		// naechstes Zeilen-Paar holen:
273 		if ( nYPair < nH2 - 1 )
274 		{
275 			pPCD->Read( pL0N, nWidth );
276 			pPCD->Read( pL1N, nWidth );
277 			pPCD->Read( pCbN, nW2 );
278 			pPCD->Read( pCrN, nW2 );
279 			pCbN[nW2]=pCbN[ nW2 - 1 ];
280 			pCrN[nW2]=pCrN[ nW2 - 1 ];
281 		}
282 		else
283 		{
284 			for ( nXPair = 0; nXPair < nW2; nXPair++ )
285 			{
286 				pCbN[ nXPair ] = pCb[ nXPair ];
287 				pCrN[ nXPair ] = pCr[ nXPair ];
288 			}
289 		}
290 
291 		// Schleife uber die beiden Zeilen des Zeilen-Paars:
292 		for ( ndy = 0; ndy < 2; ndy++ )
293 		{
294 			ny = ( nYPair << 1 ) + ndy;
295 
296 			// Schleife ueber X:
297 			for ( nx = 0; nx < nWidth; nx++ )
298 			{
299 				// nL,nCb,nCr fuer den Pixel nx,ny holen/berechenen:
300 				nXPair = nx >> 1;
301 				if ( ndy == 0 )
302 				{
303 					nL = (long)pL0[ nx ];
304 					if (( nx & 1 ) == 0 )
305 					{
306 						nCb = (long)pCb[ nXPair ];
307 						nCr = (long)pCr[ nXPair ];
308 					}
309 					else
310 					{
311 						nCb = ( ( (long)pCb[ nXPair ] ) + ( (long)pCb[ nXPair + 1 ] ) ) >> 1;
312 						nCr = ( ( (long)pCr[ nXPair ] ) + ( (long)pCr[ nXPair + 1 ] ) ) >> 1;
313 					}
314 				}
315 				else {
316 					nL = pL1[ nx ];
317 					if ( ( nx & 1 ) == 0 )
318 					{
319 						nCb = ( ( (long)pCb[ nXPair ] ) + ( (long)pCbN[ nXPair ] ) ) >> 1;
320 						nCr = ( ( (long)pCr[ nXPair ] ) + ( (long)pCrN[ nXPair ] ) ) >> 1;
321 					}
322 					else
323 					{
324 						nCb = ( ( (long)pCb[ nXPair ] ) + ( (long)pCb[ nXPair + 1 ] ) +
325 							   ( (long)pCbN[ nXPair ] ) + ( (long)pCbN[ nXPair + 1 ] ) ) >> 2;
326 						nCr = ( ( (long)pCr[ nXPair ] ) + ( (long)pCr[ nXPair + 1] ) +
327 							   ( (long)pCrN[ nXPair ] ) + ( (long)pCrN[ nXPair + 1 ] ) ) >> 2;
328 					}
329 				}
330 				// Umwandlung von nL,nCb,nCr in nRed,nGreen,nBlue:
331 				nL *= 89024L;
332 				nCb -= 156;
333 				nCr -= 137;
334 				nRed = ( nL + nCr * 119374L + 0x8000 ) >> 16;
335 				if ( nRed < 0 )
336 					nRed = 0;
337 				if ( nRed > 255)
338 					nRed = 255;
339 				nGreen = ( nL - nCb * 28198L - nCr * 60761L + 0x8000 ) >> 16;
340 				if ( nGreen < 0 )
341 					nGreen = 0;
342 				if ( nGreen > 255 )
343 					nGreen = 255;
344 				nBlue = ( nL + nCb * 145352L + 0x8000 ) >> 16;
345 				if ( nBlue < 0 )
346 					nBlue = 0;
347 				if ( nBlue > 255 )
348 					nBlue = 255;
349 
350 				// Farbwert in pBMPMap eintragen:
351 				if ( nOrientation < 2 )
352 				{
353 					if ( nOrientation == 0 )
354 						mpAcc->SetPixel( ny, nx, BitmapColor( (sal_uInt8)nRed, (sal_uInt8)nGreen, (sal_uInt8)nBlue ) );
355 					else
356 						mpAcc->SetPixel( nWidth - 1 - nx, ny, BitmapColor( (sal_uInt8)nRed, (sal_uInt8)nGreen, (sal_uInt8)nBlue ) );
357 				}
358 				else
359 				{
360 					if ( nOrientation == 2 )
361 						mpAcc->SetPixel( nHeight - 1 - ny, ( nWidth - 1 - nx ), BitmapColor( (sal_uInt8)nRed, (sal_uInt8)nGreen, (sal_uInt8)nBlue ) );
362 					else
363 						mpAcc->SetPixel( nx, ( nHeight - 1 - ny ), BitmapColor( (sal_uInt8)nRed, (sal_uInt8)nGreen, (sal_uInt8)nBlue ) );
364 				}
365 			}
366 		}
367 
368 		if ( pPCD->GetError() )
369 			bStatus = sal_False;
370 		MayCallback( nMinPercent + ( nMaxPercent - nMinPercent ) * nYPair / nH2 );
371 		if ( bStatus == sal_False )
372 			break;
373 	}
374 	rtl_freeMemory((void*)pL0 );
375 	rtl_freeMemory((void*)pL1 );
376 	rtl_freeMemory((void*)pCb );
377 	rtl_freeMemory((void*)pCr );
378 	rtl_freeMemory((void*)pL0N);
379 	rtl_freeMemory((void*)pL1N);
380 	rtl_freeMemory((void*)pCbN);
381 	rtl_freeMemory((void*)pCrN);
382 }
383 
384 //================== GraphicImport - die exportierte Funktion ================
385 
GraphicImport(SvStream & rStream,Graphic & rGraphic,FilterConfigItem * pConfigItem,sal_Bool)386 extern "C" sal_Bool __LOADONCALLAPI GraphicImport(SvStream & rStream, Graphic & rGraphic, FilterConfigItem* pConfigItem, sal_Bool )
387 {
388 	PCDReader aPCDReader;
389 	return aPCDReader.ReadPCD( rStream, rGraphic, pConfigItem );
390 }
391 
392