Forum > Graphics
[SOLVED] SDL2 image rotation Problem
Pe3s:
Hello forumers I am learning SDL and I have encountered a problem after loading the image format “portrait” rotation and fitting the image to the window margins appear at the top and bottom , when loading the image format landscape the problem does not occur how can I correct the error in the code ?
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit Unit1; {$mode objfpc}{$H+} interface usesClasses, SysUtils, Forms, Controls, Graphics, Dialogs, ComCtrls, ExtCtrls, StdCtrls, SDL2, SDL2_image, Math; type { TForm1 } TForm1 = class(TForm) Button1: TButton; Button2: TButton; Button3: TButton; Button4: TButton; Button5: TButton; Button6: TButton; Button7: TButton; OpenDialog1: TOpenDialog; Panel1: TPanel; Panel2: TPanel; StatusBar1: TStatusBar; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure Button4Click(Sender: TObject); procedure Button5Click(Sender: TObject); procedure Button6Click(Sender: TObject); procedure Button7Click(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormResize(Sender: TObject); procedure FormShow(Sender: TObject); procedure Panel1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure Panel1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure Panel1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure Panel1Paint(Sender: TObject); private SDLWindow: PSDL_Window; SDLRenderer: PSDL_Renderer; CurrentTexture: PSDL_Texture; OffsetX, OffsetY, ZoomLevel, MinZoom, MaxZoom, FRotationAngle: Double; IsPanning: Boolean; LastMouseX, LastMouseY, ImgWidth, ImgHeight: Integer; procedure InitializeSDL; procedure ShutdownSDL; procedure LoadAndDisplayImage(const FileName: string); procedure RenderImage; procedure CenterImage; procedure Zoom(Delta: Double; FocusX, FocusY: Integer); procedure FitImage; public end; var Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormShow(Sender: TObject);begin InitializeSDL; ZoomLevel := 1.0; OffsetX := 0; OffsetY := 0; IsPanning := False; ImgWidth := 0; // No image loaded yet ImgHeight := 0; // No image loaded yet CurrentTexture := nil;end; procedure TForm1.Panel1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);begin if Button = mbLeft then begin IsPanning := True; LastMouseX := X; LastMouseY := Y; end;end; procedure TForm1.Panel1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);begin if IsPanning then begin OffsetX := OffsetX + (X - LastMouseX); OffsetY := OffsetY + (Y - LastMouseY); LastMouseX := X; LastMouseY := Y; RenderImage; end;end; procedure TForm1.Panel1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);begin if Button = mbLeft then IsPanning := False;end; procedure TForm1.Panel1Paint(Sender: TObject);begin // Draw a red rectangle (example) SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255); SDL_RenderFillRect(sdlRenderer, nil); // Full screen fill SDL_RenderPresent(sdlRenderer); RenderImage;end; procedure TForm1.FormDestroy(Sender: TObject);begin ShutdownSDL;end; procedure TForm1.FormResize(Sender: TObject); var PanelWidth, PanelHeight: Integer;begin PanelWidth := Panel1.Width; PanelHeight := Panel1.Height; // Skip fitting or rendering if no image is loaded if (ImgWidth = 0) or (ImgHeight = 0) then Exit; // Check for valid dimensions before fitting or rendering if (PanelWidth > 0) and (PanelHeight > 0) then begin FitImage; // Automatically fit the image on resize end;end; procedure TForm1.Button1Click(Sender: TObject);begin if OpenDialog1.Execute then LoadAndDisplayImage(OpenDialog1.FileName);end; procedure TForm1.Button2Click(Sender: TObject);begin Zoom(1, Panel1.Width div 2, Panel1.Height div 2); // Zoom in towards the centerend; procedure TForm1.Button3Click(Sender: TObject);begin Zoom(-1, Panel1.Width div 2, Panel1.Height div 2); // Zoom out towards the centeend; procedure TForm1.Button4Click(Sender: TObject);begin ZoomLevel:= 1.0; CenterImage; RenderImage;end; procedure TForm1.Button5Click(Sender: TObject);begin FitImage; // Reset zoom and center the imageend; procedure TForm1.Button6Click(Sender: TObject);begin FRotationAngle := (FRotationAngle -90) mod 360; RenderImage;end; procedure TForm1.Button7Click(Sender: TObject);begin FRotationAngle := (FRotationAngle +90) mod 360; RenderImage;end; procedure TForm1.InitializeSDL;begin if SDL_Init(SDL_INIT_VIDEO) < 0 then raise Exception.Create('Nie udało się zainicjować SDL: ' + SDL_GetError); SDLWindow := SDL_CreateWindowFrom(Pointer(Panel1.Handle)); if SDLWindow = nil then raise Exception.Create('Nie udało się utworzyć okna SDL: ' + SDL_GetError); SDLRenderer := SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED or SDL_RENDERER_PRESENTVSYNC); if SDLRenderer = nil then raise Exception.Create('Nie można utworzyć renderowania SDL: ' + SDL_GetError); ZoomLevel := 1.0; // Initialize zoom level end; procedure TForm1.ShutdownSDL;begin if CurrentTexture <> nil then SDL_DestroyTexture(CurrentTexture); if SDLRenderer <> nil then SDL_DestroyRenderer(SDLRenderer); if SDLWindow <> nil then SDL_DestroyWindow(SDLWindow); IMG_Quit; SDL_Quit;end; procedure TForm1.LoadAndDisplayImage(const FileName: string); var PanelWidth, PanelHeight: Integer; FitZoom: Double;begin if CurrentTexture <> nil then SDL_DestroyTexture(CurrentTexture); CurrentTexture := IMG_LoadTexture(SDLRenderer, PChar(FileName)); if CurrentTexture = nil then raise Exception.Create('Nie udało się wczytać tekstury: ' + IMG_GetError); // Query the texture for its dimensions SDL_QueryTexture(CurrentTexture, nil, nil, @ImgWidth, @ImgHeight); // Calculate initial zoom to fit the image in the panel PanelWidth := Panel1.Width; PanelHeight := Panel1.Height; FitZoom := Min(PanelWidth / ImgWidth, PanelHeight / ImgHeight); // Set zoom level and center offsets ZoomLevel := FitZoom; OffsetX := (PanelWidth - Round(ImgWidth * ZoomLevel)) div 2; OffsetY := (PanelHeight - Round(ImgHeight * ZoomLevel)) div 2; // Set zoom limits MinZoom := FitZoom * 0.5; // Allow zooming out to 50% of fit size MaxZoom := 3.0; // Allow zooming in up to 300% RenderImage; FitImage;end; procedure TForm1.RenderImage; var DstRect: TSDL_Rect; PanelWidth, PanelHeight: Integer; begin if CurrentTexture = nil then Exit; // No texture to render PanelWidth := Panel1.Width; PanelHeight := Panel1.Height; if (PanelWidth <= 0) or (PanelHeight <= 0) then Exit; // Avoid rendering if panel is invalid // Calculate destination rectangle with zoom and offsets DstRect.w := Round(ImgWidth * ZoomLevel); DstRect.h := Round(ImgHeight * ZoomLevel); // Constrain panning to avoid blank spaces if DstRect.w <= PanelWidth then OffsetX := (PanelWidth - DstRect.w) / 2 else OffsetX := Max(Min(OffsetX, 0), PanelWidth - DstRect.w); if DstRect.h <= PanelHeight then OffsetY := (PanelHeight - DstRect.h) / 2 else OffsetY := Max(Min(OffsetY, 0), PanelHeight - DstRect.h); DstRect.x := Round(OffsetX); DstRect.y := Round(OffsetY); SDL_RenderClear(SDLRenderer); // Render the image SDL_RenderCopyEx(SDLRenderer, CurrentTexture, nil, @DstRect, FRotationAngle, nil, SDL_FLIP_NONE); SDL_RenderPresent(SDLRenderer);end; procedure TForm1.CenterImage; var PanelWidth, PanelHeight: Integer;begin if (ImgWidth = 0) or (ImgHeight = 0) or (CurrentTexture = nil) then Exit; PanelWidth := Panel1.Width; PanelHeight := Panel1.Height; // Reset offsets to center the image OffsetX := (PanelWidth - ImgWidth * ZoomLevel) / 2; OffsetY := (PanelHeight - ImgHeight * ZoomLevel) / 2; RenderImage;end; procedure TForm1.Zoom(Delta: Double; FocusX, FocusY: Integer); var OldZoom: Double; PanelWidth, PanelHeight: Integer; ImageCenterX, ImageCenterY: Double;begin if (ImgWidth = 0) or (ImgHeight = 0) or (CurrentTexture = nil) then Exit; OldZoom := ZoomLevel; PanelWidth := Panel1.Width; PanelHeight := Panel1.Height; // Adjust zoom level with bounds ZoomLevel := Max(MinZoom, Min(MaxZoom, ZoomLevel + Delta * 0.1)); // Compute focus point scaling if ZoomLevel <> OldZoom then begin ImageCenterX := (FocusX - OffsetX) / OldZoom; ImageCenterY := (FocusY - OffsetY) / OldZoom; OffsetX := FocusX - ImageCenterX * ZoomLevel; OffsetY := FocusY - ImageCenterY * ZoomLevel; end; // Update caption Form1.Caption := Format('Zoom: %.0f%%', [ZoomLevel * 100]); RenderImage;end; procedure TForm1.FitImage; var RotatedWidth, RotatedHeight: Double; ScalingFactor: Double; AngleRadians: Double;begin if (ImgWidth = 0) or (ImgHeight = 0) or (CurrentTexture = nil) then Exit; // Normalize the rotation angle to the range [0, 360) AngleRadians := DegToRad((FRotationAngle mod 360 + 360) mod 360); // Calculate rotated bounding box dimensions RotatedWidth := Abs(ImgWidth * Cos(AngleRadians)) + Abs(ImgHeight * Sin(AngleRadians)); RotatedHeight := Abs(ImgWidth * Sin(AngleRadians)) + Abs(ImgHeight * Cos(AngleRadians)); // Calculate scaling factor to fit the panel's height ScalingFactor := Panel1.Height / RotatedHeight; // Update the zoom level to maintain proportional scaling ZoomLevel := ScalingFactor; // Recalculate offsets to ensure proper centering CenterImage;end; end. Greetings
bobihot:
Try with
Lazarus-SDL3.0-Packages_and_Examples
https://github.com/sechshelme/Lazarus-SDL3.0-Packages_and_Examples
Me also interested, because I was used on Delphi. But I do not try now.
Thanks
Pe3s:
This is not an SDL bug rather my code.
The loaded image in landscape aspect ratio works , but when I load a portrait there is a problem when rotating.
Pe3s:
How can I dynamically swap the height with the width and update the sdl window ?
So that the rotated image will adjust to the window
Roland57:
Hello!
By the way, I can compile your project, but I get this error when I try to run it:
[roland@localhost sdl_image]$ ./project1
The program 'project1' received an X Window System error.
This probably reflects a bug in the program.
The error was 'BadWindow (invalid Window parameter)'.
(Details: serial 88 error_code 3 request_code 20 minor_code 0)
(Note to programmers: normally, X errors are reported asynchronously;
that is, you will receive the error a while after causing it.
To debug your program, run it with the --sync command line
option to change this behavior. You can then get a meaningful
backtrace from your debugger if you break on the gdk_x_error() function.)
I took a look at your code. The logic is too complicated for me. :)
Navigation
[0] Message Index
[#] Next page