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