Firemonkey bitmap scaling without Aliasing on Android
With Delphi , to the Seattle version , when you scale a bitmap image to enlarge using the command “Canvas.DrawBitmap(OiginalBitmap, RectF(0, 0, OiginalBitmap.Width, OiginalBitmap.Height), RectF(0, 0, Width, Height), 1, False);” the interpolation cant be disabled.
A way to eliminate the problem is to manually scale the bitmap directly creating an image pixel by pixel . To do this you need to get canvas.scale and create an image with the native resolution of the Android device .
This helped me for example to generate qrcode on the display of my Android devices that were as sharp as possible, i use the DelphiZXingQRCode to generate the qrcode in the original format.
To draw the qrcode generated from the library I have implemented the following procedure:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
procedure TForm2.genQrCodeToImage(DestImage: TImage; ContentText: String); var Local_Row: Integer; Local_Column: Integer; vPixelB: Integer; vPixelW: Integer; QRCode: TDelphiZXingQRCode; QRCodeBitmap: TBitmapData; Row: Integer; bmp: FMX.Graphics.TBitmap; Column: Integer; ms: TMemoryStream; bmp2: FMX.Graphics.TBitmap; DestW: Int64; DestH: Int64; pixW: Int64; pixH: Int64; j: Integer; currentRow: Int64; k: Int64; currentCol: Int64; begin { TODO : Inserire nell'url http due parametri : 1) computer name 2) servizio di remoting } ms := nil; bmp := nil; bmp2 := nil; DestW := round(DestImage.Width * Canvas.Scale); DestH := round(DestImage.Height * Canvas.Scale); DestImage.Bitmap.SetSize(DestW, DestH); DestImage.scale.X := 1; DestImage.scale.Y := 1; vPixelB := TAlphaColorRec.Black; // determine colour to use vPixelW := TAlphaColorRec.White; // determine colour to use QRCode := TDelphiZXingQRCode.Create; try QRCode.Data := ContentText; QRCode.Encoding := TQRCodeEncoding(0); QRCode.QuietZone := 4; bmp := FMX.Graphics.TBitmap.Create; bmp.SetSize(DestW,DestH); pixW := Trunc(DestW / QRCode.Columns); pixH := Trunc(DestH / QRCode.Rows); if bmp.Map(TMapAccess.maReadWrite, QRCodeBitmap) then begin // QRCodeBitmap.SetSize(QRCode.Rows, QRCode.Columns); for Local_Row := 0 to QRCode.Rows - 1 do begin currentRow := (pixH * Local_Row); j := 0; while J < pixH do Begin if J > 0 then currentRow := currentRow + 1; J := J + 1; for Local_Column := 0 to QRCode.Columns - 1 do begin currentCol := (PixW * Local_Column); k := 0; while K < pixW do Begin if k > 0 then currentCol := currentCol + 1; k := k+1; if (QRCode.IsBlack[Local_Row, Local_Column]) then begin QRCodeBitmap.SetPixel(currentRow, currentCol, vPixelB); end else begin QRCodeBitmap.SetPixel(currentRow, CurrentCol, vPixelW); end; End; end; End; end; bmp.Unmap(QRCodeBitmap); end; finally QRCode.Free; end; ms := TMemoryStream.Create; bmp.SaveToStream(ms); ms.Position := 0; DestImage.Bitmap.LoadFromStream(ms); try if ms <> nil then ms.Free; if bmp <> nil then bmp.Free; if bmp2 <> nil then bmp2.Free; except end; end; |
and the result is a perfect qrCode without aliasing and interpolation: