Ładuję do komponentu TImage co jakiś czas różne pliki graficzne (png) i chciałbym rozpoznać, który plik jest aktualnie załadowany. Próbowałem tak:
if Image1.Picture.Graphic.Equals(bitmapa1) then
ale nie wychodzi.
co to znaczy który plik jest aktualnie załadowany
? Jak ładujesz, skąd?
Załadowany instrukcją LoadFromFile(filename)
Chcę wiedzieć jaki plik graficzny jest obecnie w komponencie TIMage. Czyli znać albo nazwę pliku graficznego (może być ze ścieżką dostępu), albo czy dany plik graficzny np.
Var bitmap1:TBitmap;
bitmap1:=TBitmap.create;
bitmap1.loadfromfile(filename);
np. Bitmap1 jest aktualnie w TImage, czy też jakiś inny.
A może to porównywanie obrazów byłoby możliwe.Jak jednak porównać do siebie dwie grafiki po ich wyglądzie czy są takie same?
Rozszerz sobie subclassingiem klasę TImage
i dodaj do niej właściwość służącą do odczytu ścieżki ładowanego pliku oraz metodę, która załaduje obraz z pliku i zapamięta ścieżkę. I z głowy. ;)
type
TImage = class(ExtCtrls.TImage)
private
FFileName: String;
public
procedure LoadImageStoreName(const AFileName: String);
procedure DoneImageClearName();
public
property FileName: String read FFileName;
end;
{..}
procedure TImage.LoadImageStoreName(const AFileName: String);
begin
Picture.LoadFromFile(AFileName);
FFileName := AFileName;
end;
procedure TImage.DoneImageClearName();
begin
Picture.Clear();
FFileName := '';
end;
I zamiast używać metody LoadFromFile
, użyj LoadImageStoreName
(drugiej do usunięcia obrazu i nazwy).
A jeśli tych kontrolek używasz w wielu formularzach to zamiast subclassingu, po prostu stwórz sobie własną kontrolkę dziedziczącą z TImage
i rozszerz jej funkcjonalność w podobny sposób.
A czy przypadkiem nie chodzi Ci o coś takiego... detecting graphic formats
furious programming napisał(a):
/ciach/
A jak potrzebujesz porównać zawartość dwóch obrazów, to do tego celu służy metoda
Equals
.
Nooo... nie.
Metoda Equals
został zaimplementowana na poziomie TObject
w ten sposób:
function TObject.Equals(Obj: TObject): Boolean;
begin
Result := Obj = Self;
end;
I służy do sprawdzenia czy podana referencja na obiekt jest tym samym obiektem z którego wywołujemy metodę Equals
.
Ale na pewno nie porównuje ona dwóch obrazów.
Compare graphic to another TGraphic object and return true if objects contain same graphic.
Equals compares the contents of two TGraphic objects. Equals returns false if the TGraphic are different classes or if they contain different graphical data.
Dokumentacja kłamie? ;)
furious programming napisał(a):
Compare graphic to another TGraphic object and return true if objects contain same graphic.
Equals compares the contents of two TGraphic objects. Equals returns false if the TGraphic are different classes or if they contain different graphical data.
Dokumentacja kłamie? ;)
Pewnie ;)
TGraphic
faktycznie ma inną implementację, ale ona na pewno nie sprawdza obrazów.
Sprawdza typ pliku graficznego i rozmiar strumienia - ale nie porównuje obrazu :)
Innymi słowy - mając ten sam obraz w różnych formatach graficznych, ta metoda zawsze zwróci False.
Mając inne obrazy, w tym samym formacie grafiki i z identycznym rozmiarem, metoda zwróci True.
Czy to jest porównanie obrazów? ;-)
Nie wiem o co autorowi dokładnie chodzi. Nie znam też wewnętrznych implementacji klas, o których rozmawiacie.
Ale padło tu pytanie jak porównać dwa pliki graficzne czy są takie same.
Jeśli chodzi o bitmapy to stosunkowo proste zadane.
Bitmapy są przechowywane w pamięci w dwóch postaciach:
W tym drugim przypadku aby manipulować bitmapą trzeba znać dwa adresy:
Żeby porównać dwie bitmapy trzeba:
Porównać ich nagłówki (memcmp(adrHeader1, adrHeader2, sizeof(BITMAPINFOHEADER))
Jeśli są różne - to na pewno bitmapy są różne.
Sprawdzić pole biBitCount w BITMAPINFOHEADER i jeśli jest osiem lub mniej, to wyliczyć rozmiar tablicy kolorów.
Tablica kolorów jest pamiętana jako tablica RGBQUAD (cztery bajty na jeden kolor).
Liczba pozycji w tablicy kolorów to 2 do potęgi biBitCount.
Znając rozmiar tablicy kolorów, trzeba porównać tablice obu bitmap i jeśli są różne - to bitmapy na pewno są różne.
BITMAPINFOHEADER + tablica kolorów wzięte razem stanowią strukturę BITMAPINFO.
Porównać bajty zawierające treść obrazu
Rozmiar tego obszaru - to:
ScanBytes(header->biWidth, header->biBitCount)*header->biHeight;
ScanBytes - to funkcja wyliczająca szerokość linii skanowania
long ScanBytes(long pixWidth, int bitsPixel) {
return ((pixWidth*bitsPixel+31)>>5)<<2;
}
(linia skanowania w bajtach jest zaokrąglana do najbliższej granicy czterech bajtów w górę).
Jeśli natomiast bitmapa jest pamiętana jako zależna od sprzętu, to mamy do niej uchwyt HBITMAP.
Wtedy trzeba byłoby ją przekonwertować na DIB. Aby to zrobić należy przydzielić dwa obszary pamięci (na BITMAPINFO, tzn. BITMAPINFOHEADER + ewentualnie tablica kolorów i na bajty zawierające treść obrazu), a następnie wykonać funkcję GetDIBits (przed jej wykonaniem należy wypełnić BITMAPINFOHEADER). Po wykonaniu tej funkcji mamy dane w BITMAPINFOHEADER i w obszarze z treścią obrazu i dalej działamy jak opisałem wyżej.
Jeśli mowa o bitmapach ładowanych do obiektów klasy TBitmap
, to porównanie ich zawartości jest bardzo proste. Wystarczy skorzystać z właściwości ScanLine
i z faktu, że piksele są 24-bitowe w pamięci.
function CompareBitmaps(ABitmapA, ABitmapB: TBitmap): Boolean;
var
LineIndex, LineSize: Integer;
begin
if ABitmapA.Width <> ABitmapB.Width then Exit(False);
if ABitmapA.Height <> ABitmapB.Height then Exit(False);
LineSize := ABitmapA.Width * SizeOf(TRGBTriple);
for LineIndex := 0 to ABitmapA.Height - 1 do
if not CompareMem(ABitmapA.ScanLine[LineIndex], ABitmapB.ScanLine[LineIndex], LineSize) then
Exit(False);
Result := True;
end;
TBitmap
, alokowany jest blok pamięci, do którego wypakowywane są dane na temat pikseli (dostęp do niego daje właściwość ScanLine
). Blok ten zawsze zawiera piksele 24-bitowe, bez względu na to czy załadowano obraz 24-bitowy, czy 4-bitowy – dlatego można ”walić w ciemno”.
TBitmap
ma bardzo prostą funkcjonalność, praktycznie ogranicza się do obsługi 24-bitowych obrazów i takich używam np. w swojej gierce. Zawsze traktuję piksele jako 24-bitowe, pomimo tego, że w plikach te obrazy są 4-bitowe (indeksowana paleta kolorów) i skompresowane za pomocą RLE (coby mniej ważyły). Przy ładowaniu do pamięci, obraz jest automatycznie dekompresowany do postaci 24-bitowej i takiego się następnie używa.
TFPMemoryImage
, która przechowuje dane na temat pikseli w formie 64-bitowej (po 16 bitów na kanał) i pozwala na wszystko (obsługę różnych formatów, zmianę bitowości, obsługę palet kolorów, kompresję itd.). No i też jest wieloplatformowa.