Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Image from DB display issue when using SVG with DataSource.getFileURL()

    Hi Isomorphic,

    I have run into a strange issue I can't reproduce, but perhaps you have an idea.

    Setting: SaaS with light customer CD (main application color, logo)
    So far, I uploaded the logo as part of the deploy step. Now it should come from the DB, so that color and logo changes are possible easily via settings change.
    This does work as expected with FileUpload and DataSource.getFileURL(), but only for PNG/JPG files. The issue is that if I upload a SVG, it does not show up in my Img. It shows as broken image. When I do a "right click"->"Open in new Tab", the image is shown as expected. you have an idea.

    It does though in the showcase, which is why I'm a bit confused. Do you have an idea?
    Please note that I'm using SmartGWT and not SmartClient where it does not work.

    This is my (working) testcase:
    This SVG: https://en.wikipedia.org/wiki/File:W...ia-logo-v2.svg
    Upload it as only file here (v11.1p_2018-05-24) (as only file, as otherwise the DB request returns two rows and then the servlet call fails):
    Code:
    isc.DynamicForm.create({
        autoDraw: false,
        ID: "uploadForm", width: 300,
        dataSource: mediaLibrary,
        fields: [
            { name: "title", required: true },
            { name: "image", type: "imageFile", hint: "Maximum file size is 5 MiB" },
            { title: "Save", type: "button", 
                click: function () {
                    this.form.saveData("if(dsResponse.status>=0) uploadForm.editNewRecord()");
                }
            }
        ]
    });
    
    isc.ListGrid.create({
        autoDraw: false,
        ID: "mediaListGrid",
        width: "100%",
        height: 224,
        alternateRecordStyles: true,
        dataSource: mediaLibrary,
        canRemoveRecords: true,
        autoFetchData: true
    });
    
    isc.Img.create({
        ID: "img1",
        src: mediaLibrary.getFileURL(1),
        imageHeight: 150,
        imageWidth: 150
    });
    
    isc.Img.create({
        ID: "img2",
        src: mediaLibrary.getFileURL(2),
        size: 150,
    });
    
    isc.VLayout.create({
        autoDraw: false,
        ID:"imgLayout",
        width:"100%",
        height:190,
        padding: 50,
        members:[img1, img2]
    });
    
    isc.VLayout.create({
        autoDraw: false,
        ID:"mainLayout",
        width:500,
        height:250,
        members:[mediaListGrid, imgLayout]
    });
    
    isc.HStack.create({
        width:"100%",
        membersMargin: 10,
        members:[uploadForm, mainLayout]
    });
    For me in my application, the image does not display, but is shown as broken in the browser. In the developer console the request looks good as viewFile: status:CLEARED, like it does in the sample for [img1, img2].
    On "right click"->"Show in new Tab" the image is displayed in the new tab like expected. Any idea why this is?

    Best regards
    Blama

    #2
    Hi Isomorphic,

    this turns out to be somehow SmartGWT related. Please see this testcase (tested in FF26 Dev Mode, happens in my application also in compiled mode in FF26/GC66):

    BuiltInDS.java:
    Code:
    package com.smartgwt.sample.client;
    
    import com.google.gwt.core.client.EntryPoint;
    import com.smartgwt.client.Version;
    import com.smartgwt.client.core.KeyIdentifier;
    import com.smartgwt.client.data.DataSource;
    import com.smartgwt.client.data.Record;
    import com.smartgwt.client.util.Page;
    import com.smartgwt.client.util.PageKeyHandler;
    import com.smartgwt.client.util.SC;
    import com.smartgwt.client.widgets.IButton;
    import com.smartgwt.client.widgets.Img;
    import com.smartgwt.client.widgets.Label;
    import com.smartgwt.client.widgets.Window;
    import com.smartgwt.client.widgets.events.ClickEvent;
    import com.smartgwt.client.widgets.events.ClickHandler;
    import com.smartgwt.client.widgets.layout.VLayout;
    
    public class BuiltInDS extends VLayout implements EntryPoint {
        private IButton recreateBtn;
        final private DataSource tAttachment = DataSource.get("T_ATTACHMENT");
    
        public void onModuleLoad() {
            KeyIdentifier debugKey = new KeyIdentifier();
            debugKey.setCtrlKey(true);
            debugKey.setKeyName("D");
    
            Page.registerKey(debugKey, new PageKeyHandler() {
                public void execute(String keyName) {
                    SC.showConsole();
                }
            });
    
            setWidth100();
            setHeight100();
    
            recreateBtn = new IButton("Recreate");
            recreateBtn.addClickHandler(new ClickHandler() {
                @Override
                public void onClick(ClickEvent event) {
                    new MyWindow().show();
                }
            });
            addMember(recreateBtn);
            new MyWindow().show();
            draw();
        }
    
        private class MyWindow extends Window {
            public MyWindow() {
                setWidth(400);
                setHeight(600);
                setTitle("Problem with SVG image from DB (" + Version.getVersion() + "/" + Version.getSCVersionNumber() + ")");
                setShowMinimizeButton(false);
                setIsModal(true);
                setShowModalMask(true);
                centerInPage();
    
                final Label l1 = new Label("SVG");
                VLayout svgVLayout = new VLayout(5) {
                    {
                        final Record r = new Record();
                        r.setAttribute("ID", 1);
                        final Img svgImg = new Img(tAttachment.getFileURL(r), 150, 150);
                        svgImg.setTitle("SVG img");
    
                        setMembers(l1, svgImg);
                    }
                };
                addItem(svgVLayout);
    
                final Label l2 = new Label("PNG");
                VLayout pngVLayout = new VLayout(5) {
                    {
                        final Record r = new Record();
                        r.setAttribute("ID", 2);
                        final Img pngImg = new Img(tAttachment.getFileURL(r), 150, 150);
                        pngImg.setTitle("PNG img");
    
                        setMembers(l2, pngImg);
                    }
                };
                addItem(pngVLayout);
            }
        }
    }
    (Adjust IDs to match the PK value in your table)

    T_ATTACHMENT.ds.xml (add it in BuiltInDS.html and also add ojdbc6.jar, if you are using Oracle):
    Code:
    <DataSource dbName="Oracle" tableName="T_ATTACHMENT" ID="T_ATTACHMENT" serverType="sql">
        <fields>
            <field primaryKey="true" hidden="true" name="ID" type="sequence" />
            <field name="TITLE" type="text" length="100" required="true" />
            <field name="DATA" type="imageFile" required="true" maxFileSize="2097152" />
            <field name="DATA_FILENAME" length="255" type="text" hidden="true" required="true" />
            <field name="DATA_FILESIZE" type="integer" required="true" />
            <field name="DATA_DATE_CREATED" ignore="true" type="datetime" />
        </fields>
    </DataSource>
    Best regards
    Blama

    Comment


      #3
      Most likely this is caused by different servers returning different mime-types for SVG files, and whatever browser you are testing with is being picky about not receiving the mime-type in prefers.

      You can verify this by just looking at the HTTP headers returned with the SVG file.

      Mime types are configured differently in different servers, eg, in Tomcat they are listed out in web.xml.

      Comment


        #4
        Hi Isomorphic,

        I don't think this is the reason. I tested with the SmartClient showcase locally deployed and the BuiltInDS-based SmartGWT sample from #2 on the same Tomcat on the same machine.
        Also, "rightclick"->"open image in new window" does work as expected. It also happend in both FF26 and GC66. But I will test other browsers as well.
        Can you try the SmartGWT testcase from #2 with current 6.1p?

        Regarding MIME Types. This is your generic IDACall-viewFile servlet, so I'm pretty sure that if there is a MIME type set, you control it. It's NOT a static file from the directory structure.
        As notice: The MIME-Type returned from the (working) online showcase is svg+xml. I'll test where it is not working tomorrow in the office.

        Best regards
        Blama

        Comment


          #5
          We look up mime types by asking the servlet container. That's the standard way to do it.

          Let us know about the non-working environment, we're pretty sure this is the cause.

          Comment


            #6
            Hi Isomorphic,

            thanks. You were right about the resason (at least I assume so). This page shows it in clear words :)
            I did try the following:

            I now did set this in my application's web.xml (it is already in Tomcat's conf/web.xml) with no change:
            Code:
                <mime-mapping>
                    <extension>svg</extension>
                    <mime-type>image/svg+xml</mime-type>
                </mime-mapping>
            Setting this in my application's web.xml with the effect that all static images *.svg are served with this (wrong) header. So I'm sure the setting itself is used by Tomcat.
            Code:
                <mime-mapping>
                    <extension>svg</extension>
                    <mime-type>document/text+xml</mime-type>
                </mime-mapping>
            My question now is: How do you do this:
            Originally posted by Isomorphic View Post
            We look up mime types by asking the servlet container. That's the standard way to do it.
            Because it seems that the setting in either my application's web.xml or Tomcat's conf/web.xml is not sufficient for the framework to notice, as the header of the IDACall-viewFile response is always "text/xml", regardless of the used <mime-mapping> that does effect the static .svg files.
            The filename in the database is pretty simple and ends in ".svg".

            Best regards
            Blama

            Comment


              #7
              We use the standard approach: servletContext.getMimeType(). Get that API returning the right value and you should be all set.

              Comment


                #8
                Hi Isomorphic,

                that API is already returning the correct MIME Type, but I found the issue.
                I noticed that the Response headers for your showcase are like this:

                Click image for larger version

Name:	Headers.PNG
Views:	95
Size:	5.8 KB
ID:	253378

                This is not the case for my testcase, where the meta data is missing completely.
                The difference is that you don't have this in your .ds.xml.

                Code:
                <field name="DATA_FILENAME" length="255" type="text" hidden="true" required="true" />
                <field name="DATA_FILESIZE" type="integer" required="true" />
                <field name="DATA_DATE_CREATED" ignore="true" type="datetime" />
                I do, because I want to show this meta data in the GUI and need those fields as fields in my .ds.xml to control title, required etc. (field list excerpt):
                Code:
                    <fields>
                        <field primaryKey="true" hidden="true" name="ID" type="sequence" />
                
                ...
                        <field name="CREATED_AT" type="creatorTimestamp">
                            <title><fmt:message key="addedAt" /></title>
                        </field>
                
                ...
                        <field name="TITLE" type="text" length="100" required="true">
                            <title><fmt:message key="title" /></title>
                        </field>
                        <field name="DATA" type="binary" required="true" maxFileSize="2097152">
                            <title><fmt:message key="file" /></title>
                        </field>
                        <field name="DATA_FILENAME" length="255" type="text" hidden="true" required="true" />
                        <field name="DATA_FILESIZE" type="integer" required="true">
                            <title><fmt:message key="fileSize" /></title>
                        </field>
                        <field name="DATA_DATE_CREATED" ignore="true" type="datetime" /> <!-- not needed because of CREATED_AT with type creatorTimestamp -->
                Somewhere in your code you must have an if that only sets content headers like you describe, if those fields are not in the .ds.xml, but your default ones.
                I'm pretty sure that if you just add those three data_* fields to the showcase sample, you will notice the problem as well.

                This are the headers in my testcase without (good) and with (bad) those fields:
                Good:
                Click image for larger version

Name:	Headers_good.PNG
Views:	119
Size:	6.9 KB
ID:	253380

                Bad:
                Click image for larger version

Name:	Headers_bad.PNG
Views:	75
Size:	8.9 KB
ID:	253379


                Best regards
                Blama

                Comment


                  #9
                  See "Binary Fields" overview - you can explicitly declare the metadata fields such as _filename if you like (as you have), but the suffix is "_filename" whereas you have "_FILENAME".

                  Comment


                    #10
                    Hi Isomorphic,

                    OK, I'll try again tomorrow. The devil is in the details.

                    Best regards
                    Blama

                    Comment


                      #11
                      Hi Isomorphic,

                      this seems to solve the issue. Thank you.

                      Best regards
                      Blama

                      Comment

                      Working...
                      X