wp resize (code #2) - the pointers in image processing

Kontext

Tento program vychází z programu na sbírání informací o barvě pixelu, popsáno zde.
 
Jak funguje vlastnost Autosize?
Vlastnosti Width a Height obsahují skutečnou velikost komponenty TImage, nikoli skutečnou velikost zobrazeného obrázku. Když je vlastnost Autosize zapnutá, velikost komponenty se přizpůsobí velikosti zobrazeného obrázku, a to i přesto, že původní rozměry obrázku mohou být větší.
 
Co je podkladová bitmapa?
 
Podkladová bitmapa je tedy co? Je to ten načtený originální obrázek 1024x1024px nebo ta zmenšenina, která se zobrazuje v okně?
ChatGPT

V kontextu vašeho dotazu "underlying bitmap" se zřejmě odkazuje na původní načtený obrázek o rozměrech 1024x1024px. "Underlying bitmap" znamená doslovně "podkladová bitmapa" a v tomto kontextu to znamená originální nezměněný obrázek, který byl do komponenty TImage načten. Pokud byl tento obrázek zmenšen zobrazen nebo přizpůsoben velikosti komponenty, tak vlastnosti Width a Height komponenty TImage by ukazovaly na tyto nové rozměry, ale "underlying bitmap" by stále byla ta původní, která má rozměry 1024x1024px.

Program source - download here.

function TForm1.GetRGB(X, Y: Integer; out R, G, B: Byte; out Alpha: string): Boolean;
var
  ScanData: Pointer;
  Data24bit: PRGBTriple absolute ScanData;
  Data32bit: PRGBQuad absolute ScanData;
begin
  Result := false;
  if ScaleFactor = 0 then
    exit;

  X := trunc(X / ScaleFactor);
  Y := trunc(Y / ScaleFactor);
  if (X < 0) or (X >= Image1.Picture.Width) then
    exit;
  if (Y < 0) or (Y >= Image1.Picture.Height) then
    exit;
  // This is an original image: Image1.Picture.Bitmap
  ScanData := Image1.Picture.Bitmap.ScanLine[Y];
  case LoadedPixelFormat of
    pf24bit:
      begin
        Inc(ScanData, X * 3);
        R := Data24bit^.rgbtRed;
        G := Data24bit^.rgbtGreen;
        B := Data24bit^.rgbtBlue;
        Alpha := '';
      end;
    pf32bit:
      begin
        Inc(ScanData, X * 4);
        R := Data32bit^.rgbRed;
        G := Data32bit^.rgbGreen;
        B := Data32bit^.rgbBlue;
        Alpha := 'A = ' + IntToStr(Data32bit^.rgbReserved);
      end;
  end;

  Result := true;
end;
 

Kód je částí aplikace FreePascal/Lazarus, která získává hodnoty RGB a případně alfa kanálu (pro 32-bitové obrázky) z určitého bodu na bitmapě. Kód využívá ukazatelovou aritmetiku, aby přistoupil k pixelovým datům na konkrétním místě (X, Y) v obrázku.

V tomto kódu je použit mechanismus nazývaný "absolute" ukazatelová deklarace. Tato deklarace umožňuje, aby ukazatel ukazoval na určité offsety od začátku paměti přidělené pro ScanData. Zde je vysvětlení jednotlivých částí:

  1. ScanData: Pointer; Toto je ukazatel na data pixelů na zvoleném řádku obrázku. Tento ukazatel bude ukazovat na začátek dat pro konkrétní řádek Y.

  2. Data24bit: PRGBTriple absolute ScanData;: Tato deklarace vytváří ukazatel Data24bit, který je navázán na stejnou paměťovou adresu jako ScanData. Data24bit se interpretuje jako ukazatel na strukturu RGBTriple (která obsahuje tři bajty pro složky R, G a B).

  3. Data32bit: PRGBQuad absolute ScanData;: Tato deklarace vytváří ukazatel Data32bit, který také ukazuje na stejnou paměťovou adresu jako ScanData. Data32bit se interpretuje jako ukazatel na strukturu RGBQuad (která obsahuje čtyři bajty pro složky R, G, B a alfa kanál).

Když je v kódu použita deklarace Data24bit^.rgbtRed;, znamená to, že se přistupuje k červené složce (red) pixelu na pozici (X, Y) v 24-bitovém obrázku. Když je v kódu použita deklarace Data32bit^.rgbRed;, znamená to, že se přistupuje k červené složce pixelu na pozici (X, Y) v 32-bitovém obrázku.

Celkově vzato, tento kód slouží k získání hodnot RGB (a alfa kanálu pro 32-bitové obrázky) z určitého bodu na bitmapě. Používá ukazatelovou aritmetiku a "absolute" deklarace, aby umožnila přímý přístup k datům pixelů na dané pozici.

* * *

 

 

In this Lazarus program, pointers are used to manipulate and analyze pixel data in images. Pointers allow direct access to the memory locations where the pixel data is stored, which is essential for tasks like resizing images and extracting color information.

Let's break down the key parts of the code where pointers are used:

  1. LoadImage Procedure:

  • procedure TForm1.LoadImage(const AFileName: String); begin Image1.Picture.LoadFromFile(AFilename); LoadedPixelFormat := Image1.Picture.Bitmap.PixelFormat; ResizeImageToFitScreen; end;

    Here, the LoadImage procedure is used to load an image from a file. After loading, the pixel format of the image's bitmap is stored in the LoadedPixelFormat variable. This pixel format information is important when accessing pixel data later.

  • GetRGB Function:

  • function TForm1.GetRGB(X, Y: Integer; out R, G, B: Byte; out Alpha: string): Boolean; var ScanData: Pointer; Data24bit: PRGBTriple absolute ScanData; Data32bit: PRGBQuad absolute ScanData; begin Result := false; if ScaleFactor = 0 then exit; X := trunc(X / ScaleFactor); Y := trunc(Y / ScaleFactor); if (X < 0) or (X >= Image1.Picture.Width) then exit; if (Y < 0) or (Y >= Image1.Picture.Height) then exit; ScanData := Image1.Picture.Bitmap.ScanLine[Y]; case LoadedPixelFormat of pf24bit: begin Inc(ScanData, X * 3); R := Data24bit^.rgbtRed; G := Data24bit^.rgbtGreen; B := Data24bit^.rgbtBlue; Alpha := ''; end; pf32bit: begin Inc(ScanData, X * 4); R := Data32bit^.rgbRed; G := Data32bit^.rgbGreen; B := Data32bit^.rgbBlue; Alpha := 'A = ' + IntToStr(Data32bit^.rgbReserved); end; end; Result := true; end;

    In the GetRGB function, a pointer named ScanData is used to access pixel data at a specific row (Y coordinate) in the image's bitmap. Depending on the pixel format, the function either uses PRGBTriple or PRGBQuad pointers to extract color information (R, G, B, and possibly Alpha) from the pixel data.

    The pixel data is accessed using pointer arithmetic. The Inc(ScanData, X * 3) or Inc(ScanData, X * 4) statements move the pointer to the appropriate memory location based on the X coordinate. The color values are then extracted from the memory locations pointed to by the Data24bit or Data32bit pointers.

  • Image1MouseMove Procedure:

    1. procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var ValR, ValG, ValB: Byte; Alpha: string; begin if (LoadedPixelFormat = pf24bit) or (LoadedPixelFormat = pf32bit) then begin if GetRGB(X, Y, ValR, ValG, ValB, Alpha) then begin // ... end else begin // ... end; end; end;

      In this procedure, the GetRGB function is called to retrieve color information from the pixel under the mouse cursor. If the pixel format is either 24-bit or 32-bit, the color values and possibly the alpha channel are obtained using the pointer techniques explained earlier.

    The usage of pointers in this Lazarus program demonstrates how they can be leveraged to directly manipulate pixel data in images, which is essential for tasks like image resizing, color extraction, and analysis. Pointers provide a more efficient and direct way to access and modify memory locations, making it easier to work with pixel data at a low level.

    Specifically the ^ mark for pointer

    The ^ symbol in Pascal is used as the dereference operator. It is used to access the value pointed to by a pointer. In the context of your Lazarus program, you can see the ^ symbol being used in two places:

    1. Data24bit^.rgbtRed and Data24bit^.rgbtGreen:

  • R := Data24bit^.rgbtRed; G := Data24bit^.rgbtGreen; B := Data24bit^.rgbtBlue;

    Here, Data24bit is a pointer to a TRGBTriple structure, which represents the color information for a pixel in a 24-bit pixel format. The ^ symbol is used to dereference the pointer and access the members of the TRGBTriple structure, namely rgbtRed, rgbtGreen, and rgbtBlue.

  • Data32bit^.rgbRed and Data32bit^.rgbGreen:

    1. R := Data32bit^.rgbRed; G := Data32bit^.rgbGreen; B := Data32bit^.rgbBlue;

      Similar to the previous case, Data32bit is a pointer to a TRGBQuad structure, which represents the color information for a pixel in a 32-bit pixel format. The ^ symbol is used to dereference the pointer and access the members of the TRGBQuad structure, which are rgbRed, rgbGreen, and rgbBlue.

    In both cases, the ^ symbol tells the compiler to follow the pointer and access the data at the memory location it points to. It's an essential concept when working with pointers because it allows you to interact with the actual data stored in memory through the pointer.

    GetSystemMetrics(SM_CYCAPTION)

    The function GetSystemMetrics(SM_CYCAPTION) is used to retrieve the height of the caption bar in a window's title bar. In other words, it returns the height of the area that typically contains the window's title, system menu (close, minimize, maximize buttons), and possibly additional controls.

    Here's a breakdown of the parameters and its usage in the context of your code:

    maxImgHeight := Screen.WorkAreaHeight - // subtract window frame and title GetSystemMetrics(SM_CYCAPTION) - GetSystemMetrics(SM_CYSIZEFRAME) - Image1.Top - // subtract space above image BOTTOM_MARGIN; // subtract image margin at bottom

    In this part of your ResizeImageToFitScreen procedure, you are calculating the maximum height available for the image considering various factors such as screen space, window frame size, and margins. Let's break down each component:

    • Screen.WorkAreaHeight: This returns the height of the screen's work area, which is the usable area of the screen excluding taskbars and other system elements.

    • GetSystemMetrics(SM_CYCAPTION): This retrieves the height of the caption bar, which is the area where the window's title and control buttons are typically displayed.

    • GetSystemMetrics(SM_CYSIZEFRAME): This retrieves the height of the window's sizing border, which is the area where you can click and drag to resize the window.

    • Image1.Top: This accounts for the space between the top edge of the image and the top edge of the form.

    • BOTTOM_MARGIN: This accounts for any margin that you want to leave at the bottom of the image.

    By subtracting all these values from the Screen.WorkAreaHeight, you calculate the maximum height that can be allocated to the image while considering window decorations, margins, and other UI elements. This calculation ensures that the image can be resized to fit within the available space on the screen without overlapping with the window's title bar, sizing border, and other components.

    Screen.WorkAreaHeight a Screen.Width

    Screen.WorkAreaHeight a Screen.Width jsou dvě různá vlastnosti, které se týkají rozměrů obrazovky, ale mají různé významy:

    1. Screen.WorkAreaHeight: Tato vlastnost vrací výšku pracovní plochy obrazovky. Pracovní plocha je oblast obrazovky, která je k dispozici pro aplikace kromě různých systémových prvků, jako jsou lišty úloh, panely rychlého spuštění a další. Pracovní plocha obvykle nezahrnuje tyto systémové prvky, a tak je to místo, kde se běžné aplikace otevírají a zobrazují.

    2. Screen.Width: Tato vlastnost vrací celkovou šířku obrazovky. To zahrnuje veškerý fyzický prostor na obrazovce včetně systémových prvků, takže pokud máte například lištu úloh na spodní části obrazovky, bude zahrnuta do této šířky.

    Základním rozdílem je tedy to, že Screen.WorkAreaHeight vrátí výšku pracovní plochy bez systémových prvků, zatímco Screen.Width vrátí celkovou šířku obrazovky včetně systémových prvků.


    Scale Factor

    V případě, který jste popsal (rozlišení obrazovky 800x600 a pracovní oblast může být 1024x něco), pracovní oblast bude širší než fyzické rozlišení obrazovky. To může být zpožděno použitím různých nastavení zobrazení v operačním systému.

    Rozlišení obrazovky 800x600 znamená, že obrazovka má 800 pixelů na šířku a 600 pixelů na výšku. To je fyzický počet pixelů, které tvoří vaši obrazovku.

    Pracovní oblast o velikosti 1024x něco znamená, že operační systém nabízí pracovní plochu s šířkou 1024 pixelů. Pracovní plocha je oblast na obrazovce, kterou operační systém považuje za volnou pro aplikace, a obvykle se zde nezobrazují systémové prvky, jako jsou lišty úloh.

    Pokud máte rozlišení obrazovky 800x600 a pracovní oblast je 1024 pixelů na šířku, znamená to, že operační systém poskytuje širší prostor pro aplikace, než je fyzické rozlišení obrazovky. To může být užitečné pro zobrazování aplikací, které potřebují více prostoru než je fyzická velikost obrazovky.

     

    Scalefactor

    Význam a role ScaleFactor v kontextu pracovní plochy (work area) a oblasti obrazovky, kde se pohybuje myš, a také o výpočet tohoto faktoru a jeho význam v daném kontextu

    V programu, který jste sdílel, ScaleFactor slouží k zachování správného vztahu mezi fyzickými rozměry obrázku a jeho zobrazením na obrazovce v kontextu, kdy je obrázek zvětšován nebo zmenšován tak, aby se vešel na obrazovku. Protože může být obtížné zobrazit celý obrázek na malé obrazovce, je důležité přizpůsobit jeho velikost tak, aby se vešel do dostupného místa.

    Výpočet ScaleFactor probíhá následovně:

    ScaleFactor := Image1.Height / Image1.Picture.Height;

    Zde se ScaleFactor počítá jako podíl výšky zobrazení obrázku (Image1.Height) a výšky původního obrázku (Image1.Picture.Height). Tento faktor nám umožňuje převést souřadnice zobrazené na obrazovce zpět na souřadnice původního obrázku. Když se například pohybujete myší nad obrázkem, můžete zjistit, který pixel právě zobrazujete a převést jeho souřadnice z obrazovky zpět na původní souřadnice obrázku.

    Co se týče úseku kódu, kde je ScaleFactor použit:

    pascal
    'X (image) = ' + IntToStr(round(X/ScaleFactor)) + #13 + 'Y (image) = ' + IntToStr(round(Y/ScaleFactor)) + #13 +

    V tomto úseku se používá ScaleFactor, aby se převedly souřadnice myši z obrazovky na souřadnice původního obrázku. Přesněji, výšky a šířky na obrazovce jsou vynásobeny tímto faktorem, aby se získaly odpovídající souřadnice na původním obrázku. To je užitečné při zobrazování informací o konkrétním pixelu pod myší, protože umožňuje zobrazit, kde na původním obrázku se tento pixel nachází.

    Celkově tedy ScaleFactor slouží k zachování vztahu mezi původními rozměry obrázku a jeho zobrazením na obrazovce, což umožňuje správně interpretovat polohu myši vzhledem k původnímu obrázku.

    Formáty pf32bit a pf24bit

    Formáty pf32bit a pf24bit jsou různé reprezentace pixelů v bitmapovém obrázku, které mají rozdílný počet bitů na jeden pixel. Zde je vysvětlení těchto formátů a jak jsou použity ve vašem kódu:

    1. pf32bit (32-bitový formát): V tomto formátu je každý pixel reprezentován 32 bity, což je 4 bajty. Tato reprezentace umožňuje ukládat všechny tři složky barvy (červená, zelená, modrá) spolu s alfa kanálem, který určuje průhlednost pixelu. 32-bitový formát je často používán pro obrázky s podporou průhlednosti, například PNG obrázky, kde je důležitá kvalita průhlednosti.

    2. pf24bit (24-bitový formát): V tomto formátu je každý pixel reprezentován 24 bity, což je 3 bajty. Tento formát ukládá pouze tři složky barvy (červená, zelená, modrá) bez alfa kanálu pro průhlednost. 24-bitový formát se často používá pro obrázky, které nepotřebují průhlednost, jako jsou formáty jako JPEG.

    Ve vašem kódu GetRGB funkce zpracovává oba formáty a umožňuje získat hodnoty barev pixelů na určitých souřadnicích. Zde je to, jak jsou oba formáty použity:

    • pf24bit

      if LoadedPixelFormat = pf24bit then begin // ... R := Data24bit^.rgbtRed; G := Data24bit^.rgbtGreen; B := Data24bit^.rgbtBlue; Alpha := ''; // V tomto formátu není alfa kanál end;
    • pf32bit

      if LoadedPixelFormat = pf32bit then begin // ... R := Data32bit^.rgbRed; G := Data32bit^.rgbGreen; B := Data32bit^.rgbBlue; Alpha := 'A = ' + IntToStr(Data32bit^.rgbReserved); // Alfa kanál pro průhlednost end;

    V pf24bit jsou složky barvy (R, G, B) získány přímo z datové struktury Data24bit. V pf32bit jsou složky barvy také získány z datové struktury Data32bit, ale navíc je zde i alfa kanál (rgbReserved), který je používán k určení průhlednosti pixelu.

    Tímto způsobem vaše GetRGB funkce umožňuje získat hodnoty barev pixelů v obou formátech a pracovat s nimi v závislosti na tom, který formát aktuálně používáte.

    Komentáře

    Oblíbené příspěvky