0

We have a binary file on client. It's scaned page from book which come to client somehow compressed. We have a decoder(on client), which output a TypedArray which contains BMP data file. We need to render it, as fast as possible. BMP size is about 3000000 bytes(after decoding, it's length of returned typedArray). We tried a lot of solutions but on slow PCs it didn't work. For example fastest way which we found: We build blob from TypedArray. Create URL to this blob and specify it as src attribute on image source. It tooks about 22000ms to render 20 pages. Also we tried to render it in base64 with data: URL specified in src tag also(34000ms). We tried to render it on canvas. But there are problems such as we use drawImage on canvas which require loaded image object. May be some how we can render it with WebGL with hardware acceleration?

PS In the time included decode time which are the same in all cases.

PS I can attach code samples which we tried.

Sukhanov Niсkolay
  • 1,298
  • 1
  • 12
  • 26
  • If the file is that big and you want to load it entirely I don't think there's much to do. Perhaps you could try to change approach to the problem with something like [Zoomify](https://github.com/turban/Leaflet.Zoomify) – MarcoL Feb 19 '14 at 13:54
  • Black and white pages. I'm not sure about color data, but can check bmp header if it very important. – Sukhanov Niсkolay Feb 19 '14 at 14:31
  • MarcoCI, Perhaps i can rebuild it with low resolution? But i afraid that it will be too slow. Because we need to do all stuff on client. – Sukhanov Niсkolay Feb 19 '14 at 14:33

2 Answers2

2

The Laws of Physics always apply:

Large Images take longer to download than small images.

As a workaround, how about the "old-fashioned" approach.

Intially show a "lossy" version of your book page (a small .jpg perhaps).

var imgJPG=new Image();
imgJPG.onload=start;
imgJPG.src="yourBookPage.JPG";

function start(){
    context.drawImage(imgJPG,0,0);
}

At the same time begin an asynchronous download of your large .bmp

var imgPNG=new Image();
imgPNG.onload=start;
imgPNG.src="yourBookPage.bmp";

When the large image is fully loaded, replace the .jpg image with the .bmp image

function start(){
    context.clearRect(0,0,canvas.width,canvas.height);
    context.drawImage(imgPNG,0,0);
}

If the user is adding drawings before the .bmp is loaded, you can let them draw on a separate canvas directly on top of the .jpg canvas. Then when the .bmp is loaded you can combine the existing drawings on top of the newly loaded .bmp

context.clearRect(0,0,canvas.width,canvas.height);

// draw the .png in the background

context.drawImage(imgPNG,0,0);

// add any user drawings on top

context.drawImage(theTempDrawingCanvasWithManyUserDrawings,0,0);

Good luck with your project!

markE
  • 102,905
  • 11
  • 164
  • 176
  • I don't need download file. It already downloaded(rendered on client in Blob, the problem is how fast render it). In your example you use drawImage on canvas. There are several issues which we find. (Bad working resize, we need to wait for load img object anyway etc) May be we can append img in DOM? Why we should use drawImage? Is it faster? whithout rendering in canvas? And i want to add we already have BMP in Blob object. We don't need to download it, because we download in some specific format, and decode it on client machine in Blob. – Sukhanov Niсkolay Feb 19 '14 at 21:36
  • But your answer was very helpful anyway! so votes up. – Sukhanov Niсkolay Feb 19 '14 at 21:39
  • The image format which came to client is DJVU chunk, we decode it in BMP via javascript on client machine in browser. So there are no problems in network. We tried specified src as data:uri. And many other ways such as you proposed. But this method requires to encode BMP in base64 which takes time. Your requires image object loading. The question is that maybe exist some methods to draw image faster? For example in canvas without load img object?(which of course took some memory) – Sukhanov Niсkolay Feb 19 '14 at 21:42
2

I'm not sure what you mean by BMP file until you mean the Microsoft BMP format.

I don't know all the details of that format but if you're decoding it by hand into pixels in JavaScript you can display the decoded data directly by uploading it to a texture in WebGL and then rendering a quad with the texture.

There are example all over the net about how to render a textured quad in WebGL. Here's one

You'd upload your data to a texture with

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 
              widthOfImageInPixels, heightOfImagePixels, 0
              gl.RGBA, gl.UNSIGNED_BYTE, someUint8ArrayWithWidthByHeightPixels);

Note that if your pixels are not RGB or RGBA, like a say they are YUV or something you can create a shader to display them directly rather than convert them in JavaScript to RGB/RGBA

Community
  • 1
  • 1
gman
  • 100,619
  • 31
  • 269
  • 393