Fast loading of images lazarus / 39-Graphics ---------------------------------------------------------------------- phoenix27 · 2023-04-12 05:23 I made a program with electron which basically loads full images(50 per page but the number can be changed), then resizes them on the fly to fill the div container and shows them. It's pretty fast. Now i decided to make the same program with Lazarus and free pascal because i like wirthian languages, so different from the others, also compiled apps feel more personal and also because i always tend to go against the crowd. The problem is that it's too slow when loading and resizing the images. Why is a compiled program slower than javascript!! Anyway the code i use to load the images is basically this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure loadImages(images: ImageCollection);var   bmpDst: TBitmap;   rsrc, rdst: TRect;   img: imageRecord;    i: integer;begin  for i=0 to length(images) - 1 do  begin     img:= images[i];     pic := TPicture.create;     pic.LoadFromFile(img.thumbAbsPath);     //for resizing      bmpDst := TBitmap.Create;      bmpDst.Width := img.width;//width and height are the resized dimensions of the image, calculated in advance      bmpDst.Height:= img.height;      rdst:= Rect(0, 0, bmpDst.width, bmpDst.height);      rsrc := Rect(0, 0, pic.bitmap.Width, pic.bitmap.Height);      bmpDst.canvas.CopyRect(rdst, pic.bitmap.canvas, rsrc);      pic.free;  end   paintBox.invalidate();end;//then in the paintBox  OnPaint event handler i draw all the saved bmpDst  bmpDst.Draw(paintBox.Canvas, Bounds(img.left, img.top, img.width, img.height)); If the images are large in size it becomes even slower. What can i do to improve the performance? Is there a library which is fast for these things? Or there is something already there that i dont know about? I started programming in pascal just some weeks ago so i'm not an expert by any stretch of imagination . The thing that bothers me the most is that electron and javascript are fast and pascal, a compiled language is not I don't want to resize the images and save them on the disc. I want to do it on the fly and with an acceptable speed. Some Pascal expert can tell me how? ---------------------------------------------------------------------- domasz · 2023-04-12 07:58 In your Electron app you use BMP, PNG or JPEG? PNG and JPEG are smaller. While they need more CPU power to decode than BMP images they can be loaded from HDD/SSD a lot quicker. IF you use PNG/JPEG in Electron then use the same format in Lazarus. Your Electron app used multi threading and your app doesn't. If your processor has 8 cores than Electron can decode images 8 times quicker. You should use threads in your Lazarus app. ---------------------------------------------------------------------- balazsszekely · 2023-04-12 08:08 QuoteThe thing that bothers me the most is that electron and javascript are fast and pascal, a compiled language is notIt's not about the language, electron and javascript gets a lot of attention lately, pascal not so much. Probably somebody wrote a fast image processing library for javascript. With that said, your pascal code is far from optimal. You recreate Pic on each iteration, you only use a single thread, more over Bimtap.Canvas operations are notoriously slow. You should switch to BGRABitmap or other component. ---------------------------------------------------------------------- phoenix27 · 2023-04-12 08:53 @domasz They are exactly the same images, all JPEG.  Only in electron they show up almost instantly while in Pascal i have to wait about 10 seconds to see those 50 images. I feel like javascript is just  the scripting language of the real deal, chrome engine, just like i dont know, Lua is the scripting language of a c++ game. Thats why i dont like web programming so much. I want MY app. Not an app that runs within a bigger app( although an Operating System could be seen as a bigger app too, but thats a bit different). Before electron i made the same app as a web server in nodejs( which is again google v8 engine) and firefox as  the client and the same pictures showed up fast. @GetMem Yes i tried BGRABitmap  like this Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i pic := TBGRABitmap.Create(img.thumbAbsPath);//to resize i didBGRAReplace(pic, pic.Resample(img.width, img.height, rmSimpleStretch)); But that too is slow.  I tried also to just load the visible part of the canvas, and thats better; then i put a timer to load the rest and it  slowed things down again because  after all the loading happens in the same thread. I tried to use the TWCThread component to load the pictures in another thread. But i dont know how to pass the pictures in the new thread(it expect a variant type, but i don't think you can pass whatever value). Also i read that the LCL isn't thread safe so i cannot use TBitmap and all the other classes. So how am i supposed to load and resize those images? Threads seem a complicated business and i'm just an amateur programmer. Some practical solutions would really be appreciated. ---------------------------------------------------------------------- phoenix27 · 2023-04-12 09:08 My strategy wold be this: I load only the visible part of the canvas and at the same time i spawn some threads to resize the rest of the images. But i would like to know, how can i pass an image and the new size to the new thread and once in there can i use the Tbitmap, TPicture classes to load and do the resizing and then pass back the result? How can i do that? Somebody can post some code? ---------------------------------------------------------------------- wp · 2023-04-12 09:40 If you are mainly interested in thumbnails check out theos thumbnail viewer; it uses multiple threads for loading. (https://github.com/theo222/lazarus-thumbviewer). In case of jpg and thumbnail generation, use the "Scale" property of TJpegImage (jsHalf, jsQuarter, jsEighth); the loading time decreases accordingly. There is also a Performance property which, if set to jpBestSpeed, gets you another about 50% speed gain. See attached demo (it loads the lazarus cheetah by default which is quite small; use a larger image to better see the differences). Use a fast jpeg reading library. I once worked with Intel's IJL library and found it to be much faster than the standard JPG reader that comes with FPC (it's no longer supported and Windows only, though). There are others but I never worked with them. Create a cache of scaled images that already have been loaded. ---------------------------------------------------------------------- SymbolicFrank · 2023-04-12 10:13 Another thing is, that the pictures are completely processed before they're displayed, while in the browser you first get a blocky, low- res image, that becomes sharper the more it is processed. ---------------------------------------------------------------------- marcov · 2023-04-12 10:31 Maybe first time what the bulk of the delay is. E.g. by first loading 50 images and only then drawing them all fifty with copyrect and finally the stretchdraw and timing all those three stages. My money is on the stretchdraw, the default Windows canvas (GDI) is simply not the fastest, which is why I converted to using Opengl in my image related programs. ---------------------------------------------------------------------- phoenix27 · 2023-04-12 14:43 @wp i had already tried theos thumb viewer, yes its quite fast at processing but then when i had all the images on the canvas scrolling up and down was painfully slow As  for the TJpegImage i tried your code and works well, but  in my case it always crashes on the line: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i jped := TJpegImage.create I dont know why. I did read a tutorial on multithreading and came out with this solution. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Type  TGiveMediaEvent = procedure(bitmap: TBitmap; idx: integer) of Object;  TMyThread = class(TThread)  private    FOnGetNewMedia: TGiveMediaEvent;    mi: MediaInfo;    bmp: TBitmap;    _midx: integer;    procedure getNewMedia;  protected    procedure Execute; override;  public  Constructor Create(CreateSuspended : boolean);  property OnGetNewMedia: TGiveMediaEvent read FOnGetNewMedia write FOnGetNewMedia;  property media: MediaInfo read mi write mi;  property Bitmp: TBitmap read bmp write bmp;  property midx: integer read _midx write _midx;end;constructor TMyThread.Create(CreateSuspended : boolean); begin   inherited Create(CreateSuspended);   FreeOnTerminate := True;   mi:= nil;   bmp := nil; end;  procedure TMyThread.GetNewMedia;  begin   if Assigned(FOnGetNewMedia) then   begin     FOnGetNewMedia(bmp, midx);   end; end;  procedure TMyThread.Execute; var   pic: TBGRABitmap; begin   Synchronize(@GetNewMedia);   while (not Terminated) and (mi <> nil) do     begin       try       pic := TBGRABitmap.Create(mi.thumbAbsPath);       BGRAReplace(pic, pic.Resample(mi.width, mi.height, rmSimpleStretch));       bmp := pic.bitmap;       except          pic := TBGRABitmap.Create('imgs/image_error.jpg');          BGRAReplace(pic, pic.Resample(mi.width, mi.height, rmSimpleStretch));          bmp := pic.bitmap;       end;       Synchronize(@GetNewMedia); //stops until the main thread called the method within syncronize     end; end;    #then in the app, n the form private sectionprivate  myThread: TMyThread;  procedure giveNewMedia(bmp: TBitmap; idx: integer);public ...# and in the implementation procedure TfrmMediaStore.giveNewMedia(bmp: TBitmap; idx: integer);  var pb: MediaCanvas; begin    pb:= getActiveCanvas();    if midx < length(pb.marr) then    begin       myThread.media:= pb.marr[midx];     myThread.midx:= midx;       inc(midx);    end    else       myThread.media:= nil;    if bmp <> nil then    begin     pb.bitmaps[idx] := bmp;     pb.invalidate;    end;  end;   #and in another proc procedure loadimages();begin  frmMediaStore.midx:= 0;  frmMediaStore.myThread := TMyThread.Create(true);  frmMediaStore.myThread.OnGetNewMedia := @frmMediaStore.GiveNewMedia;   frmMediaStore.myThread.Start;end                So the main thread sends to the new thread the image info(media info with path and new size) and the index of the array where the bmp will be cached, then the thread load the image and resizes it and then sends back the bitmap and the index to the main thread which calls invalidate so the canvas get drawn. The process repeats until all the images are consumed. Works well!! I created 2 threads and from 11 seconds it went down to 4-5 seconds. Thats good. It still needs improvement, but i already like it. ---------------------------------------------------------------------- wp · 2023-04-12 14:51 Quote from: phoenix27 on April 12, 2023, 04:43:19 pmin my case it always crashes on the line: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i jped := TJpegImage.create I dont know why. Looks like a typo. Shouldn't it read "jpeg" rather than "jped"? Always have a look a the compiler messages to get an idea why code does not compile. If it is not a typo you probably do not have the unit "graphics" in the "uses" clause. ---------------------------------------------------------------------- hukka · 2023-04-12 14:52 I'm working on an image viewer and some of the most important points speedwise were: Use libjpeg-turbo for loading JPEGs. On Windows I use GDI+ for loading most other supported formats; custom routines for less common formats.If you know the dimensions you'll be downscaling to in advance, there's no need to decode the JPEG at full resolution.Use multithreading for image loading. (I see you had success with this already.)Use BGRABitmap.Have a memory cache for decoded images. ---------------------------------------------------------------------- phoenix27 · 2023-04-12 14:52 One problem that i see to my little solution is that every time a new bitmap comes from the new thread i call invalidate and so the paint box gets drawn again and again, although i just draw the visible area.  I noticed the cpu goes to 20, 26%. What do you people think, it's faster to draw on a canvas or to assign the images to a TImage control? ---------------------------------------------------------------------- phoenix27 · 2023-04-12 14:56 @wp it's not the actual code, i just typed it here. But every single time it crashes on that line. Anyway i suppose TJpegImage is just for jpeg images, what if in the future i want to use png or bmp or webp? ---------------------------------------------------------------------- phoenix27 · 2023-04-12 15:06 @hukka "If you know the dimensions you'll be downscaling to in advance, there's no need to decode the JPEG at full resolution." My little program works in this way. I have an algorithm of linear partitioning(i think its called this way) which creates all the rows based on the width and height of the container. In each row every image has the same height but width can be different, according to the aspect ratio of the image. In shorts it looks like a bunch of bricks. So when i resize the form and the width changes i have to repeat the process. So it depends on the width and also the height if i change it. Am i clear? There isn't one predefined dimension. ---------------------------------------------------------------------- VisualLab · 2023-04-12 15:07 Quote from: GetMem on April 12, 2023, 10:08:21 amQuoteThe thing that bothers me the most is that electron and javascript are fast and pascal, a compiled language is notProbably somebody wrote a fast image processing library for javascript. With that said, your pascal code is far from optimal. It seems unlikely to me that the script itself is doing this. Rather, the JavaScript interpreter uses a browser module (part of machine code) that is responsible for loading and saving raster images. Most likely, such a module takes (from the interpreter) paths or addresses and returns (to the interpreter) references to structures that store the content of images ready to be displayed. The script passes the drawing command to the rasterizer, giving it references to graphic structures and areas where they are to be displayed, and the rasterizer displays them. Given how much graphics a web page contains, it's no surprise that these parts of browsers have been heavily optimized. In the most popular web browsers, graphics and multimedia of all kinds are processed in modules written in C++ and compiled to machine code (as machine code in an extractable executable file). These modules are made available to the interpreter as a JavaScript API. A good example of such automation is Web Audio. Currently, JavaScript scripts process data only when there is no such module in the browser (of course, you can write such a "library" in JavaScript, but it will not be as efficient as an optimized browser module - unless someone invents some brilliant algorithm, unknown to anyone yet The question is: how to find in the jungle of Chrome (or Firefox) source code the module responsible for loading and displaying raster graphics? ---------------------------------------------------------------------- wp · 2023-04-12 15:12 Quote from: phoenix27 on April 12, 2023, 04:56:30 pmAnyway i suppose TJpegImage is just for jpeg images, what if in the future i want to use png or bmp or webp? Yes, it's what its name says... If you need a multiformat loader you should use TPicture. But then you are tied to the registered formats and their readers, so that you cannot optimize them. Some third-party libraries register their readers in the LCL and replace the built-in formats, however. Or you read the first few bytes from each file and determine the file format from the file header and then select the appropriate reader class yourself - distinguishing between jpg, png or bmp is really easy. I don't know much about BGRABitmap, maybe it has a multiformat reader. ---------------------------------------------------------------------- VisualLab · 2023-04-12 15:13 Quote from: phoenix27 on April 12, 2023, 04:56:30 pmBut every single time it crashes on that line. Anyway i suppose TJpegImage is just for jpeg images, what if in the future i want to use png or bmp or webp? PNG -> class TPortableNetworkGraphic BMP -> class TBGRABitmap ---------------------------------------------------------------------- phoenix27 · 2023-04-12 15:14 @hukka is it fast GDI+ ?. I'm on windows 7, so i could try. How would i load images with GDI+? ---------------------------------------------------------------------- phoenix27 · 2023-04-12 15:25 @Visual Lab i agree perfectly with you. That's why i said in a previous post that javascript it's just a scripting language which allows you to interact with the browser platform just like lua allows you to simply script a game. But lua is not c++,  in which the game was created. ---------------------------------------------------------------------- phoenix27 · 2023-04-12 15:41 @wp i noticed that TPicture,  when the extension of the file its different from the actual format,  raises a 'wrong format' error, whereas TBGRABitmap doesn't ---------------------------------------------------------------------- wp · 2023-04-12 15:57 Quote from: phoenix27 on April 12, 2023, 05:41:39 pm@wp i noticed that TPicture,  when the extension of the file its different from the actual format,  raises a 'wrong format' error, whereas TBGRABitmap doesn't Yes it would be fine if there were an option to bypass the exception in such a case. But you always can load the file into the TPicture via a stream so that the extension is unknown: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);var  stream: TStream;begin  stream := TFileStream.Create('test.bmp', fmOpenRead);  // 'test.bmp' is a 'png' image renamed to 'bmp'.  try    stream.Position := 0;    Image1.Picture.LoadFromStream(stream);  finally    stream.Free;  end;end; ---------------------------------------------------------------------- hukka · 2023-04-12 16:01 Quote from: phoenix27 on April 12, 2023, 05:14:52 pm@hukka is it fast GDI+ ?. I'm on windows 7, so i could try. How would i load images with GDI+? Snippet from my image viewer: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses Windows, GdiPlus, ActiveX; function GDILoadImage(Stream: TStream): TBGRABitmap;var        StreamAdapter: IStream;        BitmapData: TGPBitmapData;        rec: TGPRect;        gdipBitmap: GpBitmap;      Y: Integer;        PP: Pointer;begin        Result := nil;        try                StreamAdapter := TStreamAdapter.Create(Stream);              try                        gdipBitmap := nil;                      if GdipCreateBitmapFromStream(StreamAdapter, gdipBitmap) <> Ok then Exit;                        rec.X := 0; rec.Y := 0;                      GdipGetImageWidth(gdipBitmap, UINT(rec.Width));                      GdipGetImageHeight(gdipBitmap, UINT(rec.Height));                      if GdipBitmapLockBits(gdipBitmap, @rec,                              [ImageLockModeRead], PixelFormat32bppARGB, BitmapData) = Ok then                        begin                                with BitmapData do                                begin                                      Result := TBGRABitmap.Create(Width, Height);                                      PP := Scan0;                                      for Y := 0 to Height-1 do                                      begin                                                Move(PP^, Result.ScanLine[Y]^, Width*4);                                              Inc(PP, Stride);                                      end;                                end;                              GdipBitmapUnlockBits(gdipBitmap, BitmapData);                      end;                        GdipDisposeImage(gdipBitmap);              finally                        StreamAdapter := nil;              end;        except                FreeAndNil(Result);        end;end; function GDILoadImage(const Filename: String): TBGRABitmap;var        S: TFileStream;begin        Result := nil;      if not FileExists(Filename) then Exit;         S := TFileStream.Create(Filename, fmOpenRead);        try                Result := GDILoadImage(S);        finally                S.Free;      end;end; ---------------------------------------------------------------------- phoenix27 · 2023-04-13 00:54 Thank you hukka, ill try the code. I can say i' m satisfied. I put 3 threads at work and now it works like a charm, it loads all the images in less than 3 seconds. It's perfect for me. About my app in electron, i have forgotten a couple of things(i coded it a while ago). First of all i load only the images in the visible area and i load the rest incrementally while scrolling down. But more importantly, javascript has only one thread, so you cannot use multi-threading, but it has a cool feature called the event-loop(i think it's called like that), which means that I/O operations(like the loading of images, net or database connections and so on) happen by default not in the main thread(like it is for free pascal and most languages and that's why you need multi threading) but somewhere else and when the process ends you get notified through the use of callbacks. So we could say that javascript is non-blocking or async by nature. That's why it looks so smooth. Now i remember that when i loaded all the images at once there was a noticeable delay, although it is non-blocking!! That's why i decided to load only the images in the visible part of the app! ---------------------------------------------------------------------- balazsszekely · 2023-04-13 05:53 @VisualLab Fair enough. I'm not familiar with the loading mechanism. My point is javascript gets a lot of love and attention pascal not so much. @phoenix27 Quote I put 3 threads at work and now it works like a charm, it loads all the images in less than 3 seconds. It's perfect for me.It's not good enough! You wanted to prove that pascal is faster then a scripting language. Here is your chance.  Now seriously, you should try @hukka's method, it's really fast(windows only though). Please do the following: 1. Install GDIPlus from OPM(just added) 2. Install BGRABitmap if needed 3. Compile then run attached project 4. Download sample jpg image(30 Mb) from https://sample- videos.com/download-sample-jpg-image.php At my side the 30 Mb image is loaded in 0.663 sec, which is ~5 times faster then the native solution presented by @wp in reply #5. More over it can load many image formats not just jpgs. Combine this method with your threaded solution and tell us the result. Since image processing is a CPU intensive task, it makes no sense to start more threads then your CPU/Core count. Usually 3 threads are not enough though. @hukka Very nicely done! ---------------------------------------------------------------------- domasz · 2023-04-13 08:14 While Javascript is single-threaded, the web browser (Electron, Firefox, Chrome...) is not. It uses your CPU, GPU and lots of RAM for caching. Javascript is not decoding images, the browser is. And it downloads and decodes images using many threads and many internet connections. ---------------------------------------------------------------------- balazsszekely · 2023-04-13 08:44 @domasz QuoteWhile Javascript is single-threaded, the web browser (Electron, Firefox, Chrome...) is not. It uses your CPU, GPU and lots of RAM for caching. Javascript is not decoding images, the browser is. And it downloads and decodes images using many threads and many internet connections.OK! Then let's forget about Javascript for a minute and compare the mighty browser(I suppose the rendering engine is coded in c++ ) with @hukka's example. Tested with Firefox 112.0(64 bit) vs. Lazarus Trunk/FPC 3.2.2(64 bit) and the results are very similar, Firefox it's slightly faster but not by much, tested with the 30 Mb jpeg(see above). PS: Is pascal a good programming language? According to John Carmack it is: https://youtu.be/I845O57ZSy4?t=5743  PS: Also about javascript(LMAO): https://www.youtube.com/watch?v=I845O57ZSy4&t=1115s ---------------------------------------------------------------------- KodeZwerg · 2023-04-13 09:23 @GetMem, cool your loading method! I compared against ImageMagick, yours beat it 3x faster! ---------------------------------------------------------------------- balazsszekely · 2023-04-13 09:33 Quote from: KodeZwerg on April 13, 2023, 11:23:42 am@GetMem, cool your loading method! I compared against ImageMagick, yours beat it 3x faster! Thank you, but all credits goes to @hukka. I only created a small demo application according to the code posted by him. ---------------------------------------------------------------------- loaded · 2023-04-13 11:00 The Google Picasa program is the expert in this business. It makes loading, viewing and zooming the image surprisingly fast. In fact, it would be great if the experts of the business examine and analyze this software. ---------------------------------------------------------------------- domasz · 2023-04-13 11:20 I tested this lib a while ago and was the fastest JPEG decoder for Delphi. But won't compile in Lazarus: http://www.marktg.com/jpegdec/ ---------------------------------------------------------------------- balazsszekely · 2023-04-13 12:48 Quote from: domasz on April 13, 2023, 01:20:06 pmI tested this lib a while ago and was the fastest JPEG decoder for Delphi. But won't compile in Lazarus: http://www.marktg.com/jpegdec/ Challenge accepted. JpegDec(Delphi 11) vs. GDIPlus(Lazarus/FPC), same 10 MB jpg image. I would say the two are very similar in performance. ---------------------------------------------------------------------- KodeZwerg · 2023-04-13 12:58 Now add libjpeg-turbo to your test candidates and we are done ---------------------------------------------------------------------- balazsszekely · 2023-04-13 13:00 Quote from: KodeZwerg on April 13, 2023, 02:58:53 pmNow add libjpeg- turbo to your test candidates and we are done Do you have a demo somewhere? Lazarus or D. it does not matter. ---------------------------------------------------------------------- domasz · 2023-04-13 13:15 Quote from: GetMem on April 13, 2023, 02:48:27 pmChallenge accepted. JpegDec(Delphi 11) vs. GDIPlus(Lazarus/FPC), same 10 MB jpg image. I would say the two are very similar in performance. Are you measuring decoding time only? Excluding time needed to load from disk? Also multiply this by 1000 images and the difference is already noticable. ---------------------------------------------------------------------- phoenix27 · 2023-04-13 13:19 OMG hukka the code you shared is blazing fast!!! Thank you! Get mem i downloaded the 30MB image and added it, well to load that single image it took about 6 sec.  With GDI it showed up immediately, and i really mean it. What a shame that GDI is windows only. You know, up to a few weeks ago i was quite happy with linux mint, then i installed lazarus to try free pascal but i wasnt so happy because from the installation on it gave me all sorts of problems, sometimes it crashed out of the blue, sometimes it wouldn't start at all giving me some strange errors and so on. So, knowing that object pascal  is mainly a windows thing, i switched back to windows 7 and voila', it works really well now. Get mem i know that pascal is faster than javascript, its speed is comparable to that of c++. I just couldn't understand why the loading of images was so slow. But now i know why. Im' happy because now i can create my little apps without having to rely on a server/client architecture(the browser and nodejs) or electron. It's a shame that pascal doesn't get the attention that should deserve. Faster, efficient memory management, my app in electron at this moment occupies 300MB, just for showing some pictures, pascal instead is 26MB. People are sheeple ahahaha ---------------------------------------------------------------------- KodeZwerg · 2023-04-13 13:35 Quote from: GetMem on April 13, 2023, 03:00:37 pmQuote from: KodeZwerg on April 13, 2023, 02:58:53 pmNow add libjpeg-turbo to your test candidates and we are done Do you have a demo somewhere? Lazarus or D. it does not matter. A copy of old headers ( Delphi compatible, Lazarus needs love  ) and binary lib ( Windows ) files added. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses  cgJpeg; var  jpg: TJpegImage;begin  jpg := TJpegImage.Create;  try    jpg.LoadFromFile('jpegFile.jpg');    // do something with it like    Image1.Picture.Bitmap.Canvas.Draw(0, 0, jpg);  finally    jpg.Free;  end;end; ---------------------------------------------------------------------- KodeZwerg · 2023-04-13 14:01 Quote from: domasz on April 13, 2023, 03:15:22 pmQuote from: GetMem on April 13, 2023, 02:48:27 pmChallenge accepted. JpegDec(Delphi 11) vs. GDIPlus(Lazarus/FPC), same 10 MB jpg image. I would say the two are very similar in performance. Are you measuring decoding time only? Excluding time needed to load from disk? Also multiply this by 1000 images and the difference is already noticable. I do fully second your statement. For benchmarking the jpeg file should be loaded into a stream, from that stream some thousand times a jpeg decoding (LoadFromStream) should be measured and the average time should be the result. Loading file from disk and displaying shall be excluded. ---------------------------------------------------------------------- balazsszekely · 2023-04-13 15:38 @domasz, @KodeZwerg Are you aware that with your latest comment basically you auto assigned yourself to do the testing?  I'm not interested in such an extensive/detailed test, please let me know the result. Currently I' m working on a cross platform solution, which will be able to load multiple image format not just jpg(like GDI does on windows), only in a cross platform way. I believe OpenGl is the correct approach, I'm not sure yet though. @KodeZwerg Thanks for the headers. I will take a look later. @phoenix27 So how fast is your threaded version now? Also can you share the project? If you don't want to is perfectly fine. QuoteIt's a shame that pascal doesn't get the attention that should deserve. Faster, efficient memory management, my app in electron at this moment occupies 300MB, just for showing some pictures, pascal instead is 26MB. People are sheeple ahahaha In my opinion the main issue with pascal is not performance, but the lack of available jobs + students no longer learn the language. The vast majority of pascal programmers are over 40, 50 maybe?, I'm not sure. Pascal is not dying, but the programmers will at some point. ---------------------------------------------------------------------- lainz · 2023-04-13 15:48 Quote from: GetMem on April 13, 2023, 05:38:34 pmIn my opinion the main issue with pascal it's not performance, but the lack of available jobs + students no longer learn the language. The vast majority of pascal programmers are over 40, 50 maybe?, I'm not sure. Pascal is not dying, but the programmers will at some point. I'm 33 and I have a Pascal job, but here in my country few Universities teach pascal, I learned Pascal by myself. I get the job thanks to this forum and because I'm one of the authors of BGRAControls. I'm very happy ---------------------------------------------------------------------- balazsszekely · 2023-04-13 15:53 Quote from: lainz on April 13, 2023, 05:48:40 pmQuote from: GetMem on April 13, 2023, 05:38:34 pmIn my opinion the main issue with pascal it's not performance, but the lack of available jobs + students no longer learn the language. The vast majority of pascal programmers are over 40, 50 maybe?, I'm not sure. Pascal is not dying, but the programmers will at some point. I'm 33 and I have a Pascal job, but here in my country few Universities teach pascal, I learned Pascal by myself. I get the job thanks to this forum and because I'm one of the authors of BGRAControls. I'm very happy I know @lainz, but you are the exception not the rule. I'm glad to hear that younger people still learn Pascal and there are available jobs out there.  PS: 🇦🇷 is a cool country if universities still teach Pascal. Big like! ---------------------------------------------------------------------- hukka · 2023-04-13 19:04 Correction to my previous posts, I use turbojpeg, not libjpeg-turbo in my current project. I've attached the relevant header, 64-bit DLL (can't include the 32-bit DLL due to attachment filesize limit) and the JPEG loader unit from my image viewer (TBitmap32=TBGRABitmap, sorry for the idiosyncracy). ---------------------------------------------------------------------- lainz · 2023-04-14 01:01 Quote from: lainz on April 13, 2023, 05:48:40 pmQuote from: GetMem on April 13, 2023, 05:38:34 pmIn my opinion the main issue with pascal it's not performance, but the lack of available jobs + students no longer learn the language. The vast majority of pascal programmers are over 40, 50 maybe?, I'm not sure. Pascal is not dying, but the programmers will at some point. I'm 33 and I have a Pascal job, but here in my country few Universities teach pascal, I learned Pascal by myself. I get the job thanks to this forum and because I'm one of the authors of BGRAControls. I'm very happy Thanks! I've seen a Pascal online course in Spanish as well. Is a paid course but looks very complete. I did a gift of this course to a friend in the company I work he is tech support but is learning to program in Pascal. He is like 10 years younger than me. The owner of the company where I work is Pascal programmer as well and is my friend too. He knows a lot of everything from backend to frontend to Android and web, databases. I've learned a lot of that as well. ---------------------------------------------------------------------- circular · 2023-04-14 19:27 Not sure if that will be of use but there is BGRAThumbnail unit in BGRABitmap that allows to quickly load a preview, with less quality, a thumbnail of given size. About hukka suggestion to use Gdi+ that seems a good idea to do on Windows. This could be a possible optimization of BGRABitmap library.