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