Search code examples
imagedelphibitmapfiremonkey

How to load large bitmap in FMX (fire monkey)


I am trying to create a Manga viewer which needs to load JPG images with large sizes like 1000*16000, my application is in delphi FMX and i have already tried using TImage, TImageViewer, TImageControl but all of them use TBitmap which trims the size to 8192 after loading the image
I tried searching for image libraries but i was unable to find anything for FMX (firemonkey)
I was thinking maybe i could load the image in a Memory stream and then copy and draw it in smaller sizes to several bitmaps ? but i don't how can i read and parse the memory stream and only pick to a certain clean height !
In the end i'm looking for a way to load and show these large (1000*16000) images in Delphi FMX
I am using delphi 10.2.3
Thanks.

Edit 01 :
I think i have found a way that might make things easy, i added the Vcl.Imaging.jpeg to uses clause in the FMX (FireMonkey) and then i used TJPEGImage and loaded the image, and i printed the width and height and they are correct and not trimmed ! so i was thinking, maybe i can read each pixel from TJPEGImage.canvas and then print it into FMX TBitmap ?, what do you think about this approach ?, do you know a good way to copy the data inside TJPEGImage to FMX TBitmap ?

Edit 02 :
I have found a new solution, the TBitmapSurface, it seems this class doesn't have the TBitmap limitations and i was able to load the image inside of it without getting trimmed ! but there is a problem! how can i give this to TImage ? if i simply say Image.bitmap.assign(TBitmapsurface), then the image gets trimmed again ! so it seems the only possible way is rewriting the TImage so it uses TBitmapSurface instead of TBitmap, any help regarding this issue is appreciated, thanks.
Here is the code for the TBitmapSurface :

bitmapSurf := TBitmapSurface.Create;
TBitmapCodecManager.LoadFromFile(path, bitmapSurf);

Solution

  • Unlike FMX.Graphics.TBitmap which has a size limitations of 8192 * 8192, FMX.Surface.TBitmapSurface seems to support up to 16k * 16k and possibly even more (i haven't tested), so using FMX.Surface.TBitmapSurface you can load the image without getting trimmed, and then you can easily split it into two FMX.Graphics.TBitmap (or possible more parts using the same approach)
    Below you can see the code which first loads the JPG into TBitmapSurface, and then the code which splits that into two TBitmap :

    var
      srce, dest: TBitmapSurface;
      path: string;
      scan: integer;
      w, h1, h2: integer;
    begin
      path := 'C:\tmp\Imgs\res.bmp';
      srce := TBitmapSurface.Create;
      TBitmapCodecManager.LoadFromFile(path, srce); 
    
      dest := TBitmapSurface.Create;
    
      // first half
      w := srce.Width;
      h1 := srce.Height div 2;
      dest.SetSize(w, h1, TPixelFormat.RGBA);
      for scan := 0 to h1-1 do
        Move(srce.Scanline[scan]^, TBitmapSurface(dest).Scanline[scan]^, srce.Width * 4);
      Image1.Bitmap.Assign(dest); 
    
      // second half
      h2 := srce.Height - h1;
      dest.SetSize(w, h2, TPixelFormat.RGBA);
      for scan := h1 to srce.Height-1 do
        Move(srce.Scanline[scan]^, TBitmapSurface(dest).Scanline[scan-h1]^, srce.Width * 4);
      Image2.Bitmap.Assign(dest);
    
    end;  
    

    This answer was provided using the comments on the first post and the answer to my other question:
    How to draw FMX.Surface.TBitmapSurface on FMX.Graphics.TBitmap