Friday, December 9, 2016

photos - select, display, store thumbnail

December 11, 2016 - optimized code with closure and additional file information

There are some steps necessary to present and store pictures in the diary with browser or app:
  • select pictures from file system - FileReader HTML5 is necessary to select pictures
  • create thumbnail, crop the thumbnail image and create base64 string for this compressed or reduced picture - crop is necessary because thumbnail is an optical effect and not a compression of the data of the picture - canvas HTML5 is necessary for this function
  • show the thumbnail to the user - plain HTML with base64 string as image src
  • store the thumbnail in the database - plain base64 string
  • retrieve the thumbnail from the database and show it again - base64 string is image src again

The best way to select pictures from the file system I found in http://stackoverflow.com/questions/27254735/filereader-onload-with-result-and-parameter and the fiddle http://jsfiddle.net/sahilbatla/hjk3u2ee/ - the code uses closures. You get a clean loop on the files and processing the files is easy. But jshint still marks the function in the closure, because it's in a loop, although it's save.

FileReader is not available on Safari under Windows 10.
Photos are an important part for a diary. In
http://codepedia.info/editor-example/preview-image-before-upload-jquery-example/ there is an introduction with sample code for using HTML5 for file upload.

The images are displayed as thumbnail.


The corresponding html-source shows that the image is referenced with 

<img src="data:image/jpeg;base64,<base64-String>>

And this is a very good opportunitiy to upload the picture to the server or the local database.

https://github.com/nodeca/pica seems to be a good approach but the solution is large regarding the code that has to be downloaded to the client. Under node.js that would not be a problem.

Based on canvas creating a thumbnail is easy and efficient:

http://stackoverflow.com/questions/15990946/resize-image-before-upload-convert-canvas-to-a-file-object gives some background
http://jsfiddle.net/cL3hapL4/2/ shows how to do it, you can easily add some try catch block structure - just in case there is an old browser
http://stackoverflow.com/questions/15685698/getting-binary-base64-data-from-html5-canvas-readasbinarystring shows canvas.toDataURL("image/jpeg"); which will save the reduced photo.

The base64 String still has some size, so compression can be the next step.

http://pieroxy.net/blog/pages/lz-string/demo.html is a very good solution for compression, but then you have a blob - which can cause a lot of problems when store to a client database, see https://github.com/nolanlawson/state-of-binary-data-in-the-browser

My solution:

  • HTML5 FileReader is used to select pictures from the local storage
  • html img is used to show the picture, src comes from the FileReader as base64-String
  • canvas is used to create and save the thumbnail
    • getContext("2d");
    • drawImage
    • toDataURL("image/jpeg", 0.50); - uses the quality downsizing
The resulting base64-String from toDataURL is impressingly small.

http://stackoverflow.com/questions/28538913/crop-an-image-displayed-in-a-canvas shows a simple solution to crop with canvas. For the resizing with canvas the canvas has to be set to the target width and height, before the resize is done, then everythin works fine - code to come
http://stackoverflow.com/questions/27254735/filereader-onload-with-result-and-parameter shows how the inner function in the loop over the the imagefiles can be formulated as closures, then jshint will no longer put a mark on it.

No comments:

Post a Comment