1

I need to Send Images from my (Phone)-App to a Databaseserver using Datasnap. All is working fine, except that I need to send an 128x128 pixel thumbnail in windows bitmap format together with the image. The App is written in Delphi Tokyo and targeting Android 4.4 (API level 19) and later.

Is there any way to convert an TBitmap or TBitmapSurface to windows bitmap format and save it to a stream? (maybe an custom TBmpBitmapCodec for Android?)

Fabrizio
  • 7,603
  • 6
  • 44
  • 104
  • This link https://stackoverflow.com/questions/22909429/android-save-a-bitmap-to-bmp-file-format probably explains your problem (albeit the solution is not in Delphi) so the answer to your question is yes, but this answer would need to be converted to Delphi – Dsm Apr 13 '18 at 07:17
  • Why not simply use .png? – Freddie Bell Apr 13 '18 at 18:23
  • i would use .PNG or .JPG - but the Windows Software that is receving the Images needs for the Thumbnail Preview Picture BMP Format... Unfortunately i cant change this... – Erwin Sienknecht Apr 16 '18 at 09:53

2 Answers2

0

you can look https://github.com/Zeus64/alcinoe/ in the unit AlGraphic.pas you have all the functions and example you need to convert a android/iOS bitmap to an windows Bitmap.

for android you can convert a jbitmap to bitmapSurface (and later convert the bitmapsurface to bitmap object) like this :

aBitmapSurface := TBitmapSurface.Create;
try
  if JBitmapToSurface(aJBitmap, aBitmapSurface) then 
    MyBitmap.AssignFromSurface(aBitmapSurface);
finally
  ALFreeAndNil(abitmapSurface);
end;
zeus
  • 12,173
  • 9
  • 63
  • 184
  • Thanks for your answer, the package looks promising, but i really have no clue how to use it. I already have a FMX.Graphics.TBitmap (and a FMX.Surfaces.TBitmapSurface) filled with my resized Thumbnail - how can i convert this to Windows Bitmap format (24bit or 32biit) and save the result into an Stream or TBytes Array? – Erwin Sienknecht Apr 13 '18 at 09:18
  • bah just like in the example i wrote you ! – zeus Apr 13 '18 at 10:23
  • 1
    What Type is "MyBitmap" in your example? – Erwin Sienknecht Apr 13 '18 at 10:55
  • MyBitmap is fmx Tbitmap and aJbitmap is a jBitmap – zeus Apr 13 '18 at 10:56
  • 1
    I need BMP Format, so FMX.Graphics.TBitmap is no help. (on Android it only supports GIF, JPG, JPEG and PNG) – Erwin Sienknecht Apr 13 '18 at 11:06
  • ooh ok i understand, so There's no built-in encoder for BMP so forget this way, try to send png instead – zeus Apr 13 '18 at 12:02
0

i've solved my Problem - with a function that converts FMX.Graphics.TBitmap to Windows Bitmap Format (in a TBytesStream)

it only generates 24bits per Pixel, uncompressed BMPs, but for me that is fine (only 128x128 Pixel Thumbnails)

  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          := $4D42;
        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;