Issue 119735

Summary: SVG Export: missing implementation for when using GraphicProvider
Product: Draw Reporter: Sven Jacobi <Sven-Jacobi>
Component: codeAssignee: Armin Le Grand <Armin.Le.Grand>
Status: RESOLVED FIXED QA Contact:
Severity: Normal    
Priority: P3 CC: Armin.Le.Grand
Version: recent-trunk   
Target Milestone: 4.0.0   
Hardware: PC   
OS: All   
Issue Type: DEFECT Latest Confirmation in: ---
Developer Difficulty: ---
Description Flags
SVGWriter implementation
File with macro to test export/import with GraphicProvider service none

Description Sven Jacobi 2012-06-04 16:29:25 UTC
Created attachment 77944 [details]
SVGWriter implementation

In svtools/source/filter.vcl/filter.cxx the normal GDIMetafile to svg export fallback does not work, therefore you can't create a svg via, because the implementation for is missing. 

I added a patch for the missing svg implementation in filter/source/svg/
Comment 1 Armin Le Grand 2012-06-05 11:17:49 UTC
ALG: Added me to CC
Comment 2 Armin Le Grand 2012-06-06 13:19:03 UTC
ALG->Sven: Thanks for the patch. Have you tested this and if, how can I test it? Do you have a scenario for me?
Comment 3 Ariel Constenla-Haile 2012-06-07 12:29:39 UTC
Created attachment 78149 [details]
File with macro to test export/import with GraphicProvider service

The test document has an image.
The macro tries to export the image to SVG using the GraphicProvider service, then import the image back.


The MimeType used is "image/svg+xml", not sure how correct is that, but this is what the API documentation says:
See define MIMETYPE_SVG in main/svtools/source/graphic/descriptor.hxx and GraphicProvider::storeGraphic in main/svtools/source/graphic/provider.cxx

It seems that you don't need a macro to reproduce it:

- Insert a picture in Writer
- Select the picture
- Right-click with the mouse, select from the context menu "Save Graphics..."
- In the "Graphics Export" dialog, from the list box "File type" choose "SVG - Scalable Vector Graphics"
- Insert a File name
- Press "Save" button to export the graphics
- Open the graphic with a text editor: the file is empty, the file size is 0 (zero)

Expected result: there should be an XML file with the SVG graphic
Comment 4 Armin Le Grand 2012-06-08 15:17:19 UTC
ALG: Thanks Ariel, this makes it testable.
I used a bitmap graphic, inserted, selected and exported to SVG. The exported SVG is just some bytes. This is because GraphicFilter::ExportGraphic for the EXP_SVG case does not check if the Graphic is a Metafile, but just uses it by calling aGraphic.GetGDIMetaFile(). The Metafile contains a bitmap, thus an empty Metafile is used and the export is empty.
Interestingly GetGDIMetaFile just returns the local Metafile of the Graphic without any checks; compared to that the calls GetBitmap/GetBitmapEx at Graphic both convert the content to a Bitmap/BitmapEx when the content actually is a Metafile. I also found a lot of places where the type is checked before calling GetGDIMetaFile and a small, local conversion is done (VDev, Metafile with one Bitmap paint action is created).
For conformity it would make sense to do the conversion inside ImpGraphic::ImplGetGDIMetaFile and to remove as many places as possible where this is done locally (e.g. interstingly in GraphicFilter::ExportGraphic). Only caveat is that ImpGraphic::ImplGetGDIMetaFile returns a 'const GDIMetaFile&', thus creating a local one and returning would require to change the return type. In comparison, ImplGetBitmap/ImplGetBitmapEx return by value. Bitmap/BitmapEx is not expensive returning by value since these are refcounted internally, but Metafile is not and thus expensive.
There is a Metafile member in ImpGraphic, and it is empty when type is GRAPHIC_BITMAP, so using it as local buffer is a possibility. I checked usages of maMetaFile and it never gets used when type is GRAPHIC_BITMAP. It gets copied in operator=, so buffering would survive buffering. It would get lost in save/load, but that's okay. All in all it seems possible.
I will try it out...
Comment 5 Armin Le Grand 2012-06-08 16:09:25 UTC
ALG: Works as expected, should be used. Also needs not much memory since the BitmapAction in the Metafile also uses the original, ref-counted bitmap.

When looking at the export another problem arises: In SVGActionWriter::ImplWriteBmp nearly a minute is used (and assertions thrown as crazy) in the following line:

::rtl::OUString aImageData( (sal_Char*) aOStm.GetData(), aOStm.Tell(), RTL_TEXTENCODING_ASCII_US );

No wonder; the Bitmap, exported as PNG (in aOStm which is a SvMemoryStream) is copied to a rtl::OUString (!) and encoded as RTL_TEXTENCODING_ASCII_US (!). Of course a lot of non-ascii characters will be in an exported PNG.

That data is then used to create the Base64 encoded string data (of course locally, how many Base64 encoders might we have?). This can of course be done on the original memory stream data, avoiding this unicode conversion and the needed memory. Testing this...
Comment 6 Armin Le Grand 2012-06-08 16:14:06 UTC
ALG: also works as expected, is much faster, needs less memory and throws no exceptions.

All in all I have now a working export of a bitmap graphic to SVG.
Comment 7 Armin Le Grand 2012-06-08 16:14:22 UTC
ALG: Taking ownership.
Comment 8 Armin Le Grand 2012-06-11 09:28:42 UTC
ALG: Identified some more local converters from Graphic with Bitmap/BitmapEx to Metafile and replaced with GetGDIMetaFile. Checked exporting pixel graphic, metafile and SVG graphic to SVG, work all now.
Comment 9 Armin Le Grand 2012-06-11 09:38:18 UTC
ALG: Done. Thanks again to Sven for providing the initial code!
Comment 10 Sven Jacobi 2012-06-18 14:02:43 UTC
Many thanks for being so fast and taking care of this issue...

@Ariel, helping to reproduce this issue.
@Armin, for accepting my patch and finding this string problem