Flickering or what? lazarus / 39-Graphics ---------------------------------------------------------------------- phoenix27 · 2023-11-13 17:35 In the attached video(i had to keep it within the maximum admitted size so the quality is not good) you can see the problem. When i scroll up or down there is flickering(is that the way it's called?) on the top or bottom edge.  The images are painted in a TPanel contained in a TScrollBox contained into a TTabSheet contained in a TPageControl. I did set the doubleBuffered property of Tpanel and TScrollBox to true but it didn't help. I just do not know how to solve it. Does somebody have any idea? ---------------------------------------------------------------------- wp · 2023-11-13 17:57 It would be better if you'd prepare a small demo project showing the issue. Pack the .pas, .lfm, .lpi and .lpr files into a shared zip which you can upload here (do not add files generated by the compiler because this may exceed the upload size limit). Specifiy the size and count of the images to be displayed so that I can use similar images of my own. Do not upload your full project, remove everything needed, ideally begin a new project from scratch - please understand that I am not inclined to debug a huge project which i do not understand. ---------------------------------------------------------------------- phoenix27 · 2023-11-13 18:16 Thank you for you answer. I thought that too although it will require a bit of work because my programming style is messy, to say the least. But from just watching the video did you get any idea on what it could be? I tried, using the same algorithm(only translated to c++) with wxWidgets and c++ and it works well, no flickering. Keep in mind that the images are not TImage instances, they are painted in the onpaint event of the TPanel.A while ago i tried to translate the program in Delphi but using TImage for the images and it worked well. Anyway i'll try to make a little project. ---------------------------------------------------------------------- wp · 2023-11-13 18:34 Quote from: phoenix27 on November 13, 2023, 07:16:51 pmBut from just watching the video did you get any idea on what it could be? No, I did not even see any flicker at all... ---------------------------------------------------------------------- 440bx · 2023-11-13 18:37 Quote from: phoenix27 on November 13, 2023, 06:35:54 pmWhen i scroll up or down there is flickering(is that the way it's called?) on the top or bottom edge.  The images are painted in a TPanel contained in a TScrollBox contained into a TTabSheet contained in a TPageControl. I did set the doubleBuffered property of Tpanel and TScrollBox to true but it didn't help. I just do not know how to solve it. Does somebody have any idea? My knowledge of TPanel, TScrollbox and other LCL controls is nil but, I'm going to presume you're doing this app in Windows. What happens is that somewhere in all that code (whatever LCL code controls/does the scrolling) when scrolling happens the bottom part (which got scrolled up) is cleared by the default window handler.    The way to avoid the flickering is to have the background _not_ be cleared when the window is scrolled up.   The easiest way is to have a WM_BACKGROUND message handler that returns "true" indicating the newly exposed part of the window has been erased (even though it hasn't been) and then "overwritten" with the new part of the image (which you are doing but, you are overwriting the cleared background instead of what's left there of the old piciture.) As far as where in the LCL the WM_BACKGROUND should be processed, I simply don't have a clue.  (I only know pure Windows API and message handlers.) HTH. Quote from: wp on November 13, 2023, 07:34:37 pmQuote from: phoenix27 on November 13, 2023, 07:16:51 pmBut from just watching the video did you get any idea on what it could be? No, I did not even see any flicker at all... I think he is referring to the slight amount of flicker visible at the bottom of the screen window when the images are scrolled up. ---------------------------------------------------------------------- Martin_fr · 2023-11-13 19:04 I single stepped the video and I can't see "flicker". Well... I can't see the background being cleared. Though I don't know if that is happening, but missing in the video, or if it is not happening. What I can see, is that the image is scrolled up, leaving only the bottom to be painted, and therefore the bottom showing the not-yet scrolled image. And as the scrolling is not smooth, but like a maybe 50+ pixel at a time => that is visible => so that could be called flicker. That is to the best of my knowledge the way scrolling is supposed to be implemented. But I can't say, if there is a delay before the paint. Normally the paint should be really fast. But if for some reason the image still has to be decompressed to be painted, then that would cause a delay. There is a way to make sure this does not happen (though I don't have the implementation details at hand / and not sure it can easily be done with panels). That would be: - don't scroll - paint the entire background in one go with the newly offset-ed image(s). --- It is possible that the LCL does not deal optimal with the scrolling of all the panels at once (if you have lots of panels or TWinControl- descendants). ---------------------------------------------------------------------- 440bx · 2023-11-13 19:28 Quote from: Martin_fr on November 13, 2023, 08:04:02 pm as the scrolling is not smooth, but like a maybe 50+ pixel at a time => that is visible => so that could be called flicker. That's also what I'm guessing he is calling flicker.  I'm not sure but, I do believe the bottom part is cleared someway and then painted but, I could be wrong about it being cleared because I didn't step the scrolling frame by frame. There is usually a slight delay before painting which is mostly due to the fact that WM_PAINT is a low priority message (in Windows, I don't know about its equivalent in other OSs) and that can create flicker or an effect that is similar. ---------------------------------------------------------------------- phoenix27 · 2023-11-13 19:41 Before i try to make a little project, best to show the paint routine 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 TfrmMediaStore.pb_onPaint(sender: TObject);label loop, there;var i: integer; mi: TMediaItem; maxTopPos, minTopPos: integer; pb: TMediaCanvas; marr: array of TMediaItem; sb: TScrollBox; bmp, bmpTitle: TBGRABitmap; pCanvas: TCanvas; mcount:integer; Y, hei:integer; mt:MediaType; title:string=''; pmi: ^TMediaItem; sz: TSize;begin  pb := TMediaCanvas(sender);  marr:= pb.getMarrItems(mcount);  i:= 0;  sb := TScrollBox(pb.parent);  minTopPos := sb.VertScrollBar.position;  maxTopPos := sb.VertScrollBar.position + sb.ClientHeight;  pCanvas:= pb.canvas;  mt:=pb.mtype;  pmi:= @marr[0];  loop:    if i >= mcount then goto there;    mi:= pmi^;    inc(pmi);    inc(i);    if mi = nil then goto loop;      Y:=mi.top + mi.yOffset;      if (mi.bottom + mi.yOffset >= minTopPos) and (Y <= maxTopPos) then begin          if mi.bmp <> nil then              pCanvas.Draw(mi.left, Y, mi.bmp);      end;    goto loop;  there:  if pb.hoveringItem <> nil  then begin    //hovering item         mi := pb.hoveringItem;         bmp := TBGRABitmap.Create(mi.width, mi.height, BGRA(5,5,120,90));//from 0 to 255, higher means more opaque//0,0,0,100         try           // bmp.Rectangle(0, 0, mi.right, mi.yOffset + mi.bottom, BGRA(255,0,0,200), dmDrawWithTransparency); //e' il contorno           //title bar             if mt = video then                   title:= TVideoItem(mi).title             else if mt = image then                 title:= TImageItem(mi).title             else if mt = web then                 title:= TWebItem(mi).title;              if title <> '' then begin                 hei := 25;                 bmp.FontStyle:= [fsBold];                 sz := bmp.TextSize(capitalize(title));               if sz.width > bmp.width then hei := 50;                 bmpTitle:= TBGRABitmap.create(mi.width, hei, bgra(0,0,0,120));               try                    bmpTitle.FontStyle:= [fsBold];                  bmpTitle.FontHeight:=13;                    bmpTitle.TextRect(Rect(0,0, mi.Width, hei), capitalize(title), taCenter, tlCenter, CSSOrangeRed);                    bmp.PutImage(0, bmp.Height - hei, bmpTitle, dmDrawWithTransparency);                 finally                   bmpTitle.Free;                 end;           end;             bmp.Draw(pCanvas, mi.left, mi.yOffset + mi.top, False);         finally            bmp.Free;         end;    end;    marr:= pb.getSelectedItems(mcount);    if mcount > 0 then begin       for mi in marr do begin   //selected items         if assigned(mi) then begin             bmp := TBGRABitmap.Create(mi.width, mi.height, BGRA(255,192,50, 90));//from 0 to 255, higher means more opaque//0,0,0,100            // bmp.Rectangle(0, 0, mi.right, mi.yOffset + mi.bottom, BGRA(0,0,0,100), dmDrawWithTransparency);           bmp.Draw(pCanvas, mi.left, mi.yOffset + mi.top, False);           bmp.Free;         end;       end;    end;end; ---------------------------------------------------------------------- phoenix27 · 2023-11-13 20:15 @Martin_fr Yes, for example when i scroll the page down(and the images are going up) with the mouse wheel i feel like it's taking time to paint the bottom part of the appearing images whereas when i scroll using the scroll bar the bottom part appears watery so to speak Quote  There is a way to make sure this does not happen (though I don't have the implementation details at hand / and not sure it can easily be done with panels). That would be: - don't scroll - paint the entire background in one go with the newly offset-ed image(s). What do you mean do not scroll? Everything should appear in the viewport at once.  I don't like that. Paint the entire background? How? I paint image by image by first checking if it's in view as you can see in the paint routine ---------------------------------------------------------------------- Martin_fr · 2023-11-14 01:38 Quote from: phoenix27 on November 13, 2023, 09:15:05 pm@Martin_fr Yes, for example when i scroll the page down(and the images are going up) with the mouse wheel i feel like it's taking time to paint the bottom part of the appearing images whereas when i scroll using the scroll bar the bottom part appears watery so to speak Quote  There is a way to make sure this does not happen (though I don't have the implementation details at hand / and not sure it can easily be done with panels). That would be: - don't scroll - paint the entire background in one go with the newly offset-ed image(s). What do you mean do not scroll? Everything should appear in the viewport at once.  I don't like that. Paint the entire background? How? I paint image by image by first checking if it's in view as you can see in the paint routine I should have made it clear, that this is not a good replacement. Right now you have the "split screen" issue, where part is awaiting its paint... And the other part shows what had already been there, it was just scrolled (moved on the screen, without repaint) using ScrollWindowEx from the Win kernel. If  you don't use ScrollWindowEx => and instead paint the entire visible are with a single BltBitmap (using a fully prepared source bitmap), then you are always that fast, that you shouldn't get the split effect  (o.k. in theory you can hit the screen refresh, and get tearing). However full update every time is no good. It will be slow, really slow. It wont flicker, but it can easily start stuttering. ---- So the real question (and I don't have the answer) is why does it take that long to update. The mouse wheel vs scrollbar is of interest. Because if it works with the scrollbar, then your paint method is fast enough. Unless ... QuoteCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  if pb.hoveringItem <> nil  then begin    //hovering item         mi := pb.hoveringItem;         bmp := TBGRABitmap.Create(mi.width, mi.height, BGRA(5,5,120,90));//from 0 to 255, higher means more opaque//0,0,0,100         try Maybe the hovering slows your paint down? Actually that could be it. I first though, bad idea to create new bitmaps in paint, better have prepared ones, that can be used. But maybe its not that. Maybe it is still fast enough, maybe it would better be created outside paint, and kept -- not sure, you may need to try. But there is another issue. It looks like the image under the mouse is darkened? So it gets invalidated. Each time an image gets invalidated, then that entire image needs repaint => Except, the actual repaint will be much more. If you invalidate 2 small rects, then the area to repaint is the rectangle including both of them (and everything inbetween). (WIthin one single WinControl, eg. one Panel) So if you darken (and invalidate) an image in the upper half, and scrolling invalidates the entire width of the lower area (few pixels height, but full width), then the containing repaint rect, will be 80% of the screen. And that could slow think down, and the if a paint event took to long, all the scroll event get combined, do one big scroll before the next paint. And that might indeed flicker. ---------------------------------------------------------------------- Handoko · 2023-11-14 04:56 I didn't see any flicker, maybe the video quality wasn't good enough to capture it. But I did see some paint delay. I ever animated several hires images at a same time and displayed them in much smaller sizes on the screen, I got noticeable paint delay. My workaround was to resize all the images to match its display sizes before the starting the animation, it worked for my case. Perhaps you can try my solution. ---------------------------------------------------------------------- phoenix27 · 2023-11-14 15:26 @Martin_fr "Maybe the hovering slows your paint down?" I removed the code from the paint event and the problem is still there with all its ugliness. Anyway i prepared a little project for all of you to try and then tell me what's going on. Put in a folder 50 images(size is not important) launch the app then maximize the program window to see better what the problem is, finally open that folder and when the images appear start scrolling down with the mouse wheel and see for yourself. I ported the same program in c++(wxWidgets) and even in Lua and found no problem whatsoever.  Forgot to say that you must include lazgdiplus and BGRABitmappack in the project inspector for the app to work ---------------------------------------------------------------------- phoenix27 · 2023-11-14 16:35 I just loaded 687 images with the app attached in the prev post(i've never done this in my original app), it took a while to load but it can be clearly seen that it's the painting the problem, really slow!! But why? I just draw the visible images, not all of them. It can be seen in the OnPaint routine. Or It's not correct? ---------------------------------------------------------------------- phoenix27 · 2023-11-14 16:43 In the program attached at the line 304 change 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    freeAndNil(imgsArr[i]); to 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 freeAndNil(imgsArr[i].bmp); ---------------------------------------------------------------------- balazsszekely · 2023-11-14 19:01 @phoenix27 Try attached project. ---------------------------------------------------------------------- phoenix27 · 2023-11-14 20:30 @GetMem Thank you! That solves the problem. But why the OnPaint event is so slow? ---------------------------------------------------------------------- balazsszekely · 2023-11-14 20:50 Quote from: phoenix27 on November 14, 2023, 09:30:31 pm@GetMem Thank you! That solves the problem. But why the OnPaint event is so slow? Put a counter inside your original project's OnPaint event, scroll up and down a few times and observe the insane amount of drawing, no wonder there is a lot of flicker. You can use a buffer image for the drawing and only update the panel when is necessary. However since TImage can contain a persistent picture, you can get away with a single draw(in a for cycle). 1. Please check unit BGRAThumbnail, you can extract thumbnails for a loaded bgrabitmap or from a  file. I suppose is a lot faster then resizing the image(not tested) 2. You should consider spawning a few worker threads. It should speed up the loading 3. Your application leaks, don't forget  to free mi.bmp for each element of the array ---------------------------------------------------------------------- phoenix27 · 2023-11-14 22:28 QuotePut a counter inside your original project's OnPaint event, scroll up and down a few times and observe the insane amount of drawing, no wonder there is a lot of flicker. But why? I just call pnl.Invalidate() once, after loading the images. Then it's LCL  which calls the OnPaint method, not me. Isn't supposed to be like that? And so the painting should be fast, especially because i also cache the Tbitmap elements, also i just the draw only those images which are visible. Quote You should consider spawning a few worker threads. It should speed up the loadingThis was just a project extrapolated from my app in order to show the problem. In the actual app i  don't even load all the images at once, but only when i scroll and yes i use threads in order not to block the UI. Quote Your application leaks, don't forget  to free mi.bmp for each element of the array No it doesn't. I free the cached bmps every time i open a new folder QuoteYou can use a buffer image for the drawing and only update the panel when is necessary Isn't the mi.bmp a buffer image? I do update the panel only when necessary. In fact i call Invalidate only once. For the rest is the LCL calling the OnPaint method. But can you elaborate more on buffering. Maybe i' m not doing it the right way, i don't know. The TImage solution works but i need the TPanel because in my actual App i have video thumbs also and when i click on one of them i create a vlc inline player at the position of the image which shows the video. I cannot do that with the TImage because it cannot contain another control ---------------------------------------------------------------------- balazsszekely · 2023-11-15 13:04 @phoenix27 QuoteBut why? I just call pnl.Invalidate() once, after loading the images. Then it's LCL  which calls the OnPaint method, not me. Isn't supposed to be like that? And so the painting should be fast, especially because i also cache the Tbitmap elements, also i just the draw only those images which are visible.When you scroll, the panel is repainted. QuoteThis was just a project extrapolated from my app in order to show the problem. In the actual app i  don't even load all the images at once, but only when i scroll and yes i use threads in order not to block the UI. OK. QuoteNo it doesn't. I free the cached bmps every time i open a new folderYes it does. You free imgsArr in a loop, but you do not free imgsArr[].bmp,  imgsArr[].bmp must be freed separately. Also when closing application you don't free imgsArr/bmp at all. Please check "Use Heaptrc unit" in Project options/Compiler options/Debugging to see if your application leaks. I attach another version, this one is much faster with no memory leaks. You can still improve it with threads. ---------------------------------------------------------------------- phoenix27 · 2023-11-15 18:17 QuoteYes it does. You free imgsArr in a loop, but you do not free imgsArr[].bmp,  imgsArr[].bmp must be freed separately.In a previous post i clearly said to change freeAndNil(imgsArr) to freeAndNil(imgsArr.bmp). It was an error. Why should i free the array bmps when the application is closed? Doesn't windows free all the program's memory? QuoteWhen you scroll, the panel is repainted. Look i don't want to sound repetitive, i just want to understand. Isn't supposed to be like that when you use the OnPaint event handler? When the application itself needs the panel to be repainted it calls the OnPaint handler. It's not me. And in that event handler i simply draw the cached bmps, i don't load the images again and also i draw only those images that are visible in the viewport. As i said in a previous post i translated the same app in c++ using the wxwidgets framework and in the paint event did exactly the same thing and there is no delay at all. I even did it in Lua using wxlua(i think it's called like that) and no delay. That's why i asked if it was a flickering issue or something else. Anyway thank you. It's much faster than before ---------------------------------------------------------------------- balazsszekely · 2023-11-15 19:40 QuoteIn a previous post i clearly said to change freeAndNil(imgsArr) to freeAndNil(imgsArr.bmp). It was an error.Ok fair enough, I missed that line. However the application still leaks even with that change. QuoteThe system will clean up resources when the process terminates.Yes the system will eventually clean up resources and free up memory when the process terminates, however is a good practice to free everything manually. How you gonna differentiate between unintentional and intentional leaks reported by heaptrc? Anyways I don't want to insist on this topic...do as you like. QuoteLook i don't want to sound repetitive, i just want to understand. Isn't supposed to be like that when you use the OnPaint event handler? When the application itself needs the panel to be repainted it calls the OnPaint handler. And in that event handler i simply draw the cached bmps, i don't load the images again and also i draw only those images that are visible in the viewport. I don't know the exact cause of the flicker. Put a breakpoint inside the OnPaint event. Open View->Debug Windows->Call stack. Run the program, then follow the WMPaint event. I did not have time for that, maybe there is a bug in lcl and the OnPaint event is called too many time. It would be interesting to see how your programs behaves compiled with delphi. QuoteAs i said in a previous post i translated the same app in c++ using the wxwidgets framework and in the paint event did exactly the same thing and there is no delay at all. I even did it in Lua using wxlua(i think it's called like that) and no delay. That's why i asked if it was a flickering issue or something else.Can you attach the source code? QuoteAnyway thank you. It's much faster than beforeYou're welcome. If I will try to implement a threaded version if time permits. Update: I replaced in your demo application TPanel with a TPaintBox, the flicker is almost gone. TImage is still better since it can hold a persistent image. I looks like a bug in TPanel ---------------------------------------------------------------------- phoenix27 · 2023-11-15 19:59 I think i solved it!!! In the c++ code i noticed  that i was drawing the images in a wxScrolledWindow and so i decided to do the same in pascal, so i removed the TPanel altogether and did the drawing directly in the TScrollBox window and the problem is gone!! I can scroll without that ugly delay. I set the TScrollBox.VertScrollBar.range to the actual length of the page with an increment of 50 pixels(the default 8 is too slow) and the TScrollBox.Height to the form clientHeight and it works. ---------------------------------------------------------------------- phoenix27 · 2023-11-15 20:17 Well i think i was a bit too hasty. The problem is still there although is less. About the c++ code i have to prepare a little project like a did with pascal The drawing routine is this:Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   void PlayerFrame::tabPagePaint(wxPaintEvent& event){    TabPage *tp = (TabPage *) event.GetEventObject();    if(!tp) return;  wxPaintDC dc(tp);    int cw, ch;    tp->GetClientSize(&cw, &ch);    // Find Out where the window is scrolled to    int vbX,vbY;           tp->GetViewStart(&vbX,&vbY);    vbX *= PlayerFrame::scrollXStep;    vbY *= PlayerFrame::scrollYStep;    DBRG_S dbrg = tp->data;    int count = dbrg.n_rows;    MediaType mt = tp->getMediaType();    MediaItem *hmi = tp->getHovMediaItem();    MediaItem **vs = (MediaItem **) dbrg.ptrData;    int top;    for(int i = 0; i < count; i++){      MediaItem *v = *(vs + i);        top = v->top + v->yOffset;        if(v->bottom + v->yOffset > vbY && top <= vbY + ch && v->right > vbX && v->left <= vbX + cw){            if(v->bmp)                dc.DrawBitmap(*(v->bmp), v->left - vbX, top - vbY, true);        }    }    wxGraphicsContext *gc = wxGraphicsContext::Create( dc );    if(gc){        if(hmi){            wxPen pen(wxColour(204,255,0, 140), 1, wxPENSTYLE_SOLID);            pen.SetWidth(2);            gc->SetPen(pen);            gc->DrawRectangle(hmi->left - vbX - 1, hmi->top + hmi->yOffset - vbY - 1, hmi->width + 1, hmi->height + 1);          gc->SetPen(wxNullPen);        }        int n;        MediaItem **ms = tp->getSelectedItems(&n);        if(n){            gc->SetBrush(wxBrush(wxColour( 0, 0, 120, 130)));            for(int i = 0; i < n; i++){                MediaItem *si = *(ms + i);              if(si)                    gc->DrawRectangle(si->left - vbX - 1, si->top + si->yOffset - vbY - 1, si->width + 1, si->height + 1);          }            gc->SetBrush(wxNullBrush);        }        delete gc;    }} The TabPage class is just a wxScrolledWindow and i draw in there and i can assure you, no matter how many images i decide to show( i went to show almost 700 in one page) the scrolling is smooth ---------------------------------------------------------------------- balazsszekely · 2023-11-16 14:03 @phoenix27 This is my final attempt. I made the following improvements: 1. Switched to threads. The images are loaded 3-4x faster 2. Separated the user interface from the business logic 2. Thumbnail/tile under the mouse pointer is highlighted 3. Double clicking the highlighted thumbnail/tile will open the file in image viewer 4. Statusbar displays information about the image file 5. There is absolutely no flickering when scrolling 6. The interface is more responsive PS: I did not have enough time to thoroughly test the projects, it may contain bugs ---------------------------------------------------------------------- phoenix27 · 2023-11-16 21:05 It's perfect, thank you GetMem. Now i have to adapt it to my app and i' m ready to go. Thank you again ---------------------------------------------------------------------- balazsszekely · 2023-11-17 22:43 Quote from: phoenix27 on November 16, 2023, 10:05:26 pmIt's perfect, thank you GetMem. Now i have to adapt it to my app and i' m ready to go. Thank you again You're welcome! A few small bugfix and a blazingly fast thumbnail load are available in the attachment. Do the following: 1.  Menu->Images->Open folder 2.  Menu->Options->Switch from high quality to low quality PS: It would be nice if all low quality thumbnails would be equal in size. Please do your magic in PartitionMedia/Partition methods, search for FThumbnailType for more details. If you modify the code, please let me know. PS: This thread is about GDI and windows. Not applicable for Linux and macOS, sorry for that. ---------------------------------------------------------------------- phoenix27 · 2023-11-18 11:39 QuoteIt would be nice if all low quality thumbnails would be equal in sizeIn order for the thumbnails to have the same size there must be some cropping, because every image has a different aspect ratio, some have a landscape orientation, some a portrait one. I' ll try to come up with something... ---------------------------------------------------------------------- balazsszekely · 2023-11-18 12:28 @phoenix27 QuoteIn order for the thumbnails to have the same size there must be some cropping, because every image has a different aspect ratio, some have a landscape orientation, some a portrait one. I' ll try to come up with something...Not necessarily the same size, but at least each thumbnail should have a maximum size. Please load a folder with one image file in it and you will see what I mean. It looks bad even with the high quality tiles/thumbnails. ---------------------------------------------------------------------- phoenix27 · 2023-11-18 13:16 I don't think it's possible. The beauty of this algorithm is that although every row can have a different number of images the widths of the rows are the same because you can expand the width of the single image according to its aspect ratio. But if you want the same size for all images then what happens when some rows have 5 images and some 6. You will have spaces and that's not good. Try the example i prepared to see what i mean. ---------------------------------------------------------------------- balazsszekely · 2023-11-18 16:48 Quote from: phoenix27 on November 18, 2023, 02:16:27 pmI don't think it's possible. The beauty of this algorithm is that although every row can have a different number of images the widths of the rows are the same because you can expand the width of the single image according to its aspect ratio. But if you want the same size for all images then what happens when some rows have 5 images and some 6. You will have spaces and that's not good. Try the example i prepared to see what i mean. OK understood. Maybe I will come up with something completely different for the small thumbnails, something similar how images are shown in windows explorer. , but it's not a priority for now. ---------------------------------------------------------------------- phoenix27 · 2023-11-18 22:27 CHange uThumbnails.pas with this one. I modified the partitionMedia procedure, now you can set an ideal image height. Try to see if it works with few images. ---------------------------------------------------------------------- phoenix27 · 2023-11-19 04:49 Try this one and let me know ---------------------------------------------------------------------- balazsszekely · 2023-11-19 07:24 Quote from: phoenix27 on November 19, 2023, 05:49:25 amTry this one and let me know Very nicely done! Thanks. You need a SetLength in method ExplorerLikeGallery, because if you repeatedly load multiple folders it will give you an exception, the image array is nil: 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 TThumbnails.ExplorerLikeGallery(wndWidth: integer; out rowWidth, colHeight: integer);var  NImgsxRow, HMarg, VMarg, LeftMarg: Integer;  W, H, I, C, TotLeft, TotHeight,FLen: Integer;  f: String;  rct: TScaleRect;begin  LeftMarg := 0;  VMarg := 10;  NImgsxRow := trunc(wndWidth / FThumbWidth);  HMarg := (wndWidth - NImgsxRow * FThumbWidth) div NImgsxRow;  if HMarg > 10 then begin    LeftMarg := ((hMarg - 10) * NImgsxRow) div 2;    HMarg := 10;  end;  FLen := length(FFileList);  SetLength(FImgsArr, FLen); //<--this one  //...  Other then that is perfect. Now both thumbnail types(small/large) looks good. ---------------------------------------------------------------------- phoenix27 · 2023-11-22 02:33 You like it? I don' t and that's why i made it with a "brick wall" style. I like the images all close too each other with just a bit of margin between them. Instead in explorer there is too much distance between them due to the fact that they are all the same size. ---------------------------------------------------------------------- balazsszekely · 2023-11-22 05:26 Quote from: phoenix27 on November 22, 2023, 03:33:47 amYou like it? I don' t and that's why i made it with a "brick wall" style. I like the images all close too each other with just a bit of margin between them. Instead in explorer there is too much distance between them due to the fact that they are all the same size. The brick wall style looks better, however for a directory with 300-400 large image files is way to slow, more over it consumes a huge amount of memory. A managed to reduce the memory consumption to half, also the new version automatically rotates/flips jpeg images when needed, for more details check the following link: https://learn.microsoft.com/en-us/windows/win32/api/gdiplusimaging/ne- gdiplusimaging-rotatefliptype. There are some issues with the rotation on 64 bit, but it can be fixed later. Although this is a fun project, unfortunately I'm busy with other things, maybe I will revisit later. ---------------------------------------------------------------------- phoenix27 · 2023-11-23 00:24 Quotehowever for a directory with 300-400 large image files is way to slowOf course, that's why i use paging, 50 images x page for example. But i could put 400 images in a page too, because i load only the visible ones and load the others on demand while scrolling. I don't understand the memory part. I load the images and rescale them. In order to save memory i should create the actual thumbnails on disk and then load them, right? But i don't want escpecially because the whole thing is dynamic. Quote I managed to reduce the memory consumption to half, also the new version automatically rotates/flips jpeg images when needed WHat do you mean? Why do you rotate and flip the images? What this has to do with saving memory?