[Solved] Component à la TPicShow (delphi) lazarus / 39-Graphics ---------------------------------------------------------------------- WimVan · 2019-01-06 07:19 What a difficult component to fidn for Lazarus.  On the whole internet we can only find a few references that TPicshow (last update in 2014) should be available for Lazarus. I tried to import , convert but after some days I stop.  Too much items to be rewritten, faulting functions, procedures, properties ... If someone knows where to find a running Tpicshow-component for Lazarus, be welcome Meanwhile I tried to note down -how a component for a slideshow could work. 1) a TImage based component 2) the background should be an image too, with the same posibilities (stretch, autosize, ...) as the showed images.  The region that is not filled with the image should be a color we can choose.  So we have to images.  Backgroundimage and a full-component overlaying foregroundimage. Action 1) load background and foreground. 2) fade in .  At the beginning the background can be a black, ... 3) Once faded in.  We see the foreground. 4) load foreground to background 5) close foreground so we see the background. 6) load foreground as unvisible by other words, to see it, we must fade in again .. Needed properties above that of timage 1) time for fade in 2) eventually the time a picture is shown procedure: copy foreground  to background when fade in is 100% and immediately make foreground unvisible fade in is now 0% so a new foreground can be laded. Some interested of can help me ? Thanks SOLUTION. Take a look to all documentation available and learn your own.  If you can't, be a member of my group. To dummy... ---------------------------------------------------------------------- Handoko · 2019-01-06 07:32 I never knew TPicshow, but maybe you will interested to try glSlideshow: http://forum.lazarus.freepascal.org/index.php/topic,35313.msg256719.ht ml#msg256719 ---------------------------------------------------------------------- WimVan · 2019-01-06 09:24 Thanks for the info and suggestion. But, where can I find the latest version of your component ? I will give it a try.  Curious to see if it does what I want. Meanwhile I tested version 0.95 Nice example, except. I fades in from a black background. I prefer a Fading in, out from the previous images, so we do not have a black intermedium.  When you look to very much images, it becomes disturbing and renders headache. ---------------------------------------------------------------------- Handoko · 2019-01-06 10:26 Quote from: WimVan on January 06, 2019, 10:24:47 amI prefer a Fading in, out from the previous images, so we do not have a black intermedium.  When you look to very much images, it becomes disturbing and renders headache. I understand what you meant. I'm not very proficient in using OpenGL. Actually, I wanted to create the transition as what you meant but I failed. So instead of direct fading, I created fade to black, white and background. The code is open source and I know there are many OpenGL experts here. Hope they will improve the code someday. ---------------------------------------------------------------------- WimVan · 2019-01-06 17:57 I was thinking in this direction .... 1) transparent yes.  Does thhis mean if I have a picture to fade in  is not visible, background is not visible to, so I look just through w kind of window. If this is the way it acts 1) a panel with a background fe black and then 2 timages with panel als parent, asigned as client . in that case I can construct an slideshow in the way i wanted. 2) finding out how to fade in timage. ---------------------------------------------------------------------- Handoko · 2019-01-06 18:23 Standard visual components do not support transparency, including TPanel. It's still possible to make it support transparency but you have to write the code, and put it on the OnPaint event. Maybe TPanel can be used but I think it is more suitable if you use TPaintBox or TOpenGLControl. I prefer TOpenGLControl because it is hardware accelerated. I think direct fading transition isn't too hard to write. Do you need it to support other effects? Maybe zooming, moving, etc. If it's just a simple image fading program, I can write it for you. But I'm busy currently, not available to do programming until March. You should do some research about BGRABitmap first. It supports transparency and it's relatively easy to learn: http://wiki.freepascal.org/BGRABitmap_tutorial ---------------------------------------------------------------------- circular · 2019-01-07 13:32 If you're writing your fading with BGRABitmap, you could use TBGRABitmap.CrossFade function to fade between two images. Otherwise to fade one image in, you can use PutImage with a value for the opacity parameter. Note that this works on a TBGRABitmap which is not a regular Canvas. The component TBGRAVirtualScreen and TBCGraphicControl from BGRAControls package can be used for this. TBGRAVirtualScreen and TPanel are opaque controls, they cannot have a transparent background. TBCGraphicControl can have a transparent background. I am wondering if it would be worth making a TBCTransparentImage control that could contain an image with transparent background and have an opacity property. ---------------------------------------------------------------------- WimVan · 2019-01-09 07:54 @circular Thanks for the suggestion. I tried to install BGRABITMap and the controls but ... When all installation is done, I can't find anywhere a component like 'BGRABitmap' 'TBGRAVirtualScreen' and 'TBCGraphicControl' are available ... What's wrong ? Lazarus 1.8.4 Online-installation used. ---------------------------------------------------------------------- balazsszekely · 2019-01-09 08:07 @WimVan QuoteWhen all installation is done, I can't find anywhere a component like 'BGRABitmapYou can find it on the component palette. It can be tedious though if you have a lots of components installed. As an alternative solution just press(Ctrl + Alt +P) or go to menu-->view-->components. After the components window appears go to the pallette tab and type bgra. ---------------------------------------------------------------------- WimVan · 2019-01-09 08:26 As I marked, these I have.  The only which I'l looking for is  BGRABitmap. ---------------------------------------------------------------------- Handoko · 2019-01-09 08:32 Lazarus main menu > View > Components > type: bgra ---------------------------------------------------------------------- balazsszekely · 2019-01-09 08:56 @WimVan QuoteAs I marked, these I have.  The only which I'l looking for is  BGRABitmap.OK. Maybe it's just me, but your message was a little bit confusing. Anyways BGRABitmap it's not a visual component, you cannot find it in the component pallette, just add BGRABitmap to the uses clauses, then similarly to a TBitmap declare it 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 var  BGRABitmap: TBGRABitmap; Please note that BGRABitmapPack must be in the required packages(see project inspector). If not you should add it first. ---------------------------------------------------------------------- WimVan · 2019-01-09 11:40 Ok, now I follow ...  I thought it was a visual component ... Thanks ---------------------------------------------------------------------- WimVan · 2019-01-12 08:11 A small question.  When I have created 2 image using bgradbitmap ... how now usig crossfade so I see the fadeing on the screen. I put it here in a button-click-event that calls a form refresh.  bgradbitmap .... seems very very powerful and it is, but the learning- curve is huge. And I find no all needed info to try it on my own.  There is a huge amount of doc too, which helps me, but I find no clear example. I understand I have to create a new image with the crossfade-function, but how show this action onto the screen ? Here my ugly code. 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 unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,  BGRABitmap, BGRABitmapTypes;type   { TForm1 }   TForm1 = class(TForm)    Button1: TButton;    procedure Button1Click(Sender: TObject);    procedure FormCreate(Sender: TObject);    procedure FormPaint(Sender: TObject);  private    image: TBGRABitmap;    image_1: TBGRABitmap;    image_2: TBGRABitmap;  public   end; var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.Button1Click(Sender: TObject);begin  image := TBGRABitmap.Create(image_1.Width,image_2.Height); //note that size may be different between bmp1 and bmp2  form1.Tag := 1;  form1.Repaint;end; procedure TForm1.FormCreate(Sender: TObject);begin  image_1 := TBGRABitmap.Create('F:\pict_test\img_044016d.jpg');  image_2 := TBGRABitmap.Create('F:\pict_test\img_044216d.jpg');end; procedure TForm1.FormPaint(Sender: TObject);begin  if form1.Tag = 1 then  begin    image.CrossFade(Rect(0,0,image.Width,image.Height), image, image, round(0.3*255), dmSet);    Form1.Tag := 2; // ready to next  end;end; end. ---------------------------------------------------------------------- circular · 2019-01-12 15:28 Hi Wim, First, try to display an image that is stretched how you want. You need to determine the ratio with something like that: Code: Delphi  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses math, Types; procedure TForm1.FormPaint(Sender: TObject);var ratio: single;  destRect: TRect;begin  image.SetSize(ClientWidth,ClientHeight);  image.Fill(BGRABlack);   ratio := min(image.width/image_1.width, image.height/image_1.height);  //determine destination size  destRect := rect(0,0, round(image_1.width*ratio), round(image_1.width*ratio));  //center rectangle  OffsetRect(destRect, (image.width - destRect.width) div 2, (image.height - destRect.height) div 2);   image.StretchPutImage(destRect, image_1, dmDrawWithTransparency, round(0.3*255) );   image.Draw(Canvas, 0,0);end; ---------------------------------------------------------------------- Thaddy · 2019-01-12 16:08 Sounds like the rather common case of  "TComponentThatWritesMyActualProgramWithoutEffortByMe" Programs are the result of some actual intellectual input. Even generated programs rely on that. ---------------------------------------------------------------------- Handoko · 2019-01-12 17:14 Quote from: WimVan on January 12, 2019, 09:11:06 ambgradbitmap .... seems very very powerful and it is, but the learning-curve is huge. And I find no all needed info to try it on my own. I think differently. Although, I haven't really use BGRABitmap but I can sure to tell you compare to other graphics libraries BGRABitmap is really easy to learn, the tutorials are very good. If the learning curve is huge for you, I'm sorry but lets face the truth. Graphics programming is not for you. Graphics programming is not simply calling a function and it works for you. You have to understand the logic behind it, you have to have the basic mathematics skills preferably advanced skill level. Again, sorry of being harsh. But it is actually good for you. Maybe it can motivates you or maybe makes you realize and give up for better. ---------------------------------------------------------------------- WimVan · 2019-01-12 17:44 Handoko, You are right. Graphic programming is not my real interest.  I'm a photographer and I'm busy with taking picture ... Meanwhile, I once wrote a program to repair faulting jpeg's ... and still it does.  And, it was written in pure C without a graphical available gui. I wrote this all in php for the web.  Here you can see what I mean: https://www.fotospotter.be where I wrote any thing myself ...  And the program admids more than what is visible for a guest, a photo- interested person... I rewrote anything till now and all is working except, I would like to have fade in fade out so a slideshow is nicer.  No more no less.  SO can someone insult me of not being a real graphical programmer ?  I never pretended this and I will never pretend. I thought that this site was to help persons... even dummies in certain cases ... But if this a problem, forget all my requests, .... I'll stop rendering my little app more pleaseable ... By the way, I once started at DOS 2.0  without a windows-interface, programmed on a COmmodore 24, 64 128, Amiga where I then, did graphical things. DOS 3 had his entry with Pascal ... Once I programmed in basic without the existence of linenumbers, ...  SO, I'm not a young person ... Any way, thanks to every body trying to help others. Sees PS. Here you can find what I wrote above https://groups.google.com/forum/#!topic/alt.comp.freeware/XfnR7aZnzak ---------------------------------------------------------------------- Handoko · 2019-01-12 17:51 I never meant to insult you. I wanted to motivate you. But if you think differently, I'm sorry. ---------------------------------------------------------------------- WimVan · 2019-01-12 18:59 you do not mean it, but you wrote it anyway. That's why I was looking for PicShow.  I used it in the years 2004 and it did it just what I try.  But, no development requiered, It was a component. @Thaddy, Thanks for the title and the message. I feel lucky.  Apart the fact that there is all needed info, doc and all is clear, there are still so much people with questions and problems with it. Sorry, yes this sounds negative. Case closed. ---------------------------------------------------------------------- Handoko · 2019-01-12 21:39 The misunderstanding happened because I forgot about your first post that you're looking for a ready to use slideshow component (TPictShow). I saw your later post that you're trying to do fading using BGRABitmap but you said the learning curve is huge. No, there is no free slideshow component available for Lazarus. You have to build the slideshow manually using one of the available graphics or game libraries. And BGRABitmap is relatively easy among them: http://wiki.freepascal.org/Graphics_libraries http://wiki.freepascal.org/Game_framework Maybe you don't want it anymore. But hope someone will find it useful: 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 unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,  ExtDlgs, ExtCtrls, BGRABitmap, BGRABitmapTypes; type   { TForm1 }   TForm1 = class(TForm)    btnImage2: TButton;    btnImage1: TButton;    OpenPictureDialog1: TOpenPictureDialog;    Timer1: TTimer;    procedure btnImage1Click(Sender: TObject);    procedure btnImage2Click(Sender: TObject);    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);    procedure FormCreate(Sender: TObject);    procedure FormPaint(Sender: TObject);    procedure FormResize(Sender: TObject);    procedure Timer1Timer(Sender: TObject);  private    Image1: TBGRABitmap;    Image2: TBGRABitmap;    Combined: TBGRABitmap;    ImageLoaded: Boolean;  end; const  TransitionDelayTime = 100;  // should be 5 .. 500  StillDelayTime      = 200;  // should be 0 .. 1000 var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.btnImage1Click(Sender: TObject);begin  if not(OpenPictureDialog1.Execute) then Exit;  Image1            := TBGRABitmap.Create(OpenPictureDialog1.FileName);  btnImage1.Enabled := False;  btnImage2.Enabled := True;end; procedure TForm1.btnImage2Click(Sender: TObject);begin  if not(OpenPictureDialog1.Execute) then Exit;  Image2            := TBGRABitmap.Create(OpenPictureDialog1.FileName);  Combined          := TBGRABitmap.Create(Width, Height);  ImageLoaded       := True;  Timer1.Enabled    := True;  btnImage1.Visible := False;  btnImage2.Visible := False;end; procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);begin  Timer1.Enabled := False;  Image1.Free;  Image2.Free;  Combined.Free;end; procedure TForm1.FormCreate(Sender: TObject);begin  btnImage2.Enabled := False;  ImageLoaded       := False;  Timer1.Enabled    := False;  Timer1.Interval   := 20;end; procedure TForm1.FormPaint(Sender: TObject);const  Transparency : Integer = 0;  StillDelay   : Integer = 0;  Transition   : Integer = 0;  Direction    : (From1To2, From2To1) = From1To2;var  ARect: TRect;begin   // Don't start before all image are loaded  if not(ImageLoaded) then Exit;   // Process direction changing  if Transition >= TransitionDelayTime then    if StillDelay <= 0 then    begin      StillDelay := StillDelayTime;      Transition := 0;      Inc(Direction);      if Direction > High(Direction) then      Direction := Low(Direction);    end;   // Process fading and show the result  ARect        := Rect(0, 0, Width, Height);  Transparency := Round(Transition / TransitionDelayTime * 255);  case Direction of  From1To2:      begin        Combined.StretchPutImage(ARect, Image1, dmDrawWithTransparency, 255);        Combined.StretchPutImage(ARect, Image2, dmDrawWithTransparency, Transparency);      end;    From2To1:      begin        Combined.StretchPutImage(ARect, Image2, dmDrawWithTransparency, 255);        Combined.StretchPutImage(ARect, Image1, dmDrawWithTransparency, Transparency);      end;  end;  Combined.Draw(Canvas, 0,0);   // Process delays  if StillDelay <= 0 then    Inc(Transition)  else    Dec(StillDelay); end; procedure TForm1.FormResize(Sender: TObject);begin  if not(ImageLoaded) then Exit;  Combined.Free;  Combined := TBGRABitmap.Create(Width, Height);end; procedure TForm1.Timer1Timer(Sender: TObject);begin  FormPaint(Self);end; end. The code for fading is on the lines 112 .. 121 The delay time can be adjusted on line 35 and line 36It supports form resizing, see line 131It does not support proportional image stretching scaling, see Circular post on reply #14 if you want it edit: The declaration of the constant "Transparency" on line 84 should be put on the line 89 as a variable. ---------------------------------------------------------------------- circular · 2019-01-13 02:05 In fact there is a slideshow under development https://gilles-vasseur.developpez.com/tutoriels/transitions/bgra1/ though I think there is no download link I don’t believe it helps to be harsh with people. If we don’t want to spend time on it we can simply say it. If we force ourselves to help it is bad for us and the other person. And we end up being passive aggressive or judgemental. It is sometimes difficult to ask for help because we show our vulnerability. So I would enjoy it to be a safe space here. ---------------------------------------------------------------------- WimVan · 2019-01-13 09:09 Quote from: circular on January 13, 2019, 03:05:38 amIt is sometimes difficult to ask for help because we show our vulnerability. So I would enjoy it to be a safe space here. I mis a thumb-up-icon .... ---------------------------------------------------------------------- Bart · 2019-01-13 09:59 Quote from: circular on January 13, 2019, 03:05:38 amIt is sometimes difficult to ask for help because we show our vulnerability. So I would enjoy it to be a safe space here. Yes, a safe place this shall remain. Not asking for help is obviously worse. We try to help as good as we can. For me, this assumes that whoever asks for help also must put in the effort (note: this is not a reflection upon TS). You might however be subjected to various degrees of humor  (especially when askig for help with homework assignments) Bart ---------------------------------------------------------------------- Handoko · 2019-01-13 16:31 How To Do Proportional Scaling Now I improved the source code to do proportional scaling. Doing proportional scaling is not hard but it is very difficult to explain it, especially with my limitation of English. First, look the code below. There are many optimizations can be done (for better performance), but I tried to wrote it in the more readable way: 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 unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,  ExtDlgs, ExtCtrls, BGRABitmap, BGRABitmapTypes; type   { TForm1 }   TForm1 = class(TForm)    btnImage2: TButton;    btnImage1: TButton;    OpenPictureDialog1: TOpenPictureDialog;    Timer1: TTimer;    procedure btnImage1Click(Sender: TObject);    procedure btnImage2Click(Sender: TObject);    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);    procedure FormCreate(Sender: TObject);    procedure FormPaint(Sender: TObject);    procedure FormResize(Sender: TObject);    procedure Timer1Timer(Sender: TObject);  private    Image1: TBGRABitmap;    Image2: TBGRABitmap;    Combined: TBGRABitmap;    ImageLoaded: Boolean;  end; const  TransitionDelayTime = 100;  // should be 5 .. 500  StillDelayTime      = 200;  // should be 0 .. 1000 var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.btnImage1Click(Sender: TObject);begin  if not(OpenPictureDialog1.Execute) then Exit;  Image1            := TBGRABitmap.Create(OpenPictureDialog1.FileName);  btnImage1.Enabled := False;  btnImage2.Enabled := True;end; procedure TForm1.btnImage2Click(Sender: TObject);begin  if not(OpenPictureDialog1.Execute) then Exit;  Image2            := TBGRABitmap.Create(OpenPictureDialog1.FileName);  Combined          := TBGRABitmap.Create(Width, Height);  ImageLoaded       := True;  Timer1.Enabled    := True;  btnImage1.Visible := False;  btnImage2.Visible := False;end; procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);begin  Timer1.Enabled := False;  Image1.Free;  Image2.Free;  Combined.Free;end; procedure TForm1.FormCreate(Sender: TObject);begin  btnImage2.Enabled := False;  ImageLoaded       := False;  Timer1.Enabled    := False;  Timer1.Interval   := 20;end; procedure TForm1.FormPaint(Sender: TObject);const  StillDelay   : Integer = 0;  Transition   : Integer = 0;  Direction    : (From1To2, From2To1) = From1To2;var  Transparency  : Integer;  AspectForm      : Single;  AspectImage1    : Single;  AspectImage2    : Single;  Image1NewWidth  : Integer;  Image1NewHeight : Integer;  Image2NewWidth  : Integer;  Image2NewHeight : Integer;  RectImage1      : TRect;  RectImage2      : TRect;begin   // Don't start before all image are loaded  if not(ImageLoaded) then Exit;   // Process direction changing  if Transition >= TransitionDelayTime then    if StillDelay <= 0 then    begin      StillDelay := StillDelayTime;      Transition := 0;      Inc(Direction);      if Direction > High(Direction) then        Direction := Low(Direction);    end;   // Calculations for proportional scaling  AspectForm   := Width / Height;  AspectImage1 := Image1.Width / Image1.Height;  AspectImage2 := Image2.Width / Image2.Height;  if AspectForm > AspectImage1 then // use same height  begin    Image1NewHeight := Height;    Image1NewWidth  := Round(Image1NewHeight * AspectImage1);  end  else begin                      // use same width    Image1NewWidth  := Width;    Image1NewHeight := Round(Image1NewWidth / AspectImage1);  end;  if AspectForm > AspectImage2 then // use same height  begin    Image2NewHeight := Height;    Image2NewWidth  := Round(Image2NewHeight * AspectImage2);  end  else begin                        // use same width    Image2NewWidth  := Width;    Image2NewHeight := Round(Image2NewWidth / AspectImage2);  end;  RectImage1.Left   := (Width-Image1NewWidth) div 2;   // Make the image center  RectImage1.Top    := (Height-Image1NewHeight) div 2; // Make the image center  RectImage1.Width  := Image1NewWidth;  RectImage1.Height := Image1NewHeight;  RectImage2.Left   := (Width-Image2NewWidth) div 2; // Make the image center  RectImage2.Top    := (Height- Image2NewHeight) div 2; // Make the image center  RectImage2.Width  := Image2NewWidth;  RectImage2.Height := Image2NewHeight;   // Process fading and show the result  Transparency := Round(Transition / TransitionDelayTime * 255);  case Direction of    From1To2:      begin        Combined.StretchPutImage(RectImage1, Image1, dmDrawWithTransparency, 255);        Combined.StretchPutImage(RectImage2, Image2, dmDrawWithTransparency, Transparency);      end;    From2To1:      begin        Combined.StretchPutImage(RectImage2, Image2, dmDrawWithTransparency, 255);        Combined.StretchPutImage(RectImage1, Image1, dmDrawWithTransparency, Transparency);      end;  end;  Combined.Draw(Canvas, 0,0);   // Process delays  if StillDelay <= 0 then    Inc(Transition)  else    Dec(StillDelay); end; procedure TForm1.FormResize(Sender: TObject);begin  if not(ImageLoaded) then Exit;  Combined.Free;  Combined := TBGRABitmap.Create(Width, Height);end; procedure TForm1.Timer1Timer(Sender: TObject);begin  FormPaint(Self);end; end. The code for doing proportional scaling starts from line #114 .. # 143. You need to supply the image's x, y, w, h when showing it. That's why I added RectImage1 and RectImage2. See the example on line #150 and #151. The x and y values of RectImages are not (0, 0). Because (0, 0) mean top left corner. So we have to calculate the center position. The calculation are performed on the line #136, #137, #140, #141. To be able to calculate the center position, we have to calculate the image's width and height first. And this is the most tricky part. This is the pseudo code:   if AspectOfContainer > AspectOfObject then   begin       // object use the height of container       ObjectNewHeight := container's Height;       // and we calculate the object's width       ObjectNewWidth  := Round(ObjectNewHeight * AspectOfObject);   end   else begin                             // object use the width of container       ObjectNewWidth  := container's Width;       // and we calculate the object's height       ObjectNewHeight := Round(ObjectNewWidth / AspectOfObject);   end; Note: The code for calculating object's new width and new height is on the line #118 .. #135. To be able to calculate the object's new width or height we need the Aspect value of the object. You can use wikipedia to learn more about aspect. In graphics programming you can use aspect to calculate the new size of object by using these formulas: Object_New_Width = Object_New_Height x Aspect_Of_The_Object and Object_New_Height = Object_New_Width / Aspect_Of_The_Object See the pseudocode to learn how to use these formulas. We have to add Round function because BGRABitmap needs integer values for those inputs. And the last thing is the how to calculate the aspects. In our case we need 3 aspects: - Aspect of the container -> the form itself - Aspect of the object1 -> Image1 - Aspect of the object2 -> Image2 See line #115 .. #117. The explanation above is in a reverse-way. In short, this is how you do proportional scaling (in the 'correct' non reverse-way): First calculate the aspect of the container and aspect of the objectCalculate the object new width if (AspectOfContainer > AspectOfObject)Calculate the object new height if (AspectOfContainer <= AspectOfObject)Calculate the center position of the objectNow you have the x, y, w, h Graphics programming is fun ... as long as you have the passion to do it. Have fun! ---------------------------------------------------------------------- circular · 2019-01-13 17:39 Looks great Handoko. Some remarks: - the size of the drawable part is ClientWidth x ClientHeight, not Width x Height (you can also read the value of Combined.Width and Combined.Height so that the drawing is consistent with the virtual screen size) - calling FromPaint directly works on Windows and Linux but not on MacOS. Instead you can call Invalidate. This may cause some blinking depending on the system, so you need to prevent the erase background event or set the DoubleBuffered property to True. ---------------------------------------------------------------------- Handoko · 2019-01-13 17:47 In the source code I provided above, because the container is the form itself so the client width and client height is the form's width and height. It can be simplified by using width and height only, because the Self is the form. But I agree if someone copy/pasted the code, without the 'client' it has higher chances of failure. I don't have a Mac. But, I will remember to use Invalidate (instead of Form's Paint) and use Double Buffer. Thank you for the suggestions. edit: Suggestion for BGRABitmap, please consider to add proportional scaling feature. ---------------------------------------------------------------------- WimVan · 2019-01-13 20:44 Handoko, Runs well, except, if you have a a landscaped image and a portrait- image,  when the fade in image is the portrait, you still see parts of the first image ... I too tried something.  I used bgrabitmap and crossfade;  It runs well, except, I have no proportial scaling. For crossfade you need two images with the same width, height.  Portrait and landscape isn't So I was thinking to create an image (runtime) which covers the whole canvas-area after I draw an image on it respecting proportial scaling and centering it.  Of course, this may not been seen while showing the slideshow.  It should have been done in memory.  If I find this out, I'll can finalise my version. Still interested if you can fade in the new image while fade out the second one.  This is what crossfade does. 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 unit slide_1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,  ExtCtrls, math, types, BGRABitmap, BGRABitmapTypes; type   { TForm1 }   TForm1 = class(TForm)    knop: TButton;    procedure FormWindowStateChange(Sender: TObject);    procedure knopClick(Sender: TObject);    procedure FormCreate(Sender: TObject);    procedure FormPaint(Sender: TObject);  private    image: TBGRABitmap;    image_from : TBGRABitmap;    image_to   : TBGRABitmap;   public   end; var  Form1: TForm1;  nfoto : integer; implementation {$R *.lfm} { TForm1 } procedure TForm1.knopClick(Sender: TObject);var  nknop : integer;  str_foto_from, str_foto_to : string;begin  if nfoto = 0 then  begin    str_foto_from := 'img_044000d.jpg';    str_foto_to   := 'img_045014d.jpg';  end;  if nfoto = 1 then  begin    str_foto_from := 'img_045014d.jpg';    str_foto_to   := 'img_044333d.jpg';  end;  if nfoto = 2 then  begin    str_foto_from := 'img_044333d.jpg';    str_foto_to   := 'img_042000d.jpg';  end;  image_from.LoadFromFile( str_foto_from);// change image-size to a fullsized form  BGRAReplace(image_from, image_from.Resample(Form1.Width, Form1.Height, rmSimpleStretch));   image_to.LoadFromFile( str_foto_to );  // change image-size to a fullsized form  BGRAReplace(image_to, image_to.Resample(Form1.Width, Form1.Height, rmSimpleStretch));   nfoto := nfoto + 1;  if nfoto = 3 then nfoto := 0; // fading using crossqfade by incresing transparency-value (from 1 to 255 by step of 5  for nknop := 1 to 51 do  begin    knop.Tag := nknop;    form1.Tag := 1;// call form-paint-event    form1.Repaint;  end;end; procedure TForm1.FormWindowStateChange(Sender: TObject);begin  image.SetSize(ClientWidth,ClientHeight);  image.Fill(BGRABlack);end;  procedure TForm1.FormCreate(Sender: TObject);begin  image_from := TBGRABitmap.Create;  image_to   := TBGRABitmap.Create;  image      := TBGRABitmap.Create;  image.SetSize(ClientWidth,ClientHeight);  image.Fill(BGRABlack);  nfoto := 0;end; procedure TForm1.FormPaint(Sender: TObject);var r  destRect: TRect;begin  if form1.Tag = 1 then  begin// create an image from two images with transparency  FormPaint is put in a loop while increasing the transparancy of image 2(image_to), decreasing image 1 (image_from)    image.CrossFade(Rect(0,0,image.Width, image.Height), image_from, image_to, round(knop.tag * 5), dmSet);      sleep( 20 );    image.   Draw(Canvas, 0,0);    Form1.Tag := 2; // ready to next  end;end; end.  used images are added.  Image img_044333d.jpg is portrait and as I told, proportial scaling is still not set Due to limitation of attachments-size I added bad looking images (size 200 pixel-150 pixel) ---------------------------------------------------------------------- gillou58 · 2019-01-14 08:28 Hi, As circular suggested, perhaps you will be interested in a component I wrote a few months ago for teaching purpose. For the moment explanations are only in French. I will try to work on it ASAP if someone is interested in this kind of work. You have to install the excellent BRABitmap library first. The TGVTransition Component is in the gvsoft package. You have to install it too. There is a demo in the sample directory. If you can't read French, compile this program just click on the Test button and try to change the options values. There are https://www.developpez.net/forums/d1869926/autres- langages/pascal/lazarus/creer-transitions-d-image-image-lazarus- bgrabitmap-7-composant-complet/seven tutorials (all in French ) to explain how I wrote this component. [EDIT] Demo is here : https://www.dropbox.com/s/jpmsd5gpt4rwzhy/demo.7z?dl=0 Gilles ---------------------------------------------------------------------- circular · 2019-01-14 11:59 Quote from: Handoko on January 13, 2019, 06:47:39 pmIn the source code I provided above, because the container is the form itself so the client width and client height is the form's width and height. It can be simplified by using width and height only, because the Self is the form. But I agree if someone copy/pasted the code, without the 'client' it has higher chances of failure.Nope, the Form Width is a few pixels bigger than the Form ClientWidth as it contains the form border. QuoteSuggestion for BGRABitmap, please consider to add proportional scaling feature.Sure. I've added StretchPutImageProportionally on dev branch.  Hence the code becomes: Code: Delphi  [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.FormPaint(Sender: TObject);const  StillDelay   : Integer = 0;  Transition   : Integer = 0;  Direction    : (From1To2, From2To1) = From1To2;var  Transparency    : Integer;  r: TRect;begin   // Don't start before all image are loaded  if not(ImageLoaded) then Exit;   // Process direction changing  if Transition >= TransitionDelayTime then    if StillDelay <= 0 then    begin      StillDelay := StillDelayTime;      Transition := 0;      Inc(Direction);      if Direction > High(Direction) then        Direction := Low(Direction);    end;   // Process fading and show the result  Transparency := Round(Transition / TransitionDelayTime * 255);  Combined.Fill(BGRABlack);  r := Rect(0,0,Combined.Width,Combined.Height);  case Direction of    From1To2:      begin        Combined.StretchPutImageProportionally(r, taCenter,tlCenter, Image1, dmDrawWithTransparency, 255);        Combined.StretchPutImageProportionally(r, taCenter,tlCenter, Image2, dmDrawWithTransparency, Transparency);      end;    From2To1:      begin        Combined.StretchPutImageProportionally(r, taCenter,tlCenter, Image2, dmDrawWithTransparency, 255);        Combined.StretchPutImageProportionally(r, taCenter,tlCenter, Image1, dmDrawWithTransparency, Transparency);      end;  end;  Combined.Draw(Canvas, 0,0);   // Process delays  if StillDelay <= 0 then    Inc(Transition)  else    Dec(StillDelay); end; @gillou58: Thanks for the link. My mistake there was a download link: https://pascal.developpez.com/telecharger/detail/id/6236/TGVTransition -composant-visuel-pour-l-affichage-de-transitions-d-image-a-image @WimVan: I see your point. Indeed when images do not have the same aspect ratio, the previous image does not disappear as the fading occurs. You can generate your stretched images like that: Code: Delphi  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   function CreateStretched(AImage: TBGRABitmap): TBGRABitmap;  var    ratio: single;  begin    result := TBGRABitmap.Create(Combined.Width,Combined.Height, BGRABlack);    ratio := min(Combined.Width/AImage.Width,Combined.Height/AImage.Height);    r := rect(0,0,round(AImage.Width*ratio),round(AImage.Height*ratio));    r.Offset((Combined.Width-r.Width) div 2, (Combined.Height-r.Height) div 2);    result.StretchPutImage(r, AImage, dmDrawWithTransparency);  end; I noticed CrossFade was slow so I just optimized it a bit on dev branch. ---------------------------------------------------------------------- Handoko · 2019-01-14 12:43 @WimVan I tested your source code. It seems you're not familiar with event- driven programming. But that's okay, it is easy and you'll like it once you understand how it works. I rewrote your code, added some improvements. But not much, still does not support proportional scaling. Here is the source code: 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 unit slide_1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,  ExtCtrls, math, types, BGRABitmap, BGRABitmapTypes, BGRAGraphicControl; type   { TForm1 }   TForm1 = class(TForm)    knop: TButton;    Timer1: TTimer;    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);    procedure FormWindowStateChange(Sender: TObject);  procedure knopClick(Sender: TObject);    procedure FormCreate(Sender: TObject);    procedure Timer1Timer(Sender: TObject);  private    image: TBGRABitmap;    image_from : TBGRABitmap;    image_to   : TBGRABitmap;    nfoto      : integer;    TimerIndex : integer;    TimerStep  : integer;  end; var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.knopClick(Sender: TObject);var  nknop : integer;  str_foto_from, str_foto_to : string;begin  if nfoto = 0 then  begin    str_foto_from := 'img_044000d.jpg';    str_foto_to := 'img_045014d.jpg';  end;  if nfoto = 1 then  begin    str_foto_from := 'img_045014d.jpg';    str_foto_to   := 'img_044333d.jpg';  end;  if nfoto = 2 then  begin    str_foto_from := 'img_044333d.jpg';    str_foto_to   := 'img_042000d.jpg';  end;  image_from.LoadFromFile( str_foto_from);// change image-size to a fullsized form  BGRAReplace(image_from, image_from.Resample(Form1.Width, Form1.Height, rmSimpleStretch));   image_to.LoadFromFile( str_foto_to );  // change image-size to a fullsized form  BGRAReplace(image_to, image_to.Resample(Form1.Width, Form1.Height, rmSimpleStretch));   nfoto := nfoto + 1;  if nfoto = 3 then nfoto := 0; // fading using crossqfade by incresing transparency- value (from 1 to 255 by step of 5  TimerIndex     := 0;  TimerStep    := 5;  Timer1.Enabled := True;end; procedure TForm1.FormWindowStateChange(Sender: TObject);begin  image.SetSize(ClientWidth,ClientHeight);  image.Fill(BGRABlack);end; procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);begin  Timer1.Enabled := False;  image_from.Free;  image_to.Free;  image.Free;end; procedure TForm1.FormCreate(Sender: TObject);begin  image_from := TBGRABitmap.Create;  image_to   := TBGRABitmap.Create;  image      := TBGRABitmap.Create;  image.SetSize(ClientWidth,ClientHeight);  image.Fill(BGRABlack);  nfoto := 0;   Timer1.Interval := 20;  Timer1.Enabled  := False;end; procedure TForm1.Timer1Timer(Sender: TObject);begin  image.CrossFade(Rect(0,0,image.Width, image.Height), image_from, image_to, TimerIndex, dmSet);  image.Draw(Canvas, 0,0);  if TimerIndex  < 255-TimerStep then    TimerIndex := TimerIndex + TimerStep;  Application.ProcessMessages; // avoid to become unresponsiveend; end. Note: if you want to compare source codes, I recommend Meld http://meldmerge.org/ 1. Use a TTimer for the looping I saw you did this:   for nknop := 1 to 51 do   begin     knop.Tag := nknop;     form1.Tag := 1; // call form-paint-event     form1.Repaint;   end; Calling Form.Repaint (refresh or invalidate) several times for doing the transition is not correct. The easiest solution for it is use a TTimer, see line #105 .. #112. This is the documentation of TTimer: https://lazarus-ccr.sourceforge.io/docs/lcl/extctrls/ttimer.html On my previous codes (fade.zip and fade2.zip) I put the code for drawing in the OnPaint event and use a TTimer to 'force' the canvas the refresh by calling the OnPaint event. But this time I did it differently, to make the code more readable. I now moved all the code inside OnPaint into OnTimer, so there is nothing for OnPaint event. 2. Set the values of the TTimer We need to provide the values for the TTimer when program starts and when user clicks the button. See line #101 .. #102 and line #73 .. #75. 3. Free the objects We should free the objects before the program ends, see line #84 .. #90. For your information, not all components need to be freed manually because it will handled by its owner. 4. Prevent unresponsive In GUI programming, the interface can become unresponsive if a looping runs too long. To prevent it, we use Application.ProcessMessages; see line #111. In this code, you won't notice any serious unresponsive thing to happens if you remove that line but you will experience some delay if you click the close button when the transition is running. 5. Move the global variable to form's private section For more beautiful code, I move the variable nfoto to the form's private section. Form's private section is the good place to put variables, see line #23 .. #29. 6. Use more descriptive name I renamed your nknop and knop.tag to something more descriptive. See line #73 .. #74. 7. Don't use component's tag It is not a sin but it may cause the source code become harder to maintain in the future. So some programmers ... including @Thaddy disagree the use of tags. So I removed your knop.tag and form1.tag. ---------------------------------------------------------------------- Handoko · 2019-01-14 12:49 Quote from: circular on January 14, 2019, 12:59:30 pmQuote from: Handoko on January 13, 2019, 06:47:39 pmIn the source code I provided above, because the container is the form itself so the client width and client height is the form's width and height. It can be simplified by using width and height only, because the Self is the form. But I agree if someone copy/pasted the code, without the 'client' it has higher chances of failure.Nope, the Form Width is a few pixels bigger than the Form ClientWidth as it contains the form border. I never know it, I will make a test for it. Quote from: circular on January 14, 2019, 12:59:30 pmI've added StretchPutImageProportionally on dev branch.  That's great! ---------------------------------------------------------------------- WimVan · 2019-01-14 14:12 Thanks Handoko ... Please note, that, when I write tests, I do it in a badly way, without cleaning, ... without capting errors, freeing objects, memory ...  Why.  It is draft and I prefer investigating trials and errors in a quick way, the cleanup, definite version comes later. That's the way I always developed.  A prototype with garbage programming, but with a logic I want to use, see. Optimizing, cleanup ... comes later if I'm sure all is working as I like. But, Thanks for the info. Meanwhile I  worked again some hours (from this morning 4 o clock) on testing, reading on the internet, insulting my desktop, my bad memory ...  Finally I got all working like I whished. Source are not optimized as you did, because I worked on the previous trial.  Tonight I'll write a proper one.  But, it is just to see if my logic was write and if it runs. Goal: a slide-show without black moments.  Proportial ratio must be kept, eventually time of transition  must be adaptable, ...  Backgroundcolor must be adaptive. I uses crossfade.  But, to get this properly working I created an temp-image where I get a black image.  This is not the same as the background.  The fact that it is an image it is treated as an image so it is not transparent (background is) and ther is the glue to remove parts of the previous image when transition takes place (You see that when you slide between a landscape and a portrait). This is also usable to start a presentation from a black image (this is changeable so one of my goals is done). For the moment I used sleep for the transition, but of course and you are right, it is better to use a timer.  But in draft using sleep is quicker (I'm sometime very lazy) I uses the canvas of a form, but it can be something else.  Be aware, in that case I must change the existent references to Form.  In my optimized version it will be a parameter. See it as follow, this code I made is the start-up for more.  But I had to know if it was possible and yes, it does. For those who want the full-size images, source and executable, you can this with the url: http://fotospotter.be/_all_download/slide.zip Here is the code: (I did not added your ideas, corrections , they will be inserted later. 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 unit slide_1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,  ExtCtrls, types, BGRABitmap, BGRABitmapTypes; type   { TForm1 }   TForm1 = class(TForm)    knop: TButton;    procedure FormResize(Sender: TObject);    procedure FormWindowStateChange(Sender: TObject);    procedure knopClick(Sender: TObject);    procedure FormCreate(Sender: TObject);    procedure FormPaint(Sender: TObject);  private    image    : TBGRABitmap;    image_from : TBGRABitmap;    image_to   : TBGRABitmap;    procedure resize_to_slide_show( work_image: TBGRABitmap; str_image : string );   public   end; var  Form1: TForm1;  nfoto : integer; implementation {$R *.lfm} { TForm1 }  //----------------------------------------------------- procedure TForm1.resize_to_slide_show( work_image: TBGRABitmap; str_image : string );var  FormVerhouding      : Single;  BeeldVerhouding     : Single;  SlideBreedte   : Integer;  SlideHoogte  : Integer;  RectSlide       : TRect;  image_tmp       : TBGRABitmap;begin   try    RectSlide       := TRect.Create(0,0,Form1.Width,Form1.Height); //  load backgroundimage to fill whole projectioncanvas    image_tmp := TBGRABitmap.Create( 'black.jpg' );     work_image.StretchPutImage(RectSlide, image_tmp, dmset, 255);    image_tmp.Free; // get picture to be loaded    image_tmp := TBGRABitmap.Create( str_image ); // scale en ratio    FormVerhouding  := Form1.Width / Form1.Height;    BeeldVerhouding := image_tmp.Width / image_tmp.Height;     if FormVerhouding > BeeldVerhouding then // use same height    begin      SlideHoogte := Form1.Height;      SlideBreedte  := Round(SlideHoogte * BeeldVerhouding);    end    else begin                        // use same width      SlideBreedte  := Form1.Width;      SlideHoogte := Round(SlideBreedte / BeeldVerhouding);    end;    if (image_tmp.Width < form1.Width) or     (image_tmp.Height < form1.Height) then    begin      image_tmp.ResampleFilter := rfBestQuality;      BGRAReplace(image_tmp, image_tmp.Resample(form1.Width, form1.Height));    end; // center SLide    RectSlide.Left   := (Form1.Width  - SlideBreedte)  div 2;    RectSlide.Top    := (Form1.Height - SlideHoogte) div 2;    RectSlide.Width  := SlideBreedte;    RectSlide.Height := SlideHoogte;     work_image.StretchPutImage(RectSlide, image_tmp, dmSet, 255);   finally    image_tmp.Free;  end;end; //---------------- -------------------------------------- procedure TForm1.knopClick(Sender: TObject);var  nknop : integer;  str_foto_from, str_foto_to : string;begin  Knop.Visible := false;  if nfoto = 0 then  begin    str_foto_from := 'black.jpg';    str_foto_to := 'img_044000d.jpg';  end;  if nfoto = 1 then  begin    str_foto_from := 'img_044000d.jpg';    str_foto_to   := 'img_045014d.jpg';  end;  if nfoto = 2 then  begin    str_foto_from := 'img_045014d.jpg';    str_foto_to   := 'img_044333d.jpg';  end;  if nfoto = 3 then  begin    str_foto_from := 'img_044333d.jpg';    str_foto_to   := 'img_042000d.jpg';  end;  if nfoto = 4 then  begin  str_foto_from := 'img_042000d.jpg';    str_foto_to   := 'black.jpg';  end;   nfoto := nfoto + 1;  if nfoto = 5 then nfoto := 0;   resize_to_slide_show( image_from, str_foto_from );  resize_to_slide_show( image_to, str_foto_to );   for nknop := 1 to 51 do  begin    knop.Tag := nknop;    form1.Tag := 1;    form1.Repaint;  end;  Knop.Visible := true;end;  procedure TForm1.FormWindowStateChange(Sender: TObject);begin    image.SetSize(ClientWidth,ClientHeight);  image.Fill(BGRAWhite); end; procedure TForm1.FormResize(Sender: TObject);begin  image_from.SetSize(ClientWidth,ClientHeight);  image_to.SetSize(ClientWidth,ClientHeight);  image.SetSize(ClientWidth,ClientHeight);end; procedure TForm1.FormCreate(Sender: TObject);begin  image_from := TBGRABitmap.Create(ClientWidth,ClientHeight);  image_to   := TBGRABitmap.Create(ClientWidth,ClientHeight);  image      := TBGRABitmap.Create(ClientWidth,ClientHeight);//  image.SetSize(ClientWidth,ClientHeight);  image.Fill(BGRABlack);  nfoto := 0;end; procedure TForm1.FormPaint(Sender: TObject);var  destRect: TRect;begin  if form1.Tag = 1 then  begin    OffsetRect(destRect, (image.width - destRect.width) div 2, (image.height - destRect.height) div 2);    image.CrossFade(Rect(0,0,image.Width, image.Height), image_from, image_to, round(knop.tag * 5), dmSet);    sleep( 20 );    image.Draw(Canvas, 0,0);    Form1.Tag := 2; // ready to next  end;end; end.  So, any way, thanks for the info, addings, suggestions... I'll pass the definite version within some days ..   Now I have to find out how I can insert google maps. By the way, This slideshow is is already written, but without the transition.  And slides can be mixed with video-parts.  This runs already.  Now I can remove the black intervals. ---------------------------------------------------------------------- Handoko · 2019-01-14 15:13 I've just tried your new code. It compiled but I got SIGSEGV error if I click the start/next button. While your previous version seems to run okay unless the fading transition not working yet. Quote from: WimVan on January 14, 2019, 03:12:59 pmNow I have to find out how I can insert google maps. ...  And slides can be mixed with video-parts. I remember there were several discussions about google maps and video playback here. I think you may get what you need by searching the forum. Quote from: WimVan on January 14, 2019, 03:12:59 pm... when I write tests, I do it in a badly way, without cleaning, ... without capting errors, freeing objects, memory ... Yes, I understand. And I was the same as you. I ever posted my prototype code in the forum and I got critiques from Thaddy. It feels bad if we receive critique, but I try to take the positive side. Now I always write my code as beautiful, maintainable and readable as I can, even when prototyping. And it becomes my habit. The advantage of it, is no need to do cleaning up to upgrade the prototype to become definite version. Thaddy's words often sound harsh. But his nitpicking about the security and maintainability of the source code, makes me now write better code. ---------------------------------------------------------------------- WimVan · 2019-01-14 16:13 handoko I see that the attachment was not succesfull.  The reason why you got the error is the lack of black.jpg. Here the attachment with all used sources I already merged a week ago video's too in the slideshow.  Now I have to merge the transition Look at your first code please. Proportial scale is good, but if you transition from a landscaped picture to a portrait, parts of the landscape picture remain. ---------------------------------------------------------------------- Handoko · 2019-01-14 16:55 Tested your new upload. But I got an error. Ignoring it, I got the second error. For your information, I use Linux. It seems you work too much and you need some proper sleep to re- energize your power. Quote from: WimVan on January 14, 2019, 05:13:04 pmhandoko Proportial scale is good, but if you transition from a landscaped picture to a portrait, parts of the landscape picture remain. I've just checked it. Yes, you're right I saw the issue. ---------------------------------------------------------------------- WimVan · 2019-01-15 09:19 @Handoko I took your advice ...  Went to sleep. Next code should work now.  I added a kind of stop in the timer to, otherwise I see that is is updating whole the time, even it no fading is no more needed and we wait till the start-next is clicked. It is programmed on a Win10, so I'm not sure that this runs on Linux, but normally it should. I used your cleaned up version.  Added a procedure to resize, proportial scale and add a black-image to the BGRABitmap-container (I see this as a container), so it can be used for as well the from-image and the to-image. .... In future I'll try doing proper development in prototyping ... 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 unit slide_1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,  ExtCtrls, types, BGRABitmap, BGRABitmapTypes; type   { TForm1 }   TForm1 = class(TForm)    Show_slide_button: TButton;    Slide_panel: TPanel;  Timer1: TTimer;    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);    procedure FormWindowStateChange(Sender: TObject);    procedure Show_slide_buttonClick(Sender: TObject);    procedure FormCreate(Sender: TObject);    procedure Timer1Timer(Sender: TObject);  private    image: TBGRABitmap;    image_from : TBGRABitmap;    image_to   : TBGRABitmap;    nfoto      : integer;    TimerIndex : integer;    TimerStep  : integer;    procedure resize_to_slide_show( work_image: TBGRABitmap; str_image : string );  end; var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.resize_to_slide_show( work_image: TBGRABitmap; str_image : string );var  FormVerhouding  : Single;  BeeldVerhouding : Single;  SlideBreedte    : Integer;  SlideHoogte     : Integer;  RectSlide       : TRect;  image_tmp       : TBGRABitmap;begin   try  RectSlide       := TRect.Create(0,0,Slide_panel.Width,Slide_panel.Height);  //  load backgroundimage to fill whole projectioncanvas    image_tmp := TBGRABitmap.Create( 'black.jpg' );    work_image.StretchPutImage(RectSlide, image_tmp, dmset, 255);    image_tmp.Free; // get picture to be loaded    image_tmp := TBGRABitmap.Create( str_image ); // scale en ratio    FormVerhouding  := Slide_panel.Width / Slide_panel.Height;    BeeldVerhouding := image_tmp.Width / image_tmp.Height;     if FormVerhouding > BeeldVerhouding then // use same height    begin      SlideHoogte := Slide_panel.Height;      SlideBreedte  := Round(SlideHoogte * BeeldVerhouding);    end    else begin                        // use same width      SlideBreedte  := Slide_panel.Width;      SlideHoogte := Round(SlideBreedte / BeeldVerhouding);    end;    if (image_tmp.Width < Slide_panel.Width) or       (image_tmp.Height < Slide_panel.Height) then    begin      image_tmp.ResampleFilter := rfBestQuality;      BGRAReplace(image_tmp, image_tmp.Resample(Slide_panel.Width, Slide_panel.Height));    end; // center SLide    RectSlide.Left   := (Slide_panel.Width  - SlideBreedte)  div 2;    RectSlide.Top    := (Slide_panel.Height - SlideHoogte) div 2;    RectSlide.Width  := SlideBreedte;    RectSlide.Height := SlideHoogte;     work_image.StretchPutImage(RectSlide, image_tmp, dmSet, 255);   finally    image_tmp.Free;  end;end;  procedure TForm1.Show_slide_buttonClick(Sender: TObject);var  str_foto_from, str_foto_to : string; begin  if nfoto = 0 then  begin    str_foto_from := 'black.jpg';    str_foto_to   := 'img_044000d.jpg';  end;  if nfoto = 1 then  begin    str_foto_from := 'img_044000d.jpg';    str_foto_to := 'img_045014d.jpg';  end;  if nfoto = 2 then  begin    str_foto_from := 'img_045014d.jpg';    str_foto_to   := 'img_044333d.jpg';  end;  if nfoto = 3 then  begin    str_foto_from := 'img_044333d.jpg';    str_foto_to   := 'img_042000d.jpg';  end;  if nfoto = 4 then  begin    str_foto_from := 'img_042000d.jpg';    str_foto_to   := 'black.jpg';  end;   resize_to_slide_show( image_from, str_foto_from );   resize_to_slide_show( image_to, str_foto_to );   nfoto := nfoto + 1;  if nfoto = 5 then nfoto := 0; // fading using crossqfade by incresing transparency-value (from 1 to 255 by step of 5  TimerIndex     := 0;  TimerStep      := 5;  Timer1.Enabled := True;end; procedure TForm1.FormWindowStateChange(Sender: TObject);begin  image_from.SetSize(Slide_panel.Width,Slide_panel.Height);  image_to.SetSize(Slide_panel.Width,Slide_panel.Height);  image.SetSize(Slide_panel.Width,Slide_panel.Height);  image.Fill(BGRABlack);end; procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);begin  Timer1.Enabled := False;  image_from.Free;  image_to.Free;  image.Free;end; procedure TForm1.FormCreate(Sender: TObject);begin  image_from := TBGRABitmap.Create( Slide_panel.Width,Slide_panel.Height );  image_to := TBGRABitmap.Create( Slide_panel.Width,Slide_panel.Height );  image      := TBGRABitmap.Create( Slide_panel.Width,Slide_panel.Height );  image.Fill(BGRABlack);  nfoto := 0;   Timer1.Interval := 20;  Timer1.Enabled  := False;end; procedure TForm1.Timer1Timer(Sender: TObject);begin  image.CrossFade(Rect(0,0,image.Width, image.Height), image_from, image_to, TimerIndex, dmSet);  image.Draw(Slide_panel.Canvas, 0,0);  if TimerIndex  < 255-TimerStep then    TimerIndex := TimerIndex + TimerStep    else Timer1.Enabled:=false;;  Application.ProcessMessages; // avoid to become unresponsiveend; end. ---------------------------------------------------------------------- Handoko · 2019-01-15 13:59 Finally, your baseslide3 works! I got an error but it's easy solved after I copied the images from your previous post. ---------------------------------------------------------------------- WimVan · 2019-01-17 09:29 @Handoko We have a logical problem, error in the timer-event 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.Timer1Timer(Sender: TObject);begin  image.CrossFade(Rect(0,0,image.Width, image.Height), image_from, image_to, TimerIndex, dmSet);  image.Draw(Slide_panel.Canvas, 0,0);  if TimerIndex  < 255-TimerStep then    TimerIndex := TimerIndex + TimerStep    else Timer1.Enabled:=false;;  Application.ProcessMessages; // avoid to become unresponsiveend; This routine runs correct as long 255 is divisible by Timerstep. BUt, if it is not divisible, Timerindex will never be 255, so the transition is never done completly (read 255).  This means that when the refresh stops, still parts will be visible of the first image.  Nearly completly fade out, but not wiped. I modified it this way procedure TForm1.Timer1Timer(Sender: TObject); begin   if TimerIndex  > 255 then TimerIndex := 255;  // transparenty greater than 255 returns an error   image.CrossFade(Rect(0,0,image.Width, image.Height), image_from, image_to, TimerIndex, dmSet);   image.Draw(Slide_panel.Canvas, 0,0);   if TimerIndex  < 255 + TimerStep then     TimerIndex := TimerIndex + TimerStep     else Timer1.Enabled:=false;;   Application.ProcessMessages; // avoid to become unresponsive end; ---------------------------------------------------------------------- Handoko · 2019-01-17 09:45 When I wrote "if TimerIndex < 255-TimerStep then", I was a bit unsure if it was 'correct'. My sixth sense told me it wasn't good. But you're right, that was wrong. And you fix it simply and cleverly: if TimerIndex  > 255 then TimerIndex := 255;