如何在 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)及更高版本.

有什么方法可以将 TBitmapTBitmapSurface 转换为 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;