Proporcjonalna zmiana rozmiaru obrazu

0

Ogólnie chciałbym zmniejszyć bitmapę do określonych rozmiarów, ale robiąc to wg funkcji zawartych w Canvas, obraz jest albo rozciągany, albo po prostu ma potem na sobie jakieś dziwne linie, kropki i nie wiadomo co. Na razie udało mi się stworzyć coś takiego.

Mój kod:

function ResizeBitmap(Bitmap: TBitmap; Width, Height: Integer; Background: TColor): TBitmap
var
  B: TBitmap;
  RX, RY, R: integer;
  OX, OY: integer;
 
begin
  RX := Bitmap.Width - Width;
  RY := Bitmap.Height - Height;
 
  if Width <= Bitmap.Width- RY then begin    //jeżeli przyszłe zmniejszenie wysokości nie będzie mniejsze od szerokości
 
    OX := Bitmap.Width;
    OY := Bitmap.Height;
    R := RY;
 
    B.Width:= Bitmap.Width-R;
    B.Height:= Bitmap.Height-R;
    B.Canvas.StretchDraw( Rect( 0, 0, Bitmap.Width-R, Bitmap.Height-R ), Bitmap );    //zmniejsz rozmiar
 
    Bitmap.Width:= Width;
    Bitmap.Height:= Height;
    Bitmap.Canvas.Brush.Color:= Background;
    Bitmap.Canvas.FillRect(Bitmap.Canvas.ClipRect);
    Bitmap.Canvas.CopyRect( Rect(0, 0, Width, Height),
                       B.Canvas,
                       Rect(R, 0, B.Width-Trunc((B.Width-Width)/2), B.Height));    //wytnij boki po zmniejszeniu
    //Bitmap.Canvas.Draw(0, 0, B);
 
  end else { if Height <= Bitmap.Height- RX then } begin    //jeżeli przyszłe zmniejszenie szerokości nie będzie mniejsze od wysokoci
 
    OX := Bitmap.Width;
    OY := Bitmap.Height;
    R := RX;
 
    B.Width:= Bitmap.Width-R;
    B.Height:= Bitmap.Height-R;
    B.Canvas.StretchDraw( Rect( 0, 0, Bitmap.Width-R, Bitmap.Height-R ), Bitmap );    //zmniejsz rozmiar
 
    Bitmap.Width:= Width;
    Bitmap.Height:= Height;
    Bitmap.Canvas.Brush.Color:= Background;
    Bitmap.Canvas.FillRect(Bitmap.Canvas.ClipRect);
    Bitmap.Canvas.CopyRect( Rect(0, 0, Width, Height),
                       B.Canvas,
                       Rect(0, R, B.Width, B.Height-Trunc((B.Height-Height)/2)));   //wytnij górę i dół po zmniejszeniu
    //Bitmap.Canvas.Draw(0, 0, B);
 
  end;
  B.Free;
  result := Bitmap;

end;
X1,Y1                           X1,Y1
------------------------------  ------------------------------
|  X2,Y2                     |  |  X2,Y2                     |
|  ------------------------  |  |  ------------------------  |
|  |   | X3,Y3        |   |  |  |  |                      |  |
|  |   |              |   |  |  |  |----------------------|  |
|  |   |              |   |  |  |  | X3,Y3                |  |
|  |   |              |   |  |  |  |                      |  |
|  ------------------------  |  |  |                      |  |
|                            |  |  |----------------------|  |
------------------------------  |  |                      |  |
                                |  ------------------------  |
                                |                            |
                                ------------------------------

X1,Y1 - to rozmiary obrazka domyślnego
X3,Y3 - to rozmiary docelowe

ale czasem obraz wychodzi rozciągnięty w pionie albo w poziomie jak nie dostosuję odpowiednich proporcji
Chciałbym najpierw dostosować obraz tak aby jego długość albo wysokość była dostosowana do przyszłego rozmiaru, a następnie te elementy które się nie zmieściły odciąć, tak aby obraz nie był rozciągnięty.

Czytałem jeszcze na temat algorytmów Najbliższego sąsiedztwa i Interpolacji dwuliniowej, ale niestety te algorytmy są za wolne, dla programu w którym obraz jest zmniejszany ilektroć zmieniam rozmiar formy, czy ją przenoszę, zawsze zawiesza się na jakieś 2, 3 sekundy, także te algorytmy nie są dobre jak dla mnie, (może do programu graficznego jak najbardziej).

2
zoom := Min(x3/x1, y3/y1);
x3 := x1 * zoom;
y3 := y1 * zoom;

masz wymiary nowego z uwzględnieniem proporcji

0

Pobawiłem się jeszcze w powiększanie obrazu (procentowe) ale jak do tej proporcji teraz to powiększenie zastosować?

procedure TFormMain.ImageZoom;
var
  ZoomX : integer;
  ZoomY : integer;

begin

  ImageMedia.Picture := nil;
  ZoomX := Trunc( ImageMediaMod.Picture.Width * (TrackBar_ImageSize.Position/100) );
  ZoomY := Trunc( ImageMediaMod.Picture.Height * (TrackBar_ImageSize.Position/100) );
  ImageMedia.Picture.Bitmap.Width := ImageMediaMod.Picture.Width - ZoomX;
  ImageMedia.Picture.Bitmap.Height := ImageMediaMod.Picture.Height - ZoomY;

  ImageZoomX := ZoomX div 2;
  ImageZoomY := ZoomY div 2;

  ImageMedia.Picture.Bitmap.Canvas.Draw( -ImageZoomX, -ImageZoomY, ImageMediaMod.Picture.Graphic );

end;

Teraz wygląda mniej więcej tak:

-------------------------------
|o                            |
|    ---------------------    |
|  --|z                  |--  |
|  |f|                   | |  |
|  | |                   | |  |
|  | |                   | |  |
|  | |                   | |  |
|  --|                   |--  |
|    ---------------------    |
|                             |
-------------------------------

o - obraz orygiganlny
z - fragment obrazu wyciętego jako powiększenie
f - miejsce na którym się obraz wyświetla

Na razie działa to tak że pomniejszam obraz a potem inną procedurą wrzucam go na widoczny element. Jeżeli obraz jest 3:4 a widoczny element 16:9 to boki są po prostu puste, a chciałbym by powiększając obraz, rozchodził się on też na te boki. A kiedy odwrotnie wrzucam 16:9 na 3:4 to znowu nie mam góry i dołu.

Stosuję ten kod z postu powyżej do wrzucania obrazu na widoczny element.

1

Jeśli Zoom jest w procentach to nie możesz go odejmować/dodawać od wymiaru tylko musisz wymiar przemnożyć/podzielić* przez Zoom

  • w zależności jak liczysz zoom
0

Może inaczej.
Mam dwie procedury:

Jedna która wycina obszar zoomowania:

--------------------
|o                 |
|    ----------    |
|    |n       |    |
|    |        |    |
|    ----------    |
|                  |
--------------------

o - oryginalny
n - nowy
procedure TFormMain.ImageZoom;
var
  ZoomX : integer;
  ZoomY : integer;
 
begin
  ImageMedia.Picture := nil;
  ZoomX := Trunc( ImageMediaMod.Picture.Width * (TrackBar_ImageSize.Position/100) );
  ZoomY := Trunc( ImageMediaMod.Picture.Height * (TrackBar_ImageSize.Position/100) );
  ImageMedia.Picture.Bitmap.Width := ImageMediaMod.Picture.Width - ZoomX;
  ImageMedia.Picture.Bitmap.Height := ImageMediaMod.Picture.Height - ZoomY;
 
  ImageZoomX := ZoomX div 2;
  ImageZoomY := ZoomY div 2;
 
  ImageMedia.Picture.Bitmap.Canvas.Draw( -ImageZoomX, -ImageZoomY, ImageMediaMod.Picture.Graphic );
end;

A następnie kolejna która pokazuje zoom na ekranie:
Czyli dostosowywuje wycięty kawałek do ekranu, ale niestety wycięty kawałek nie ma boków więc nie ma wypełnionych kawałków po bokach, albo na górze bądź na dole, w zależności czy obraz 4:3 czy 16:9

--------------------
|s |n          |  |
|  |            |  |
|  |            |  |
|  |            |  |
--------------------

o - wycięty element powiększony
s - obszar wyświetlania
function ResizeBitmap(Bitmap: TBitmap; Width, Height: Integer; Background: TColor; Mode: integer): TBitmap;
var
  B: TBitmap;
  X,Y,RX,RY: Integer;
  Zoom : Real;
begin 
  Zoom := Min( Width/Bitmap.Width, Height/Bitmap.Height );
  B.Width := Trunc(Bitmap.Width * Zoom);
  B.Height := Trunc(Bitmap.Height * Zoom);
  B.Canvas.Brush.Color:= Background;
  B.Canvas.FillRect( B.Canvas.ClipRect );
  B.Canvas.StretchDraw( Rect( 0, 0, B.Width, B.Height ), Bitmap );
  RX := 0;
  RY := 0;
  if ( B.Width < Width ) then RX := ( Width - B.Width ) div 2;
  if ( B.Height < Height ) then RY := ( Height - B.Height ) div 2;
  Bitmap.Width:= Width;
  Bitmap.Height:= Height;
  Bitmap.Canvas.Brush.Color:= Background;
  Bitmap.Canvas.FillRect(Bitmap.Canvas.ClipRect);
  Bitmap.Canvas.Draw(0+RX, 0+RY, B);
  B.Free;
  result := Bitmap;
end;

I teraz chciałbym w procedurze zmiany rozmiaru gdzie po prostu obliczam jaki procent obrazu ma być usunięty żeby zostawić sobie obszar który ma być powiększony dodać też obszar ten który jest nie zapełniony.

Obraz przed przybliżeniem:
1.png

Obraz po przybliżeniu:
2.png

0
chkam napisał(a):
-------------------------------
|o                            |
|    ---------------------    |
|  --|z                  |--  |
|  |f|                   | |  |
|  | |                   | |  |
|  | |                   | |  |
|  | |                   | |  |
|  --|                   |--  |
|    ---------------------    |
|                             |
-------------------------------

o - obraz orygiganlny
z - fragment obrazu wyciętego jako powiększenie
f - miejsce na którym się obraz wyświetla

obraz o po przycięciu do z staje się nieistotny, więc nie zaciemniajmy rysunku:


       ---------------------
       |z                  | 
   ----+-------------------+---- 
   |f  |                   |   |
   |   |                   |   |
   |   |                   |   |
   |   |                   |   |
   ----+-------------------+----
       |                   |
       ---------------------

co teraz potrzebujesz zrobić, to powiększyć z aby osiągnął szerokość taką jak ma f:

   ------------------------------
   |z                           | 
   |                            |
   |                            |
   ------------------------------ 
   |f                           |
   |                            |
   |                            |
   |                            |
   ------------------------------
   |                            |
   |                            |
   |                            |
   ------------------------------

i przyciąć górę i dół.

a ile przyciąć? od góry (wysokość_powiększonego_z - wysokość_f) / 2, a z dołu wysokość_powiększonego_z - wysokość_f - tyle_ile_obcięto_z_góry

0

B.Canvas.StretchDraw( Rect( 0, 0, Bitmap.Width-R, Bitmap.Height-R ), Bitmap );

a co w ogóle robi - wiesz co to robi, kontrolujesz to?

SetStretchBltMode z windowsa:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd145089%28v=vs.85%29.aspx

0

Dziękuję ogólnie za pomoc.
Doszedłem dzisiaj do pozytywnych wyników w końcu :)

Oto stworzony przeze mnie moduł, biblioteka, czy jak tam to się zwie, gdzie jest kod który przetwarza obraz na wiele sposobów:
Wycinanie, Przycinanie, dopasowywanie do nowych rozmiarów, zmiana rozmiaru, i powiększenie obrazu oraz wyświetlenie powiększenia w odpowiednich rozmiarach.
Udostępniam bo może się przydać komuś ;)
bibGraphics.pas

Pozdrawiam
Temat do zamknięcia

1 użytkowników online, w tym zalogowanych: 0, gości: 1