0
votes

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);
1
There are multiple formats, even within JPG, not to mention compression and color format. Reading an image via a stream will be a major undertaking to support those different formats. Which platform(s) do you intend to target?Jerry Dodge
@JerryDodge For now Desktop but i hope to target android after this, i even have a working prototype which works with normal mangas which have small images and yes indeed reading via stream will be a very hard thing to do which is why i am looking for a better way!, by the way, what do think about loading the image into a stream, and then drawing it manually ?, is this possible ?ali ahmadi
Sure, it's possible. But that's the same thing that I just described - you'd need to parse it and interpret everything yourself. Start by studying JPG specifications. Or continue searching for a third-party library.Jerry Dodge
you can use imagemagick (imagemagick.org) that support tera pixels :) for using it in delphi, you can take a look at github.com/Zeus64/alcinoezeus
Also, you can look at OpenGL libraries to paint image on any canvas.Pavel Minenkov

1 Answers

0
votes

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