如何在 Android/iOS 上将 FireMonkey TBitmap 转换为 Windows 位图 (.bmp)?
How to Convert FireMonkey TBitmap to Windows Bitmap (.bmp) on Android/iOS?
我需要使用 Datasnap 将图像从我的 (Phone)-App 发送到数据库服务器。一切正常,只是我需要将 windows 位图格式的 128x128 像素缩略图与图像一起发送。
该应用程序是在 Delphi Tokyo 中编写的,目标是 Android 4.4(API 级别 19)及更高版本.
有什么方法可以将 TBitmap
或 TBitmapSurface
转换为 windows 位图格式并将其保存到流中? (也许是 Android 的自定义 TBmpBitmapCodec
?)
您可以查看 https://github.com/Zeus64/alcinoe/ 单元 AlGraphic.pas
您拥有将 android/iOS 位图转换为 windows 位图所需的所有函数和示例。
对于 android,您可以像这样将 jbitmap 转换为 bitmapSurface(然后将位图表面转换为位图对象):
aBitmapSurface := TBitmapSurface.Create;
try
if JBitmapToSurface(aJBitmap, aBitmapSurface) then
MyBitmap.AssignFromSurface(aBitmapSurface);
finally
ALFreeAndNil(abitmapSurface);
end;
我已经解决了我的问题 - 使用将 FMX.Graphics.TBitmap 转换为 Windows 位图格式(在 TBytesStream 中)的函数
它只生成每像素 24 位、未压缩的 BMP,但对我来说这很好(只有 128x128 像素缩略图)
Type TBitmapFileHeader = Record
bfType : Word; // ASCII "BM" (Hex: 0x424D)
bfSize : FixedUInt; // Size of BMP File
bfReserved : FixedUInt; // Reserved, Default 0x00000000
bfOffBits : FixedUInt; // Offset of Imagedata, Default 0x00000036 (Header (14) + Infoheader(40) = 54)
end;
TBitmapInfoHeader = Record
biSize : FixedUInt; // Größe der BITMAPINFOHEADER-Struktur in Byte
biWidth : FixedInt; // Breite der Bitmap in Pixel.
biHeight : FixedInt; // Der Betrag gibt die Höhe der Bitmap in Pixel an.
// Ist der Wert positiv, so ist die Bitmap eine sogenannte "bottom-up"-Bitmap (die Bilddaten beginnen mit der untersten und enden mit der obersten Bildzeile). Dies ist die gebräuchlichste Variante.
// Ist der Wert negativ, so ist die Bitmap eine "top-down"-Bitmap (die Bilddaten beginnen mit der obersten und enden mit der untersten Bildzeile).
biPlanes : Word; // 1 (Stand in einigen älteren Formaten wie PCX für die Anzahl der Farbebenen, wird aber für BMP nicht verwendet)
biBitCount : Word; // Gibt die Farbtiefe der Bitmap in bpp an; muss einer der folgenden Werte sein: 1, 4, 8, 16, 24 oder 32. Bei 1, 4 und 8 bpp sind die Farben indiziert.
biCompression : FixedUInt; // Einer der folgenden Werte:
// 0 (BI_RGB): Bilddaten sind unkomprimiert.
// 1 (BI_RLE8): Bilddaten sind lauflängenkodiert für 8 bpp. Nur erlaubt wenn biBitCount=8 und biHeight positiv.
// 2 (BI_RLE4): Bilddaten sind lauflängenkodiert für 4 bpp. Nur erlaubt wenn biBitCount=4 und biHeight positiv.
// 3 (BI_BITFIELDS): Bilddaten sind unkomprimiert und benutzerdefiniert (mittels Farbmasken) kodiert. Nur erlaubt wenn biBitCount=16 oder 32.
biSizeImage : FixedUInt; // Wenn biCompression=BI_RGB: Entweder 0 oder die Größe der Bilddaten in Byte.
// Ansonsten: Größe der Bilddaten in Byte.
biXPelsPerMeter : FixedInt; // Horizontale Auflösung des Zielausgabegerätes in Pixel pro Meter; wird aber für BMP-Dateien meistens auf 0 gesetzt.
biYPelsPerMeter : FixedInt; // Vertikale Auflösung des Zielausgabegerätes in Pixel pro Meter; wird aber für BMP-Dateien meistens auf 0 gesetzt.
biClrUsed : FixedUInt; // Wenn biBitCount=1: 0.
// Wenn biBitCount=4 oder 8: die Anzahl der Einträge der Farbtabelle; 0 bedeutet die maximale Anzahl (2, 16 oder 256).
// Ansonsten: Die Anzahl der Einträge der Farbtabelle (0=keine Farbtabelle). Auch wenn sie in diesem Fall nicht notwendig ist, kann dennoch eine für die Farbquantisierung empfohlene Farbtabelle angegeben werden.
biClrImportant : FixedUInt; // Wenn biBitCount=1, 4 oder 8: Die Anzahl sämtlicher im Bild verwendeten Farben; 0 bedeutet alle Farben der Farbtabelle.
// Ansonsten:
// Wenn eine Farbtabelle vorhanden ist und diese sämtliche im Bild verwendeten Farben enthält: deren Anzahl.
// Ansonsten: 0.
end;
Function ConvertTBitmapToBMP(orgBitmap: FMX.Graphics.TBitmap) : tBytesStream;
var x, y, p : Integer;
offBits : Integer;
dataSize : Integer;
BmpFHeader : TBitmapFileHeader;
BmpIHeader : TBitmapInfoHeader;
BitData : TBitmapData;
AC : TAlphaColor;
begin
Result := NIL;
if Assigned(orgBitmap) then begin
if (orgBitmap.Map(TMapAccess.ReadWrite, BitData)) then begin
try
Result := tBytesStream.Create;
BmpIHeader.biSize := SizeOf(TBitmapInfoHeader);
BmpIHeader.biWidth := orgBitmap.width;
BmpIHeader.biHeight := orgBitmap.height;
BmpIHeader.biPlanes := 1;
BmpIHeader.biBitCount := 24;
BmpIHeader.biCompression := 0;
BmpIHeader.biSizeImage := orgBitmap.width * orgBitmap.height * (BmpIHeader.biBitCount DIV 8);
BmpIHeader.biXPelsPerMeter := 0;
BmpIHeader.biYPelsPerMeter := 0;
BmpIHeader.biClrUsed := 0;
BmpIHeader.biClrImportant := 0;
offBits := SizeOf(TBitmapFileHeader) + SizeOf(TBitmapInfoHeader);
dataSize := orgBitmap.width * orgBitmap.height * (BmpIHeader.biBitCount DIV 8);
BmpFHeader.bfType := D42;
BmpFHeader.bfSize := offBits + dataSize;
BmpFHeader.bfReserved := 0;
BmpFHeader.bfOffBits := offBits;
Result.Clear;
Result.Write(BmpFHeader.bfType, 2);
Result.Write(BmpFHeader.bfSize, 4);
Result.Write(BmpFHeader.bfReserved, 4);
Result.Write(BmpFHeader.bfOffBits, 4);
Result.Write(BmpIHeader.biSize, 4);
Result.Write(BmpIHeader.biWidth, 4);
Result.Write(BmpIHeader.biHeight, 4);
Result.Write(BmpIHeader.biPlanes, 2);
Result.Write(BmpIHeader.biBitCount, 2);
Result.Write(BmpIHeader.biCompression, 4);
Result.Write(BmpIHeader.biSizeImage, 4);
Result.Write(BmpIHeader.biXPelsPerMeter, 4);
Result.Write(BmpIHeader.biYPelsPerMeter, 4);
Result.Write(BmpIHeader.biClrUsed, 4);
Result.Write(BmpIHeader.biClrImportant, 4);
Result.Size := BmpFHeader.bfSize;
for y := 0 to orgBitmap.height - 1 do begin
for x := 0 to orgBitmap.width - 1 do begin
AC := BitData.GetPixel(x, y);
p := (((orgBitmap.height-y) * orgBitmap.width) + x) * (BmpIHeader.biBitCount DIV 8);
Result.Bytes[offBits+p ] := TAlphaColorRec(AC).B;
Result.Bytes[offBits+p+1] := TAlphaColorRec(AC).G;
Result.Bytes[offBits+p+2] := TAlphaColorRec(AC).R;
end;
end;
Result.Position := 0;
finally
orgBitmap.Unmap(BitData);
end;
end;
end;
end;
我需要使用 Datasnap 将图像从我的 (Phone)-App 发送到数据库服务器。一切正常,只是我需要将 windows 位图格式的 128x128 像素缩略图与图像一起发送。 该应用程序是在 Delphi Tokyo 中编写的,目标是 Android 4.4(API 级别 19)及更高版本.
有什么方法可以将 TBitmap
或 TBitmapSurface
转换为 windows 位图格式并将其保存到流中? (也许是 Android 的自定义 TBmpBitmapCodec
?)
您可以查看 https://github.com/Zeus64/alcinoe/ 单元 AlGraphic.pas
您拥有将 android/iOS 位图转换为 windows 位图所需的所有函数和示例。
对于 android,您可以像这样将 jbitmap 转换为 bitmapSurface(然后将位图表面转换为位图对象):
aBitmapSurface := TBitmapSurface.Create;
try
if JBitmapToSurface(aJBitmap, aBitmapSurface) then
MyBitmap.AssignFromSurface(aBitmapSurface);
finally
ALFreeAndNil(abitmapSurface);
end;
我已经解决了我的问题 - 使用将 FMX.Graphics.TBitmap 转换为 Windows 位图格式(在 TBytesStream 中)的函数
它只生成每像素 24 位、未压缩的 BMP,但对我来说这很好(只有 128x128 像素缩略图)
Type TBitmapFileHeader = Record
bfType : Word; // ASCII "BM" (Hex: 0x424D)
bfSize : FixedUInt; // Size of BMP File
bfReserved : FixedUInt; // Reserved, Default 0x00000000
bfOffBits : FixedUInt; // Offset of Imagedata, Default 0x00000036 (Header (14) + Infoheader(40) = 54)
end;
TBitmapInfoHeader = Record
biSize : FixedUInt; // Größe der BITMAPINFOHEADER-Struktur in Byte
biWidth : FixedInt; // Breite der Bitmap in Pixel.
biHeight : FixedInt; // Der Betrag gibt die Höhe der Bitmap in Pixel an.
// Ist der Wert positiv, so ist die Bitmap eine sogenannte "bottom-up"-Bitmap (die Bilddaten beginnen mit der untersten und enden mit der obersten Bildzeile). Dies ist die gebräuchlichste Variante.
// Ist der Wert negativ, so ist die Bitmap eine "top-down"-Bitmap (die Bilddaten beginnen mit der obersten und enden mit der untersten Bildzeile).
biPlanes : Word; // 1 (Stand in einigen älteren Formaten wie PCX für die Anzahl der Farbebenen, wird aber für BMP nicht verwendet)
biBitCount : Word; // Gibt die Farbtiefe der Bitmap in bpp an; muss einer der folgenden Werte sein: 1, 4, 8, 16, 24 oder 32. Bei 1, 4 und 8 bpp sind die Farben indiziert.
biCompression : FixedUInt; // Einer der folgenden Werte:
// 0 (BI_RGB): Bilddaten sind unkomprimiert.
// 1 (BI_RLE8): Bilddaten sind lauflängenkodiert für 8 bpp. Nur erlaubt wenn biBitCount=8 und biHeight positiv.
// 2 (BI_RLE4): Bilddaten sind lauflängenkodiert für 4 bpp. Nur erlaubt wenn biBitCount=4 und biHeight positiv.
// 3 (BI_BITFIELDS): Bilddaten sind unkomprimiert und benutzerdefiniert (mittels Farbmasken) kodiert. Nur erlaubt wenn biBitCount=16 oder 32.
biSizeImage : FixedUInt; // Wenn biCompression=BI_RGB: Entweder 0 oder die Größe der Bilddaten in Byte.
// Ansonsten: Größe der Bilddaten in Byte.
biXPelsPerMeter : FixedInt; // Horizontale Auflösung des Zielausgabegerätes in Pixel pro Meter; wird aber für BMP-Dateien meistens auf 0 gesetzt.
biYPelsPerMeter : FixedInt; // Vertikale Auflösung des Zielausgabegerätes in Pixel pro Meter; wird aber für BMP-Dateien meistens auf 0 gesetzt.
biClrUsed : FixedUInt; // Wenn biBitCount=1: 0.
// Wenn biBitCount=4 oder 8: die Anzahl der Einträge der Farbtabelle; 0 bedeutet die maximale Anzahl (2, 16 oder 256).
// Ansonsten: Die Anzahl der Einträge der Farbtabelle (0=keine Farbtabelle). Auch wenn sie in diesem Fall nicht notwendig ist, kann dennoch eine für die Farbquantisierung empfohlene Farbtabelle angegeben werden.
biClrImportant : FixedUInt; // Wenn biBitCount=1, 4 oder 8: Die Anzahl sämtlicher im Bild verwendeten Farben; 0 bedeutet alle Farben der Farbtabelle.
// Ansonsten:
// Wenn eine Farbtabelle vorhanden ist und diese sämtliche im Bild verwendeten Farben enthält: deren Anzahl.
// Ansonsten: 0.
end;
Function ConvertTBitmapToBMP(orgBitmap: FMX.Graphics.TBitmap) : tBytesStream;
var x, y, p : Integer;
offBits : Integer;
dataSize : Integer;
BmpFHeader : TBitmapFileHeader;
BmpIHeader : TBitmapInfoHeader;
BitData : TBitmapData;
AC : TAlphaColor;
begin
Result := NIL;
if Assigned(orgBitmap) then begin
if (orgBitmap.Map(TMapAccess.ReadWrite, BitData)) then begin
try
Result := tBytesStream.Create;
BmpIHeader.biSize := SizeOf(TBitmapInfoHeader);
BmpIHeader.biWidth := orgBitmap.width;
BmpIHeader.biHeight := orgBitmap.height;
BmpIHeader.biPlanes := 1;
BmpIHeader.biBitCount := 24;
BmpIHeader.biCompression := 0;
BmpIHeader.biSizeImage := orgBitmap.width * orgBitmap.height * (BmpIHeader.biBitCount DIV 8);
BmpIHeader.biXPelsPerMeter := 0;
BmpIHeader.biYPelsPerMeter := 0;
BmpIHeader.biClrUsed := 0;
BmpIHeader.biClrImportant := 0;
offBits := SizeOf(TBitmapFileHeader) + SizeOf(TBitmapInfoHeader);
dataSize := orgBitmap.width * orgBitmap.height * (BmpIHeader.biBitCount DIV 8);
BmpFHeader.bfType := D42;
BmpFHeader.bfSize := offBits + dataSize;
BmpFHeader.bfReserved := 0;
BmpFHeader.bfOffBits := offBits;
Result.Clear;
Result.Write(BmpFHeader.bfType, 2);
Result.Write(BmpFHeader.bfSize, 4);
Result.Write(BmpFHeader.bfReserved, 4);
Result.Write(BmpFHeader.bfOffBits, 4);
Result.Write(BmpIHeader.biSize, 4);
Result.Write(BmpIHeader.biWidth, 4);
Result.Write(BmpIHeader.biHeight, 4);
Result.Write(BmpIHeader.biPlanes, 2);
Result.Write(BmpIHeader.biBitCount, 2);
Result.Write(BmpIHeader.biCompression, 4);
Result.Write(BmpIHeader.biSizeImage, 4);
Result.Write(BmpIHeader.biXPelsPerMeter, 4);
Result.Write(BmpIHeader.biYPelsPerMeter, 4);
Result.Write(BmpIHeader.biClrUsed, 4);
Result.Write(BmpIHeader.biClrImportant, 4);
Result.Size := BmpFHeader.bfSize;
for y := 0 to orgBitmap.height - 1 do begin
for x := 0 to orgBitmap.width - 1 do begin
AC := BitData.GetPixel(x, y);
p := (((orgBitmap.height-y) * orgBitmap.width) + x) * (BmpIHeader.biBitCount DIV 8);
Result.Bytes[offBits+p ] := TAlphaColorRec(AC).B;
Result.Bytes[offBits+p+1] := TAlphaColorRec(AC).G;
Result.Bytes[offBits+p+2] := TAlphaColorRec(AC).R;
end;
end;
Result.Position := 0;
finally
orgBitmap.Unmap(BitData);
end;
end;
end;
end;