Skip to Content

Invoices, Receipts, Images: Large files everywhere! We as developers and users probably all know it and struggle almost daily with the upload of way too big files resulting in awful performance.

So I tried finding a solution for this scaling problem and decided to take it to the UI5Lab which has been announced at the last UI5Con. The UI5Lab project initially came with a few controls from community members and I already contributed with an initial version of the nabi.m.PDFViewer as part of the nabi.m library. There was a little hype around UI5Lab as people talked about finally “having a place for community stuff”, and people talked about adding own controls. Now the UI5Con is over and it’s time to “walk the talk”: In this Blog I’d like to show you why the scaling of images is so important and how to do it before uploading them to the server.

Let’s start with the“Why” from which we can easily derive our requirements.

 

From the Use Case to the Requirements

Let’s assume your company has a large sales force. Your sales representatives travel a lot and they have expenses which they want to get refunded. To get their expenses refunded they have to report their travels including expenses. When it comes to expenses, the sales reps need to upload invoices. This also means they either scan the original invoices or take pictures of them. Furthermore, they might want to report their travels and expenses using any kind of device; be it desktop, smartphone, or tablet. Let’s only focus on uploading the expenses. When taking pictures using modern devices the resulting image files might be quite large, maybe 4 MB – 10 MB or even more (we can’t be sure of the exact size and we can’t prescribe the size). When using a scanner for scanning documents to image files (i.e JPEG) we might have the same issue again – large files everywhere. Furthermore, sometimes users scan documents to PDF instead of scanning them to JPEGs. Of course, we don’t want to waste the time of our company’s support team to explain the users how to configure their particular scanner in order to scan to JPEGs instead of scanning to PDFs. Additionally, sometimes the users even receive invoices per email and already as PDF. Thus, we need to allow PDF files to be uploaded, too. Now let’s assume a user took pictures of 10 invoices using the smartphone, each of them resulting in JPEG files of 10 MB. Next, they want to attach them to their travel report. If we as developers would not care much, then we would simply allow the user to upload the 100 MB (believe me, I have seen developers with this approach). Of course, this has some major disadvantages. For example, uploading 100 MB takes some time, the user acceptance of the app heavily decreases because of the performance, 100 MB over network will “bind” resources on server side, on mobile networks the free data volumes might decrease (depends on data plan), etc.

Typically, you don’t want to always scale down images. Furthermore, you might want to decide how to scale the images. In other words: we need to define “when” and “how” images are scaled down. Here are a few questions to give you an idea why this is important:

  • Would you scale down images in case their initial size is 0.5 MB?
  • And would you scale down images having a resolution of 1024×768?
  • Or would you simply always scale down?
  • Maybe using a factor, i.e. scale down by 50%?
  • Or maybe by specifying a target resolution, i.e. 1024×768?

Answering these questions most probably depends on your own use case. Thus, we need a control that supports such requirements. It must be flexible enough to support your use cases, too.

Hint: The term “resolution” is often referred to as for example “pixels per inch” or “dots per inch (DPI)”. Instead, we use this term in a more pragmatic way, i.e. it simply means width x height in pixels (similar to your monitor’s resolution).

 

Just for the log (and what we will neglect completely in this blog):


When it comes to Travel Reporting you have to think about legal stuff, too. For example, the invoices received must be archived. Space in an archive system/tool can be expensive. Thus, decreasing the file sizes somehow could positively influence the costs. Furthermore, you should check if it’s legally fine to scale down images (i.e. the invoices). When it comes to scaling images down we could also implement the down scaling on the backend instead of scaling down images on the frontend. But that would not solve the issue of sending too many bytes over the wire from the client to the server – another reason for doing this on the frontend.

 

Solution: the new control nabi.m.ImageFileUploader


In case of image files, we want to scale down the images so that each image gets much smaller before they get uploaded. We can save 80-90% of bytes transferred over the wire this way! Sure, it has to work on any browser and device supported by SAPUI5. And again, uploading PDFs should work seamlessly, too. My new nabi.m.ImageFileUploader control gives you what you need. The required features mentioned above are exposed with a fairly simple API (hopefully), and the control can be seen as an in-place replacement of the sap.ui.unified.FileUploader as it is a (more or less) simple sub-control.

 

Using the nabi.m.ImageFileUploader control

The new control nabi.m.ImageFileUploader extends the sap.ui.unified.FileUploader control shipped with UI5. Currently, the nabi.m.ImageFileUploader uses private APIs of sap.ui.unified.FileUploader which is a very bad practice (see all “fixme” hints in this control’s code). However, this was the easiest/fastest way to leverage from the amazing code that already exists (think about the renderer incl. not losing file input values on re-rendering, i18n, accessibility, parameters, OData support,…). As soon as SAP offers a clean way for overwriting the right methods (public APIs, interface, …) I will migrate this control. In fact, I have a suggestion, see my pull request on Github at https://github.com/SAP/openui5/pull/1623. As long as the pull request is not accepted make sure to test this control with your version of UI5 (and yes, I will write some automated tests soon) – and do that every time you upgrade your UI5 version! The following astah UML diagram shows what properties are added (for simplicity only relevant properties/methods are listed). Together with the comments/jsdoc in the code this should help you understand the details of my implementation (I want to keep this blog short).

 

 

The nabi.m library contains 8 examples giving you some ideas of how to use the APIs of nabi.m.ImageFileUploader (in the UI5Lab Browser or the docs page for the control) I hope the usage itself is simple enough, see examples in the library. And here is a little appetizer:

The default scaleType is nabi.m.ImageScaleType.Factor (“Factor”). This simple example uses a scaleFactor of 0.5, meaning the image will be scaled down by 50%. You know most of the properties from the sap.ui.unified.FileUploader, here is the code that scales the image before it gets uploaded:

 

var oImageFileUploader = new nabi.m.ImageFileUploader({
    scaleFactor : 0.5,
    uploadUrl: "{/uploadUri}",
    uploadOnChange : true,
    uploadComplete : function (oEvent) {
        var sStatus = oEvent.getParameter("status");
        if (sStatus === 200) {
            sMsg = "Return Code: 200 ";
            oEvent.getSource().setValue("");
        } else {
            sMsg = "Error Code: " + sStatus;
        }
        sap.m.MessageToast.show(sMsg);
    }
});
oImageFileUploader.placeAt("content");

 

Behind the Scenes

The magic happens behind the scenes with plain old JavaScript / HTML5. However, files are uploaded using FormData and XHR. Scaling of the files is based on HTML5 Canvas and the File API (window.File). As you can guess this means that the control is not supported by Internet Explorer 9. That’s ok, because officially SAPUI5 does not support IE 9 anymore anyway. In fact, currently SAPUI5 officially supports IE11+ and thus I have no pain not supporting IE9 :-).

Using HTML5 Canvas for scaling images down (“down sampling”) comes in pretty handy for us as we don’t have to deal with all the math; instead we let the browser handle the process of down sampling for us. Down sampling means “decreasing the pixel number (scaling down), and this usually results in a visible quality loss” (Wikipedia). Using HTML5 Canvas might not always be the best option in terms of quality. However, it might be enough for lots of use cases. In future, I might introduce an API allowing you to use something different than HTML5 Canvas, i.e. your own down sampling algorithm (Wikipedia).

 

Summary

Using my new control allows you to scale images down before you upload them. It does not rely on any plugins, and it works even without Cordova. The control’s docs file lists a few ideas for the future.

Wanna try out the ImageFileUploader yourself? Follow the instructions (same as for any UI5Lab control library) and open the browser on localhost afterwards:

git clone https://github.com/nzamani/ui5-nabi-m

cd ui5-nabi-m

npm install

npm start

 

Do you have a better idea or know how to improve the control? Feel free to send me some pull requests! Any feedback is welcome.

Do you have an idea for a useful control? Let me know by opening an issue

 

Previous Post: UI5ers Buzz #11

Next Post: UI5ers Buzz #13

 

Cheers, Nabi

Nabi is a Software Engineer running a small Technology Consulting in Mannheim. His background is LEAN/Agile, Java, ABAP, JavaScript, Web and related technologies. Having worked with UI5 since 2011 he loves both its major competitors and UI5 itself. He wrote his first blogs around 2009, mostly about Java and Web development reaching thousands of developers, before he added UI5 tutorials and blogs. For him, SAPUI5 is like good Italian food – once you try it you want to have more. And he loves both Italian food and UI5.

 

 

 

To report this post you need to login first.

1 Comment

You must be Logged on to comment or reply to a post.

  1. Nabi Zamani Post author

    The Pull Request 1623 mentioned above was merged with change 6d4bce0

    This means nabi.m.ImageFileUploader is now using public APIs for SAPUI5/OpenUI5 1.52. For older versions of UI5 a quirk which uses private APIs has been implemented. In other words: you should be able to use nabi.m.ImageFileUploader for UI5 version >= 1.44.x (I did not test with versions before 1.44.x).

    (0) 

Leave a Reply