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 <stdio.h>
22 :
23 : #include <tools/solar.h>
24 : #include <vcl/svapp.hxx>
25 : #include <vcl/bitmap.hxx>
26 : #include <vcl/bitmapex.hxx>
27 : #include <vcl/animate.hxx>
28 : #include <vcl/gdimtf.hxx>
29 : #include <vcl/graph.h>
30 : #include <vcl/window.hxx>
31 : #include <vcl/graph.hxx>
32 : #include <vcl/metaact.hxx>
33 : #include <vcl/virdev.hxx>
34 : #include <vcl/cvtgrf.hxx>
35 : #include <vcl/bmpacc.hxx>
36 : #include <unotools/tempfile.hxx>
37 : #include <osl/process.h>
38 : #include <osl/file.hxx>
39 : #include <boost/scoped_array.hpp>
40 :
41 : class FilterConfigItem;
42 :
43 : /*************************************************************************
44 : |*
45 : |* ImpSearchEntry()
46 : |*
47 : |* Description Checks if there is a string(pDest) of length nSize
48 : |* inside the memory area pSource which is nComp bytes long.
49 : |* Check is NON-CASE-SENSITIVE. The return value is the
50 : |* address where the string is found or NULL
51 : |*
52 : *************************************************************************/
53 :
54 0 : static sal_uInt8* ImplSearchEntry( sal_uInt8* pSource, sal_uInt8* pDest, sal_uLong nComp, sal_uLong nSize )
55 : {
56 0 : while ( nComp-- >= nSize )
57 : {
58 : sal_uLong i;
59 0 : for ( i = 0; i < nSize; i++ )
60 : {
61 0 : if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
62 0 : break;
63 : }
64 0 : if ( i == nSize )
65 0 : return pSource;
66 0 : pSource++;
67 : }
68 0 : return NULL;
69 : }
70 :
71 :
72 : // SecurityCount is the buffersize of the buffer in which we will parse for a number
73 0 : static long ImplGetNumber( sal_uInt8 **pBuf, int& nSecurityCount )
74 : {
75 0 : sal_Bool bValid = sal_True;
76 0 : sal_Bool bNegative = sal_False;
77 0 : long nRetValue = 0;
78 0 : while ( ( --nSecurityCount ) && ( ( **pBuf == ' ' ) || ( **pBuf == 0x9 ) ) )
79 0 : (*pBuf)++;
80 0 : sal_uInt8 nByte = **pBuf;
81 0 : while ( nSecurityCount && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
82 : {
83 0 : switch ( nByte )
84 : {
85 : case '.' :
86 : // we'll only use the integer format
87 0 : bValid = sal_False;
88 0 : break;
89 : case '-' :
90 0 : bNegative = sal_True;
91 0 : break;
92 : default :
93 0 : if ( ( nByte < '0' ) || ( nByte > '9' ) )
94 0 : nSecurityCount = 1; // error parsing the bounding box values
95 0 : else if ( bValid )
96 : {
97 0 : nRetValue *= 10;
98 0 : nRetValue += nByte - '0';
99 : }
100 0 : break;
101 : }
102 0 : nSecurityCount--;
103 0 : nByte = *(++(*pBuf));
104 : }
105 0 : if ( bNegative )
106 0 : nRetValue = -nRetValue;
107 0 : return nRetValue;
108 : }
109 :
110 :
111 :
112 0 : static int ImplGetLen( sal_uInt8* pBuf, int nMax )
113 : {
114 0 : int nLen = 0;
115 0 : while( nLen != nMax )
116 : {
117 0 : sal_uInt8 nDat = *pBuf++;
118 0 : if ( nDat == 0x0a || nDat == 0x25 )
119 : break;
120 0 : nLen++;
121 : }
122 0 : return nLen;
123 : }
124 :
125 0 : static void MakeAsMeta(Graphic &rGraphic)
126 : {
127 0 : VirtualDevice aVDev;
128 0 : GDIMetaFile aMtf;
129 0 : Bitmap aBmp( rGraphic.GetBitmap() );
130 0 : Size aSize = aBmp.GetPrefSize();
131 :
132 0 : if( !aSize.Width() || !aSize.Height() )
133 : aSize = Application::GetDefaultDevice()->PixelToLogic(
134 0 : aBmp.GetSizePixel(), MAP_100TH_MM );
135 : else
136 0 : aSize = Application::GetDefaultDevice()->LogicToLogic( aSize,
137 0 : aBmp.GetPrefMapMode(), MAP_100TH_MM );
138 :
139 0 : aVDev.EnableOutput( false );
140 0 : aMtf.Record( &aVDev );
141 0 : aVDev.DrawBitmap( Point(), aSize, rGraphic.GetBitmap() );
142 0 : aMtf.Stop();
143 0 : aMtf.WindStart();
144 0 : aMtf.SetPrefMapMode( MAP_100TH_MM );
145 0 : aMtf.SetPrefSize( aSize );
146 0 : rGraphic = aMtf;
147 0 : }
148 :
149 0 : static oslProcessError runProcessWithPathSearch(const OUString &rProgName,
150 : rtl_uString* pArgs[], sal_uInt32 nArgs, oslProcess *pProcess,
151 : oslFileHandle *pIn, oslFileHandle *pOut, oslFileHandle *pErr)
152 : {
153 : oslProcessError result;
154 0 : oslSecurity pSecurity = osl_getCurrentSecurity();
155 : #ifdef WNT
156 : /*
157 : * ooo#72096
158 : * On Window the underlying SearchPath searches in order of...
159 : * The directory from which the application loaded.
160 : * The current directory.
161 : * The Windows system directory.
162 : * The Windows directory.
163 : * The directories that are listed in the PATH environment variable.
164 : *
165 : * Because one of our programs is called "convert" and there is a convert
166 : * in the windows system directory, we want to explicitly search the PATH
167 : * to avoid picking up on that one if ImageMagick's convert preceeds it in
168 : * PATH.
169 : *
170 : */
171 : OUString url;
172 : OUString path(reinterpret_cast<const sal_Unicode*>(_wgetenv(L"PATH")));
173 :
174 : oslFileError err = osl_searchFileURL(rProgName.pData, path.pData, &url.pData);
175 : if (err != osl_File_E_None)
176 : return osl_Process_E_NotFound;
177 :
178 : result = osl_executeProcess_WithRedirectedIO(url.pData,
179 : pArgs, nArgs, osl_Process_HIDDEN,
180 : pSecurity, 0, 0, 0, pProcess, pIn, pOut, pErr);
181 : #else
182 : result = osl_executeProcess_WithRedirectedIO(rProgName.pData,
183 : pArgs, nArgs, osl_Process_SEARCHPATH | osl_Process_HIDDEN,
184 0 : pSecurity, 0, 0, 0, pProcess, pIn, pOut, pErr);
185 : #endif
186 0 : osl_freeSecurityHandle( pSecurity );
187 0 : return result;
188 : }
189 :
190 : #if defined(WNT)
191 : # define EXESUFFIX ".exe"
192 : #else
193 : # define EXESUFFIX ""
194 : #endif
195 :
196 0 : static bool RenderAsEMF(const sal_uInt8* pBuf, sal_uInt32 nBytesRead, Graphic &rGraphic)
197 : {
198 0 : utl::TempFile aTemp;
199 0 : aTemp.EnableKillingFile();
200 0 : OUString fileName("pstoedit" EXESUFFIX);
201 0 : OUString arg1("-f");
202 0 : OUString arg2("emf:-OO");
203 0 : OUString arg3("-");
204 0 : OUString output;
205 0 : osl::FileBase::getSystemPathFromFileURL(aTemp.GetURL(), output);
206 : rtl_uString *args[] =
207 : {
208 : arg1.pData, arg2.pData, arg3.pData, output.pData
209 0 : };
210 : oslProcess aProcess;
211 0 : oslFileHandle pIn = NULL;
212 0 : oslFileHandle pOut = NULL;
213 0 : oslFileHandle pErr = NULL;
214 : oslProcessError eErr = runProcessWithPathSearch(fileName,
215 0 : args, sizeof(args)/sizeof(rtl_uString *),
216 0 : &aProcess, &pIn, &pOut, &pErr);
217 :
218 0 : if (eErr!=osl_Process_E_None)
219 0 : return false;
220 :
221 0 : bool bRet = false;
222 : sal_uInt64 nCount;
223 0 : osl_writeFile(pIn, pBuf, nBytesRead, &nCount);
224 0 : if (pIn) osl_closeFile(pIn);
225 0 : bool bEMFSupported=true;
226 0 : if (pOut)
227 : {
228 0 : rtl::ByteSequence seq;
229 0 : if (osl_File_E_None == osl_readLine(pOut, (sal_Sequence **)&seq))
230 : {
231 0 : OString line( (const sal_Char *) seq.getConstArray(), seq.getLength() );
232 0 : if (line.startsWith("Unsupported output format"))
233 0 : bEMFSupported=false;
234 : }
235 0 : osl_closeFile(pOut);
236 : }
237 0 : if (pErr) osl_closeFile(pErr);
238 0 : if (nCount == nBytesRead && bEMFSupported)
239 : {
240 0 : SvFileStream aFile(output, STREAM_READ);
241 0 : if (GraphicConverter::Import(aFile, rGraphic, CVT_EMF) == ERRCODE_NONE)
242 0 : bRet = true;
243 : }
244 0 : osl_joinProcess(aProcess);
245 0 : osl_freeProcessHandle(aProcess);
246 0 : return bRet;
247 : }
248 :
249 0 : static bool RenderAsBMPThroughHelper(const sal_uInt8* pBuf, sal_uInt32 nBytesRead,
250 : Graphic &rGraphic, OUString &rProgName, rtl_uString *pArgs[], size_t nArgs)
251 : {
252 : oslProcess aProcess;
253 0 : oslFileHandle pIn = NULL;
254 0 : oslFileHandle pOut = NULL;
255 0 : oslFileHandle pErr = NULL;
256 : oslProcessError eErr = runProcessWithPathSearch(rProgName,
257 : pArgs, nArgs,
258 0 : &aProcess, &pIn, &pOut, &pErr);
259 0 : if (eErr!=osl_Process_E_None)
260 0 : return false;
261 :
262 0 : bool bRet = false;
263 : sal_uInt64 nCount;
264 0 : osl_writeFile(pIn, pBuf, nBytesRead, &nCount);
265 0 : if (pIn) osl_closeFile(pIn);
266 0 : if (nCount == nBytesRead)
267 : {
268 0 : SvMemoryStream aMemStm;
269 : sal_uInt8 aBuf[32000];
270 0 : oslFileError eFileErr = osl_readFile(pOut, aBuf, 32000, &nCount);
271 0 : while (eFileErr == osl_File_E_None && nCount)
272 : {
273 0 : aMemStm.Write(aBuf, sal::static_int_cast< sal_Size >(nCount));
274 0 : eFileErr = osl_readFile(pOut, aBuf, 32000, &nCount);
275 : }
276 :
277 0 : aMemStm.Seek(0);
278 0 : if (
279 0 : aMemStm.GetEndOfData() &&
280 0 : GraphicConverter::Import(aMemStm, rGraphic, CVT_BMP) == ERRCODE_NONE
281 : )
282 : {
283 0 : MakeAsMeta(rGraphic);
284 0 : bRet = true;
285 0 : }
286 : }
287 0 : if (pOut) osl_closeFile(pOut);
288 0 : if (pErr) osl_closeFile(pErr);
289 0 : osl_joinProcess(aProcess);
290 0 : osl_freeProcessHandle(aProcess);
291 0 : return bRet;
292 : }
293 :
294 0 : static bool RenderAsBMPThroughConvert(const sal_uInt8* pBuf, sal_uInt32 nBytesRead,
295 : Graphic &rGraphic)
296 : {
297 0 : OUString fileName("convert" EXESUFFIX);
298 : // density in pixel/inch
299 0 : OUString arg1("-density");
300 : // since the preview is also used for PDF-Export & printing on non-PS-printers,
301 : // use some better quality - 300x300 should allow some resizing as well
302 0 : OUString arg2("300x300");
303 : // read eps from STDIN
304 0 : OUString arg3("eps:-");
305 : // write bmp to STDOUT
306 0 : OUString arg4("bmp:-");
307 : rtl_uString *args[] =
308 : {
309 : arg1.pData, arg2.pData, arg3.pData, arg4.pData
310 0 : };
311 : return RenderAsBMPThroughHelper(pBuf, nBytesRead, rGraphic, fileName, args,
312 0 : sizeof(args)/sizeof(rtl_uString *));
313 : }
314 :
315 0 : static bool RenderAsBMPThroughGS(const sal_uInt8* pBuf, sal_uInt32 nBytesRead,
316 : Graphic &rGraphic)
317 : {
318 : #ifdef WNT
319 : OUString fileName("gswin32c" EXESUFFIX);
320 : #else
321 0 : OUString fileName("gs" EXESUFFIX);
322 : #endif
323 0 : OUString arg1("-q");
324 0 : OUString arg2("-dBATCH");
325 0 : OUString arg3("-dNOPAUSE");
326 0 : OUString arg4("-dPARANOIDSAFER");
327 0 : OUString arg5("-dEPSCrop");
328 0 : OUString arg6("-dTextAlphaBits=4");
329 0 : OUString arg7("-dGraphicsAlphaBits=4");
330 0 : OUString arg8("-r300x300");
331 0 : OUString arg9("-sDEVICE=bmp256");
332 0 : OUString arg10("-sOutputFile=-");
333 0 : OUString arg11("-");
334 : rtl_uString *args[] =
335 : {
336 : arg1.pData, arg2.pData, arg3.pData, arg4.pData, arg5.pData,
337 : arg6.pData, arg7.pData, arg8.pData, arg9.pData, arg10.pData,
338 : arg11.pData
339 0 : };
340 : return RenderAsBMPThroughHelper(pBuf, nBytesRead, rGraphic, fileName, args,
341 0 : sizeof(args)/sizeof(rtl_uString *));
342 : }
343 :
344 0 : static bool RenderAsBMP(const sal_uInt8* pBuf, sal_uInt32 nBytesRead, Graphic &rGraphic)
345 : {
346 0 : if (RenderAsBMPThroughGS(pBuf, nBytesRead, rGraphic))
347 0 : return true;
348 : else
349 0 : return RenderAsBMPThroughConvert(pBuf, nBytesRead, rGraphic);
350 : }
351 :
352 : // this method adds a replacement action containing the original wmf or tiff replacement,
353 : // so the original eps can be written when storing to ODF.
354 0 : void CreateMtfReplacementAction( GDIMetaFile& rMtf, SvStream& rStrm, sal_uInt32 nOrigPos, sal_uInt32 nPSSize,
355 : sal_uInt32 nPosWMF, sal_uInt32 nSizeWMF, sal_uInt32 nPosTIFF, sal_uInt32 nSizeTIFF )
356 : {
357 0 : OString aComment("EPSReplacementGraphic");
358 0 : if ( nSizeWMF || nSizeTIFF )
359 : {
360 0 : SvMemoryStream aReplacement( nSizeWMF + nSizeTIFF + 28 );
361 0 : sal_uInt32 nMagic = 0xc6d3d0c5;
362 0 : sal_uInt32 nPPos = 28 + nSizeWMF + nSizeTIFF;
363 0 : sal_uInt32 nWPos = nSizeWMF ? 28 : 0;
364 0 : sal_uInt32 nTPos = nSizeTIFF ? 28 + nSizeWMF : 0;
365 :
366 0 : aReplacement.WriteUInt32( nMagic ).WriteUInt32( nPPos ).WriteUInt32( nPSSize )
367 0 : .WriteUInt32( nWPos ).WriteUInt32( nSizeWMF )
368 0 : .WriteUInt32( nTPos ).WriteUInt32( nSizeTIFF );
369 0 : if ( nSizeWMF )
370 : {
371 0 : boost::scoped_array<sal_uInt8> pBuf(new sal_uInt8[ nSizeWMF ]);
372 0 : rStrm.Seek( nOrigPos + nPosWMF );
373 0 : rStrm.Read( pBuf.get(), nSizeWMF );
374 0 : aReplacement.Write( pBuf.get(), nSizeWMF );
375 : }
376 0 : if ( nSizeTIFF )
377 : {
378 0 : boost::scoped_array<sal_uInt8> pBuf(new sal_uInt8[ nSizeTIFF ]);
379 0 : rStrm.Seek( nOrigPos + nPosTIFF );
380 0 : rStrm.Read( pBuf.get(), nSizeTIFF );
381 0 : aReplacement.Write( pBuf.get(), nSizeTIFF );
382 : }
383 0 : rMtf.AddAction( (MetaAction*)( new MetaCommentAction( aComment, 0, (const sal_uInt8*)aReplacement.GetData(), aReplacement.Tell() ) ) );
384 : }
385 : else
386 0 : rMtf.AddAction( (MetaAction*)( new MetaCommentAction( aComment, 0, NULL, 0 ) ) );
387 0 : }
388 :
389 : //there is no preview -> make a red box
390 0 : void MakePreview(sal_uInt8* pBuf, sal_uInt32 nBytesRead,
391 : long nWidth, long nHeight, Graphic &rGraphic)
392 : {
393 0 : GDIMetaFile aMtf;
394 0 : VirtualDevice aVDev;
395 0 : Font aFont;
396 :
397 0 : aVDev.EnableOutput( false );
398 0 : aMtf.Record( &aVDev );
399 0 : aVDev.SetLineColor( Color( COL_RED ) );
400 0 : aVDev.SetFillColor();
401 :
402 0 : aFont.SetColor( COL_LIGHTRED );
403 : // aFont.SetSize( Size( 0, 32 ) );
404 :
405 0 : aVDev.Push( PUSH_FONT );
406 0 : aVDev.SetFont( aFont );
407 :
408 0 : Rectangle aRect( Point( 1, 1 ), Size( nWidth - 2, nHeight - 2 ) );
409 0 : aVDev.DrawRect( aRect );
410 :
411 0 : OUString aString;
412 : int nLen;
413 0 : sal_uInt8* pDest = ImplSearchEntry( pBuf, (sal_uInt8*)"%%Title:", nBytesRead - 32, 8 );
414 0 : if ( pDest )
415 : {
416 0 : pDest += 8;
417 0 : if ( *pDest == ' ' )
418 0 : pDest++;
419 0 : nLen = ImplGetLen( pDest, 32 );
420 0 : sal_uInt8 aOldValue(pDest[ nLen ]); pDest[ nLen ] = 0;
421 0 : if ( strcmp( (const char*)pDest, "none" ) != 0 )
422 : {
423 0 : aString += " Title:" + OUString::createFromAscii( (char*)pDest ) + "\n";
424 : }
425 0 : pDest[ nLen ] = aOldValue;
426 : }
427 0 : pDest = ImplSearchEntry( pBuf, (sal_uInt8*)"%%Creator:", nBytesRead - 32, 10 );
428 0 : if ( pDest )
429 : {
430 0 : pDest += 10;
431 0 : if ( *pDest == ' ' )
432 0 : pDest++;
433 0 : nLen = ImplGetLen( pDest, 32 );
434 0 : sal_uInt8 aOldValue(pDest[ nLen ]); pDest[ nLen ] = 0;
435 0 : aString += " Creator:" + OUString::createFromAscii( (char*)pDest ) + "\n";
436 0 : pDest[ nLen ] = aOldValue;
437 : }
438 0 : pDest = ImplSearchEntry( pBuf, (sal_uInt8*)"%%CreationDate:", nBytesRead - 32, 15 );
439 0 : if ( pDest )
440 : {
441 0 : pDest += 15;
442 0 : if ( *pDest == ' ' )
443 0 : pDest++;
444 0 : nLen = ImplGetLen( pDest, 32 );
445 0 : sal_uInt8 aOldValue(pDest[ nLen ]); pDest[ nLen ] = 0;
446 0 : if ( strcmp( (const char*)pDest, "none" ) != 0 )
447 : {
448 0 : aString += " CreationDate:" + OUString::createFromAscii( (char*)pDest ) + "\n";
449 : }
450 0 : pDest[ nLen ] = aOldValue;
451 : }
452 0 : pDest = ImplSearchEntry( pBuf, (sal_uInt8*)"%%LanguageLevel:", nBytesRead - 4, 16 );
453 0 : if ( pDest )
454 : {
455 0 : pDest += 16;
456 0 : int nCount = 4;
457 0 : long nNumber = ImplGetNumber( &pDest, nCount );
458 0 : if ( nCount && ( (sal_uInt32)nNumber < 10 ) )
459 : {
460 0 : aString += " LanguageLevel:" + OUString::number( nNumber );
461 : }
462 : }
463 0 : aVDev.DrawText( aRect, aString, TEXT_DRAW_CLIP | TEXT_DRAW_MULTILINE );
464 0 : aVDev.Pop();
465 0 : aMtf.Stop();
466 0 : aMtf.WindStart();
467 0 : aMtf.SetPrefMapMode( MAP_POINT );
468 0 : aMtf.SetPrefSize( Size( nWidth, nHeight ) );
469 0 : rGraphic = aMtf;
470 0 : }
471 :
472 :
473 : //================== GraphicImport - the exported function ================
474 :
475 : // this needs to be kept in sync with
476 : // ImpFilterLibCacheEntry::GetImportFunction() from
477 : // vcl/source/filter/graphicfilter.cxx
478 : #if defined(DISABLE_DYNLOADING)
479 : #define GraphicImport ipsGraphicImport
480 : #endif
481 :
482 : extern "C" SAL_DLLPUBLIC_EXPORT bool SAL_CALL
483 0 : GraphicImport( SvStream & rStream, Graphic & rGraphic, FilterConfigItem* )
484 : {
485 0 : if ( rStream.GetError() )
486 0 : return false;
487 :
488 0 : Graphic aGraphic;
489 0 : sal_Bool bRetValue = sal_False;
490 0 : sal_Bool bHasPreview = sal_False;
491 0 : sal_Bool bGraphicLinkCreated = sal_False;
492 : sal_uInt32 nSignature, nPSStreamPos, nPSSize;
493 0 : sal_uInt32 nSizeWMF = 0;
494 0 : sal_uInt32 nPosWMF = 0;
495 0 : sal_uInt32 nSizeTIFF = 0;
496 0 : sal_uInt32 nPosTIFF = 0;
497 0 : sal_uInt32 nOrigPos = nPSStreamPos = rStream.Tell();
498 0 : sal_uInt16 nOldFormat = rStream.GetNumberFormatInt();
499 0 : rStream.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
500 0 : rStream.ReadUInt32( nSignature );
501 0 : if ( nSignature == 0xc6d3d0c5 )
502 : {
503 0 : rStream.ReadUInt32( nPSStreamPos ).ReadUInt32( nPSSize ).ReadUInt32( nPosWMF ).ReadUInt32( nSizeWMF );
504 :
505 : // first we try to get the metafile grafix
506 :
507 0 : if ( nSizeWMF )
508 : {
509 0 : if ( nPosWMF != 0 )
510 : {
511 0 : rStream.Seek( nOrigPos + nPosWMF );
512 0 : if ( GraphicConverter::Import( rStream, aGraphic, CVT_WMF ) == ERRCODE_NONE )
513 0 : bHasPreview = bRetValue = sal_True;
514 : }
515 : }
516 : else
517 : {
518 0 : rStream.ReadUInt32( nPosTIFF ).ReadUInt32( nSizeTIFF );
519 :
520 : // else we have to get the tiff grafix
521 :
522 0 : if ( nPosTIFF && nSizeTIFF )
523 : {
524 0 : rStream.Seek( nOrigPos + nPosTIFF );
525 0 : if ( GraphicConverter::Import( rStream, aGraphic, CVT_TIF ) == ERRCODE_NONE )
526 : {
527 0 : MakeAsMeta(aGraphic);
528 0 : rStream.Seek( nOrigPos + nPosTIFF );
529 0 : bHasPreview = bRetValue = sal_True;
530 : }
531 : }
532 : }
533 : }
534 : else
535 : {
536 0 : nPSStreamPos = nOrigPos; // no preview available _>so we must get the size manually
537 0 : nPSSize = rStream.Seek( STREAM_SEEK_TO_END ) - nOrigPos;
538 : }
539 0 : sal_uInt8* pHeader = new sal_uInt8[ 22 ];
540 0 : rStream.Seek( nPSStreamPos );
541 0 : rStream.Read( pHeader, 22 ); // check PostScript header
542 0 : if ( ImplSearchEntry( pHeader, (sal_uInt8*)"%!PS-Adobe", 10, 10 ) &&
543 0 : ImplSearchEntry( &pHeader[ 15 ], (sal_uInt8*)"EPS", 3, 3 ) )
544 : {
545 0 : rStream.Seek( nPSStreamPos );
546 0 : sal_uInt8* pBuf = new sal_uInt8[ nPSSize ];
547 0 : if ( pBuf )
548 : {
549 0 : sal_uInt32 nBufStartPos = rStream.Tell();
550 0 : sal_uInt32 nBytesRead = rStream.Read( pBuf, nPSSize );
551 0 : if ( nBytesRead == nPSSize )
552 : {
553 0 : int nSecurityCount = 32;
554 0 : if ( !bHasPreview ) // if there is no tiff/wmf preview, we will parse for an preview in the eps prolog
555 : {
556 0 : sal_uInt8* pDest = ImplSearchEntry( pBuf, (sal_uInt8*)"%%BeginPreview:", nBytesRead - 32, 15 );
557 0 : if ( pDest )
558 : {
559 0 : pDest += 15;
560 0 : long nWidth = ImplGetNumber( &pDest, nSecurityCount );
561 0 : long nHeight = ImplGetNumber( &pDest, nSecurityCount );
562 0 : long nBitDepth = ImplGetNumber( &pDest, nSecurityCount );
563 0 : long nScanLines = ImplGetNumber( &pDest, nSecurityCount );
564 0 : pDest = ImplSearchEntry( pDest, (sal_uInt8*)"%", 16, 1 ); // go to the first Scanline
565 0 : if ( nSecurityCount && pDest && nWidth && nHeight && ( ( nBitDepth == 1 ) || ( nBitDepth == 8 ) ) && nScanLines )
566 : {
567 0 : rStream.Seek( nBufStartPos + ( pDest - pBuf ) );
568 :
569 0 : Bitmap aBitmap( Size( nWidth, nHeight ), 1 );
570 0 : BitmapWriteAccess* pAcc = aBitmap.AcquireWriteAccess();
571 0 : if ( pAcc )
572 : {
573 : int nBitsLeft;
574 0 : sal_Bool bIsValid = sal_True;
575 0 : sal_uInt8 nDat = 0;
576 : char nByte;
577 0 : for ( long y = 0; bIsValid && ( y < nHeight ); y++ )
578 : {
579 0 : nBitsLeft = 0;
580 0 : for ( long x = 0; x < nWidth; x++ )
581 : {
582 0 : if ( --nBitsLeft < 0 )
583 : {
584 0 : while ( bIsValid && ( nBitsLeft != 7 ) )
585 : {
586 0 : rStream.ReadChar( nByte );
587 0 : switch ( nByte )
588 : {
589 : case 0x0a :
590 0 : if ( --nScanLines < 0 )
591 0 : bIsValid = sal_False;
592 : case 0x09 :
593 : case 0x0d :
594 : case 0x20 :
595 : case 0x25 :
596 0 : break;
597 : default:
598 : {
599 0 : if ( nByte >= '0' )
600 : {
601 0 : if ( nByte > '9' )
602 : {
603 0 : nByte &=~0x20; // case none sensitive for hexadecimal values
604 0 : nByte -= ( 'A' - 10 );
605 0 : if ( nByte > 15 )
606 0 : bIsValid = sal_False;
607 : }
608 : else
609 0 : nByte -= '0';
610 0 : nBitsLeft += 4;
611 0 : nDat <<= 4;
612 0 : nDat |= ( nByte ^ 0xf ); // in epsi a zero bit represents white color
613 : }
614 : else
615 0 : bIsValid = sal_False;
616 : }
617 0 : break;
618 : }
619 : }
620 : }
621 0 : if ( nBitDepth == 1 )
622 0 : pAcc->SetPixelIndex( y, x, static_cast<sal_uInt8>(nDat >> nBitsLeft) & 1 );
623 : else
624 : {
625 0 : pAcc->SetPixelIndex( y, x, nDat ? 1 : 0 ); // nBitDepth == 8
626 0 : nBitsLeft = 0;
627 : }
628 : }
629 : }
630 0 : if ( bIsValid )
631 : {
632 0 : VirtualDevice aVDev;
633 0 : GDIMetaFile aMtf;
634 0 : Size aSize;
635 0 : aVDev.EnableOutput( false );
636 0 : aMtf.Record( &aVDev );
637 0 : aSize = aBitmap.GetPrefSize();
638 0 : if( !aSize.Width() || !aSize.Height() )
639 0 : aSize = Application::GetDefaultDevice()->PixelToLogic( aBitmap.GetSizePixel(), MAP_100TH_MM );
640 : else
641 0 : aSize = Application::GetDefaultDevice()->LogicToLogic( aSize, aBitmap.GetPrefMapMode(), MAP_100TH_MM );
642 0 : aVDev.DrawBitmap( Point(), aSize, aBitmap );
643 0 : aMtf.Stop();
644 0 : aMtf.WindStart();
645 0 : aMtf.SetPrefMapMode( MAP_100TH_MM );
646 0 : aMtf.SetPrefSize( aSize );
647 0 : aGraphic = aMtf;
648 0 : bHasPreview = bRetValue = sal_True;
649 : }
650 0 : aBitmap.ReleaseAccess( pAcc );
651 0 : }
652 : }
653 : }
654 : }
655 :
656 0 : sal_uInt8* pDest = ImplSearchEntry( pBuf, (sal_uInt8*)"%%BoundingBox:", nBytesRead, 14 );
657 0 : if ( pDest )
658 : {
659 0 : nSecurityCount = 100;
660 : long nNumb[4];
661 0 : nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
662 0 : pDest += 14;
663 0 : for ( int i = 0; ( i < 4 ) && nSecurityCount; i++ )
664 : {
665 0 : nNumb[ i ] = ImplGetNumber( &pDest, nSecurityCount );
666 : }
667 0 : if ( nSecurityCount)
668 : {
669 0 : bGraphicLinkCreated = sal_True;
670 0 : GfxLink aGfxLink( pBuf, nPSSize, GFX_LINK_TYPE_EPS_BUFFER, true ) ;
671 0 : GDIMetaFile aMtf;
672 :
673 0 : long nWidth = nNumb[2] - nNumb[0] + 1;
674 0 : long nHeight = nNumb[3] - nNumb[1] + 1;
675 :
676 : // if there is no preview -> try with gs to make one
677 0 : if( !bHasPreview )
678 : {
679 0 : bHasPreview = RenderAsEMF(pBuf, nBytesRead, aGraphic);
680 0 : if (!bHasPreview)
681 0 : bHasPreview = RenderAsBMP(pBuf, nBytesRead, aGraphic);
682 : }
683 :
684 : // if there is no preview -> make a red box
685 0 : if( !bHasPreview )
686 : {
687 : MakePreview(pBuf, nBytesRead, nWidth, nHeight,
688 0 : aGraphic);
689 : }
690 :
691 : aMtf.AddAction( (MetaAction*)( new MetaEPSAction( Point(), Size( nWidth, nHeight ),
692 0 : aGfxLink, aGraphic.GetGDIMetaFile() ) ) );
693 0 : CreateMtfReplacementAction( aMtf, rStream, nOrigPos, nPSSize, nPosWMF, nSizeWMF, nPosTIFF, nSizeTIFF );
694 0 : aMtf.WindStart();
695 0 : aMtf.SetPrefMapMode( MAP_POINT );
696 0 : aMtf.SetPrefSize( Size( nWidth, nHeight ) );
697 0 : rGraphic = aMtf;
698 0 : bRetValue = sal_True;
699 : }
700 : }
701 : }
702 : }
703 0 : if ( !bGraphicLinkCreated )
704 0 : delete[] pBuf;
705 : }
706 0 : delete[] pHeader;
707 0 : rStream.SetNumberFormatInt(nOldFormat);
708 0 : rStream.Seek( nOrigPos );
709 0 : return ( bRetValue );
710 : }
711 :
712 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|