Menu

#1135 SVG corrupted: missing image

None
closed-accepted
nobody
None
2016-05-23
2012-06-01
Anonymous
No

I can generte SVG image using the SVG terminal when I plot any funtion. that's fine. The problem arises when I plot from a matrix. in the SVF there is a link to an unknown image:

in svg file generated:
....
<g style="fill:none; color:red; stroke:currentColor; stroke-width:1.00; stroke-linecap:butt; stroke-linejoin:miter">
<image x='-765.0' y='47.8' width='3242.7' height='747.3' preserveAspectRatio='none' xlink:href='gp_image_01.png'/>;
</g>
....

commands:
set terminal svg size 1000,800 dynamic enhanced
set output 'd:\tmp\sample.svg'
set cbrange [0:200]
set xrange [0:0.5]

set title "tasca"
plot 'file.dat' matrix index 2 notitle with image;

reset;

-----
and the sample data is:

#deficit
100 0
300 0
0 0
0 0
0 0
0 0
0 0
1 0
0 0
102 0
101 0
0 0

Discussion

1 2 > >> (Page 1 of 2)
  • Ethan Merritt

    Ethan Merritt - 2012-06-01
    • status: open --> open-works-for-me
     
  • Ethan Merritt

    Ethan Merritt - 2012-06-01

    %%%%%%%%%%%%%
    Quick fix:

    gnuplot> help failsafe
    Some terminals use device- or library-specific optimizations to render image
    data within a rectangular 2D area. This sometimes produces undesirable output,
    e.g. bad clipping or scaling, missing edges. The `failsafe` keyword tells
    gnuplot to use generic code that renders the image pixel-by-pixel instead.
    This rendering mode is slower and may result in much larger output files, but
    should produce a consistent rendered view on all terminals.
    Example:
    plot 'data' with image failsafe

    %%%%%%%%%%%%%%%%5

    More detailed answer:
    Terminals whose native representation of an image is very inefficient, including svg, store the image in a PNG file instead if possible. Of course this requires being able to create the PNG file, but normally gnuplot is built with PNG support so this is not a problem. Are you sure that the *.png file was not created? Or maybe it was created but got separated from the *.svg file? Were there any error messages when running gnuplot?

     
  • Anonymous

    Anonymous - 2012-06-02

    thaks for your answer, failsafe was ok for me.
    I saw that the "missing" png file was created in another directory different from where svg was created. Maybe both images should be created in the same dir....

    PS:there were no error messages

     
  • Ethan Merritt

    Ethan Merritt - 2012-06-06
    • status: open-works-for-me --> closed-works-for-me
     
  • Dan Sebald

    Dan Sebald - 2016-05-12

    Ethan,

    This same issue has come up in an Octave bug report:

    https://savannah.gnu.org/bugs/?38323

    It looks like this behavior has been consistent from the beginning of its introduction:

    2011-04-07  Ethan A Merritt  <merritt@u.washington.edu>
    
        * src/term.h term/svg.trm demo/html/webify_svg.pl demo/html/Makefile.svg
        demo/html/Makefile.svg:  Add bitmap image handling to the svg terminal
        using the same mechanism of external png files used by the canvas and 
        tikz terminals.
    
        * term/svg.trm(SVG_init): Konqueror (KDE 4.5) crashes if the xlink to
        gnuplot_svg.js fails to load.  Work around this by adding a test for the
        presence of gnuplot_svg before initializing.
    

    I see the info on external images:

    http://www.w3.org/TR/SVG11/struct.html#ImageElementHrefAttribute

    and the W3 examples do not include any examples of "rasters" (it is vector graphics after all), but I think it is possible to include data directly in the file rather than have it separate. I'm attaching an example in which I generated the PNG via Octave/gnuplot. I took the gp_image_01.svg and imported that into Inkscape and then saved that as gp_image_01-mod.svg. The important SVG code is

     xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAABmJLR0QA/wD/AP+gvaeTAAADQUlE
    

    eog reads these files. The contents is viewable by Mint/Gnome3 file navigator.

    I'm wondering if it makes sense to have an SVG option for how images are treated, i.e., "standalone" or non-standalone, "embedded" or non-embedded, etc. It shouldn't be too difficult of a change in svg.trm--just the option, and then some extra code in SVG_image() for the standalone/embedded case.

    I would think that "failsafe"/pixels layout wouldn't be as good quality as rendering an image in some instances depending upon what the viewer ultimately is.

     
  • Ethan Merritt

    Ethan Merritt - 2016-05-13

    It sounds like a good idea to offer an option to embed the image. Are you willing to work on a patch that converts from an in-memory PNG image to whatever that "base64" encoding is? There may be some standard library routines to do it, but I've never looked into the question.

    Having said that, would this actually help the Octave issue? Anything we add to gnuplot now will obviously effect only future gnuplot versions, while the bug trail you point to is concerned with how to support old gnuplot versions.

     
  • Dan Sebald

    Dan Sebald - 2016-05-13

    Microsoft has a Convert.[function] routine for Base64 conversion. Anyway, I may have done something close to this with the EPS encoding of images, so this is probably one of those things where it's easier to write a bit of code rather than go through the trouble of including a library. I'll have a look this weekend.

    No, it doesn't help the immediate Octave issue, but in the long term would make for more compact and better scaled SVG. Octave will just have to use failsafe mode for gnuplot 4.6 to 5.1 or whatever the next version is.

     
  • Ethan Merritt

    Ethan Merritt - 2016-05-13

    I think you have that backwards. Placing the image in-line in Base64 will not change the scaling at all, and it makes the SVG file larger that the SVG+(binary)PNG combination.

    I think it is reasonble to offer the option to embed images but I also think the Octave bug report is misguided. It is perfectly normal for an SVG to reference external files and there are clear advantages to doing it that way. That doesn't mean it's always the right choice, but it certainly isn't a "bug". If you overwrite a referenced PNG file with a later command, that's a user error not a gnuplot error. It's no different than if you mistakenly overwrite a previous output file in some other format.

     
  • Dan Sebald

    Dan Sebald - 2016-05-13

    I meant size-wise compared to the failsafe option that puts the description for individual pixels within the SVG file so has a single file.

    I agree about the Octave bug report. I would modify things so that the SVG and PNG end up in the same directory. Then if an option comes along have a device option "svg+png" or "svgstandalone". Octave already has "tikzstandalone" as a precedent. Ultimately, I would assume an option for Octave is good too because then someone could have several SVG file variants that have the same image as a base--cut down on data traffic for a webpage.

     

    Last edit: Dan Sebald 2016-05-13
  • Ethan Merritt

    Ethan Merritt - 2016-05-13

    Compared to the failsafe option, sure. By the way the prefered name for that option is now "pixels". It exists for a different purpose - it forces the svg renderer to display individual pixels as solid color rectangles rather than doing color-smoothing across multiple pixels. See
    http://gnuplot.sourceforge.net/demo_svg_5.1/heatmaps.html
    It just happens to have the side effect of providing a work-around to force in-line images as an alternative to referenced PNG files.

     
  • Dan Sebald

    Dan Sebald - 2016-05-16

    I got around to implementing the embedded PNG Sunday evening. It's pretty straightforward actually. The PostScript code is ASCII85, which is a bit more complicated.

    Attached is a first pass at a patch in which I simply used "embedimagedata" as an option. I wanted to use "standalone", but that is already taken for the mouse. Could it be used for both? Don't know, but we can discuss the best terminology for the option.

    Also, I'm just using the gp_image_XX.png file as a temporary holder for the PNG file. It would actually be best to use a file in the /tmp directory, but I wasn't sure how gnuplot handles temp files. (I could look, but I figured I'd leave that up to you.) The issue with temp files these days is that there has been an attempt to deprecate requesting for a tempname and then opening that temp file. Instead, newer routines will give an open temp file immediately...but sometimes it is difficult to get the temp file name from that open file. It all has to do with security. Supposedly, requesting a name and then opening that name leaves room for malware to intervene and the contents gets written somewhere it wasn't intended to.

     
    • Ethan Merritt

      Ethan Merritt - 2016-05-16

      Also, I'm just using the gp_image_XX.png file as a temporary holder for the PNG file. It would actually be best to use a file in the /tmp directory, but I wasn't sure how gnuplot handles temp files.

      There is no need to use a separate file in this case. The png image already exists in memory, why write it out to a file just so you can read it back again?

       
      • Dan Sebald

        Dan Sebald - 2016-05-16

        That would be preferred. I only skimmed the front part of the routine thinking

        write_png_image (m, n, image, color_mode, image_file);

        this does the image translation and file save in one step. I'll have a look.

         
      • Dan Sebald

        Dan Sebald - 2016-05-16

        You are suggesting we might rewrite write_png_image() slightly so that it could make use of, say, this gdLib function?

        https://boutell.com/gd/manual2.0.33.html#creating

        void gdImagePngPtr(gdImagePtr im, int size) (FUNCTION)
        Identical to gdImagePng except that it returns a pointer to a memory area with the PNG data. This memory must be freed by the caller when it is no longer needed. The caller must invoke gdFree(), not free(), unless the caller is absolutely certain that the same implementations of malloc, free, etc. are used both at library build time and at application build time. The 'size' parameter receives the total size of the block of memory.

        We could change the name write_png_image() to save_png_image() for a to-file version and have create_png_image() be almost the same but call gdImagePngPtr().

         
  • Dan Sebald

    Dan Sebald - 2016-05-16

    Attached is a set of commands to illustrate the SVG embedded and with auxiliary for a 2x2 image. Note that I think something else is needed here because there is clear interpolation and the resulting image sizing is outside the axes. (I'll post images if you like.)

     
  • Dan Sebald

    Dan Sebald - 2016-05-16

    And here is larger example similar to what the Octave user was generating for that bug report. To use the attached file, try something like:

    set term svg enhanced size 560,420
    set output 'testlarge-aux.svg'
    load 'largeimage.gp'
    set output
    
    set term svg enhanced size 560,420 embedimagedata
    set output 'testlarge-embed.svg'
    load 'largeimage.gp'
    set output
    
     
  • Dan Sebald

    Dan Sebald - 2016-05-16

    I forgot to delete a line of cruft from the code.

    82d81
    < + byte4 -= 1;

    New patch attached.

     
  • Dan Sebald

    Dan Sebald - 2016-05-16

    Oh yeah, I was going to point out the behavior of the current setup for auxiliary file naming convention. The gp_image_XX.png get overwritten every time gnuplot is relaunched. It does point out this conflict in the documentation--and the "name" option is fine. However, it might make sense to use the SVG file name as the default base name rather than just "gp", and then reset the counter for every new plot sequence between the lines:

    set output 'MYFILE.svg'
    set output

    Also, it might be good to delete from the directory any "MYFILE_image_XX.png" at the point of "set output 'MYFILE.svg". That way, the default behavior at the end of this would be, say, a group of files

    MYFILE.svg
    MYFILE_image_01.png
    MYFILE_image_02.png
    MYFILE_image_03.png

    And then lets say I decide to run this plot again, but this time I leave out one of the images in my sequence. Well, then in the directory would only be

    MYFILE.svg
    MYFILE_image_01.png
    MYFILE_image_02.png

    because the MYFILE_image_03.png will have been deleted. It would just aid the user in managing files instead of having a seemingly random group of gp_image_XX.png files in the directory and not quite sure which SVG is referencing what files.

     
  • Ethan Merritt

    Ethan Merritt - 2016-05-16

    Let's take a step or two back.
    As I understand it there are two issues:

    1) Can Octave be taught to make better (less error-prone) use of old gnuplot versions. The answer here seems to be "Yes. Make sure that it uses FILENAME both for 'set out FILENAME' and 'set term svg name FILENAME'".

    2) How can we provide embedded images in future gnuplot versions. This won't help Octave in the short term, but may be worth doing in its own right.

    One very simple path to (2) is to clone the pdfcairo terminal code (very few lines total) to create a new terminal svgcairo. I think this can be done entirely in .../term/cairo.trm
    Here's is a proof-of-principle dump of "barchart_art.dem" as a cairo+svg file:
    It works, but note that the file size is 80kB whereas the svg+5xpng images produces for the same demo by the current svg terminals take a little more than half that (45kB).
    Another down-side of this approach is that it would not support the interactive extras like hyptertext and mousing that are provided by the current svg terminal.

    A second path as you say would be to reuse or modify the code in write_png_image. The cairo version of that takes all of 3 lines:

     image255 = gp_cairo_helper_coordval_to_chars(image, m, n, color_mode);
      image_surface = cairo_image_surface_create_for_data((unsigned char*) image255, CAIRO_FORMAT_ARGB32, m, n, 4*m);
      cairo_surface_write_to_png_stream (image_surface, callback_write_function, closure_data)
    

    You would have to provide a callback write function that applies the Base64 encoding and dumps into the gnuplot output file.
    The libgd code is a lot more verbose and is not normally built into gnuplot if cairo is available. But yeah, you could work off that instead.

     
  • Ethan Merritt

    Ethan Merritt - 2016-05-16
    • status: closed-works-for-me --> open
    • Group: -->
    • Priority: 5 -->
     
  • Dan Sebald

    Dan Sebald - 2016-05-17

    I suggested 1 to the Octave bug report. They seemed vehement it had to be a single file. If they do 1 and call that svg then when a new gnuplot version adds a standalone option, then can call that "svgstandalone".

    The svgcairo.svg file is an example where having an external file really benefits. And there probably are conceivable examples in which a small picture is used several times on, say, a map (election results), etc.

    It might not be too difficult to provide both libgd and cairo in the different cases within write_png_image. An svgcairo terminal is fine too. Have all the code now, so it isn't too much work to piece things together.

     
  • Ethan Merritt

    Ethan Merritt - 2016-05-17

    The vehemence I saw was that a good solution should work even if the user has an older version of gnuplot. That limits the options to whatever older versions provided, and thus is a separate discussion from whatever new things we add going forward.

     
  • Dan Sebald

    Dan Sebald - 2016-05-20

    Attached is a much larger patch incorporating what we had discussed, i.e., not having to use a temporary file for the case where PNG is embedded. The Cairo case was a little trickier than expected (although not bad) because the callback function gets called time and again with small hunks of data, e.g., 8 bytes, 24 bytes, 4 bytes, 4 bytes, 8 bytes, etc.

    BTW, what is a "closure" in the Cairo nomenclature?

    I also removed all the os_error() calls from within write_png_image.c because it's not good practice to bail to the command line from a lower level function. The person programming at the terminal driver level might not realize it bails to the command line and then there is the potential for a memory leak. There were potential leaks from within write_png_image.c as well. And these are not highly unlikely cases because it is conceivable the user could specify a file name that refers to an existing read-only image file and the image writing routines might fail, in which case a potential big chunk memory in the form of a Cairo or gd image could be lost. So, I've tried to make sure memory is all cleaned up properly.

    Note that even though Cairo and gd cases both work, they do not produce exactly the same image for the small image file example I attached earlier. The Cairo PNG image is one for which there is interpolation and the interpolation is with a black background so the image gets dark near the edges. The gd PNG image is similarly interpolated, but the interpolation is with alpha shading so the outer edges are transparent.

     
    • Ethan Merritt

      Ethan Merritt - 2016-05-20

      BTW, what is a "closure" in the Cairo nomenclature?

      AIUI "closure" == "pointer to some opaque data that cairo doesn't need to know about but the caller wants to be able to reference whenever it is called back by cairo". As a simple example, it might be a file pointer or filename string so that when your routine gets called back it knows which of several files to write to.

       
1 2 > >> (Page 1 of 2)

Log in to post a comment.