Jump to content

vfbb

Members
  • Content Count

    266
  • Joined

  • Last visited

  • Days Won

    30

Posts posted by vfbb


  1. 18 minutes ago, Krzy said:

    I did it.

    But when I click Menu > Project > Deploy , Delphi update file AndroidManifest.xml and delete this line.

    You should edit your AndroidManifest.template.xml (You can found it template in your dproj folder after the first compilation to android platform), and not the final AndroidManifest in deploy path.

    • Like 3

  2. 25 minutes ago, William23668 said:

    This mean I have to draw at canvas level inside each row in TListView ?

     

    
    ACanvas.DrawSimpleText('"Each dream that you', 2, 25, LFont, LPaint);

     

    Not! This part is exemplifying the direct use of the API. It's exactly like @Sherlock said, just replace the default FMX renderer with Skia's renderer ("GlobalUseSkia := True;" in your dpr). But there are a few more notes in the RightToLeft section in readme, which I've printed here:

     

    image.thumb.png.6ef2660bf4073d6585e13045bf74edd8.png

     

     

     

    • Like 2
    • Thanks 1

  3. 31 minutes ago, Anders Melander said:

    A picture of a red apple and a yellow banana is "similar" because they are both pictures of fruits.

    When I said similarity of images, I meant similarity of pixels. It can check if the image is identical (similarity = 1) or if it is very close (similarity >= 0.99 for example).

     

    We use this because it is normal for some drawings to vary a few pixels from platform to platform or from backend render to backend render. For example, text on Windows is slightly different from text on Android, even though both have the same font loaded. So in the unit tests we set up some tolerable similarity for each type of drawing.

    • Like 2

  4. If you just want to check if 2 images are identical or similar, I have an optimal solution:

     

    The Skia4Delphi unit test has an independent unit of image hashing (or similarity hashing).

     

    https://github.com/skia4delphi/skia4delphi/blob/main/Tests/Source/Skia.Tests.Foundation.ImageHash.pas

     

    Basically, this class allows you to:


    - Compare 2 images and return the similarity between them (0..1)
    - Generate a hash of the image
    - Compare an image with a previously generated hash and return the similarity (0..1)

     

    Note: It may seem strange but the hash it generates is a hash itself for similarity, that is, if you change part of the image, only part of the hash will be changed. Internally it implements 3 known similarity algorithms (like perceptual hash) and one of our own. The union of the 4 algorithms is to increase the final accuracy.

     

    Logically there is a margin of error, but the accuracy is excellent. You can put for example a check to see if the hash similarity is >= 0.99 to decide if they are equal.

     

    In the class, the input parameters of the images are of type ISkImage, which can be created in two different ways:

     

    - TSkImage.MakeFromEncoded(Bytes)
    - Bitmap.ToSkImage;

     

    Note: Add the units Skia and Skia.Vcl (or Skia.FMX), to use the example above.


  5. @Uwe Raabe I also wanted to suggest adding a flag to remove the jars. If I remove the android jars from a dproj, I can use the same dproj in any version of Delphi (the IDE will set the default jars when open it). But if I don't remove it, I have to do a 'Revert To Defaults' when I open the project (and an amateur programmer doesn't even know this, will compile and see an error and give up).

     

    The solution would be: either add a flag to remove them or check if the list of jars is the defaults of some version of RAD Studio and if it will remove it automatically.


  6. You can try using Refit, which is a library to consume apis rest in a simple way, without manipulating strings, json, or http components.

     

    First you would create a unit for your api:

     

    unit CheckBook;
    
    interface
    
    uses
      iPub.Rtl.Refit; // Just download and add it to your project: https://github.com/viniciusfbb/ipub-refit
    
    type
      TNewPayment = record
        Recipient: string;
        Name: string;
        Amount: Double;
        Number: string;
        Description: string;
      end;
    
      [BaseUrl('https://sandbox.checkbook.io/v3')]
      ICheckBookApi = interface(IipRestApi)
        ['{97789B20-5C26-4359-AC41-D2042C4FAEC7}']
    
        [Post('/check/digital')]
        [Headers('Authorization', '{AuthToken}')]
        function CreateDigitalPayment(const ABody: TNewPayment): string;
    
        function GetAuthToken: string;
        procedure SetAuthToken(const AValue: string);
        property AuthToken: string read GetAuthToken write SetAuthToken;
      end;
    
    var
      FCheckBookApi: ICheckBookApi;
    
    implementation
    
    initialization
      FCheckBookApi := GRestService.&For<ICheckBookApi>;
    end.

     

    Then you would consume it in your forms as follows:

     

    uses
      CheckBook;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      LNewPayment: TNewPayment;
    begin
      LNewPayment.Recipient := 'testing@checkbook.io';
      LNewPayment.Name := 'Widgets Inc.';
      LNewPayment.Amount := 5;
      LNewPayment.Number := '';
      LNewPayment.Description := 'Test Payment';
    
      FCheckBookApi.AuthToken := 'xxxxxxxxx:xxxxxxxx';
      ShowMessage(FCheckBookApi.CreateDigitalPayment(LNewPayment));
    end;

     

    • Like 2
    • Thanks 1

  7. @XylemFlow You can use the Skia4Delphi for that. I made a small example of how to do this:
     

    unit Unit1;
    
    interface
    
    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
      FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs;
    
    type
      TForm1 = class(TForm)
        procedure FormPaint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.fmx}
    
    uses
      {$IFDEF SKIA}
      Skia, Skia.FMX, Skia.FMX.Graphics,
      {$ENDIF}
      System.Math;
    
    {$IFDEF SKIA}
    procedure DrawPath(const ACanvas: ISkCanvas; const APathData: TPathData;
      const AFillType: TSkPathFillType; const AFill: TBrush;
      const AStroke: TStrokeBrush);
    var
      LPaint: ISkPaint;
      LPath: ISkPath;
      LPathBuilder: ISkPathBuilder;
    begin
      LPathBuilder := TSkPathBuilder.Create(AFillType);
      LPathBuilder.AddPath(APathData.ToSkPath);
      LPath := LPathBuilder.Detach;
    
      if (AFill <> nil) and (AFill.Kind = TBrushKind.Solid) then
      begin
        LPaint := TSkPaint.Create;
        LPaint.AntiAlias := True;
        LPaint.Color := AFill.Color;
        ACanvas.DrawPath(LPath, LPaint);
      end;
      if (AStroke <> nil) and (AStroke.Kind = TBrushKind.Solid) then
      begin
        LPaint := TSkPaint.Create(TSkPaintStyle.Stroke);
        LPaint.AntiAlias := True;
        LPaint.Color := AStroke.Color;
        LPaint.StrokeWidth := AStroke.Thickness;
        ACanvas.DrawPath(LPath, LPaint);
      end;
    end;
    {$ENDIF}
    
    procedure TForm1.FormPaint(Sender: TObject; Canvas: TCanvas;
      const ARect: TRectF);
    
      function CircleRect(const ACenterX, ACenterY, ARadius: Single): TRectF;
      begin
        Result := TRectF.Create(ACenterX - ARadius, ACenterY - ARadius, ACenterX + ARadius, ACenterY + ARadius);
      end;
    
    var
      LBitmap: TBitmap;
      LPathData: TPathData;
      LRadius: Single;
    begin
      LRadius := Min(ARect.Width, ARect.Height) / 4;
    
      LPathData := TPathData.Create;
      LPathData.AddEllipse(CircleRect(ARect.CenterPoint.X - LRadius / 2, ARect.CenterPoint.Y - LRadius / 2, LRadius));
      LPathData.AddEllipse(CircleRect(ARect.CenterPoint.X - LRadius / 2, ARect.CenterPoint.Y + LRadius / 2, LRadius));
      LPathData.AddEllipse(CircleRect(ARect.CenterPoint.X + LRadius / 2, ARect.CenterPoint.Y - LRadius / 2, LRadius));
      LPathData.AddEllipse(CircleRect(ARect.CenterPoint.X + LRadius / 2, ARect.CenterPoint.Y + LRadius / 2, LRadius));
    
      Canvas.Fill.Kind := TBrushKind.Solid;
      Canvas.Fill.Color := TAlphaColors.Cadetblue;
      Canvas.Stroke.Kind := TBrushKind.Solid;
      Canvas.Stroke.Color := TAlphaColors.Chocolate;
      Canvas.Stroke.Thickness := 8;
    
      {$IFDEF SKIA}
      if Canvas is TSkCanvasCustom then
      begin
        DrawPath(TSkCanvasCustom(Canvas).Canvas, LPathData, TSkPathFillType.Winding, Canvas.Fill, Canvas.Stroke);
      end
      else
      begin
        // Fallback if you remove the "GlobalUseSkia := True;" from .dpr
        LBitmap := TBitmap.Create(Round(ARect.Width), Round(ARect.Height));
        try
          LBitmap.SkiaDraw(
            procedure(const ACanvas: ISkCanvas)
            begin
              DrawPath(TSkCanvasCustom(Canvas).Canvas, LPathData, TSkPathFillType.Winding, Canvas.Fill, Canvas.Stroke);
            end);
          Canvas.DrawBitmap(LBitmap, LBitmap.BoundsF, ARect, 1);
        finally
          LBitmap.Free;
        end;
      end;
      {$ELSE}
      Canvas.FillPath(LPathData, 1);
      Canvas.DrawPath(LPathData, 1);
      {$ENDIF}
    end;
    
    end.

     

    The result with FMX pure:

    image.thumb.png.ec0816ffe8ce2cc7bf22c0831739c9db.png

     

    The result after enable Skia in the project:

    image.thumb.png.dfae01dfe6f9e2bc95833dbd0ce17e96.png

     

    The project is attached.

    WindingPath.7z


  8. @David_Lyon  We still don't have an ideal renderer, the complete and correct job would be to replace 25% of the FMX, that is, the entire rendering:

    • TCanvas (of screen and bitmaps),
    • TContext (rendering of 3D forms and shaders)
    • TTextLayout,
    • Codecs,
    • Shaders code (Filters and Effects),
    • Printers,
    • Backends graphic libraries (GLES, Metal, DirectX, ...),
    • Caching systems,
    • and others;

    Making implementations that use Skia, because Skia is a layer that adds new features, quality, reliability and important optimizations.

    Much of the work has already been done and works perfectly, and is already faster overall than the default system (see the Benchmark/FmxFPS project in your Skia4Delphi folder). But there are still parts that need to be improved, for example, the performance of bitmaps and effects.

     

    About the quality, we did something that FMX should have done: we considered the already existing property Form.Quality to define the quality of the drawings, which can be HighPerformance, SystemDefault or HighQuality. Anti-alias is only disabled when Form.Quality = HighPerformance, which should be your case.

     

    Over the past few months we have focused on full API stability, adding features and rendering reliability. It is likely that the performance is in the next targets but, as I said, in the current implementation there are already some gains in the main operations, mainly in the texts, and only some types of applications or hardware show worsening.

     

    Note: do not use VM or Debug mode to run the benchmark and I advise leaving Form.Quality = SystemDefault.

    Furthermore, Skia4Delphi's renderer is optional, that is, you can disable it and use only the library controls for example. In this case, just remove the "GlobalUseSkia := True;" make your .dpr.


  9.  

    v4.0.1

     

    • Added option to "Enable Skia" in dll projects; [Plugin]
    • Fixed AV with GPU canvas; [Render]
    • Fixed exceptions with OpenGLES backend on Android; [Render]
    • Fixed issue with creating bitmap cache (texture); [Render]
    • Fixed 3D controls (TViewPort3D) rendering with OpenGLES backend; [Render]
    • Fixed wrong draw of text with attributes in TTextLayout; [Render]
    • Minor improvements.

      Skia version: 107.0.0

     

    • Like 2

  10. github-social-preview.thumb.png.06fa9b6d00c8816b8daf0bf167ba7080.png

     

     

    v4.0.0

     

     

    • Skia library version has been updated from Milestone 98 to 107; [API]
    • Added support for iOS Simulator ARM 64-bit to RAD Studio 11.2 Alexandria or newer. [API]
    • Added TBitmap.CreateFromSkImage; [Framework]
    • Added LinesCount and DidExceedMaxLines properties to TSkLabel; [Framework]
    • Added new splashscreen to our main demo; [Samples]
    • Added ISkParagraph.Visit method; (#136) [API]
    • Rewritted TSkAnimatedImage and TSkAnimatedPaintBox, adding features to have full control over the animation; (#104) [Framework]
      Some of them are: Start and Stop methods, and AutoReverse, CurrentTime, Delay, Duration, Enabled, Inverse, Loop, Pause, Progress, Running, Speed, StartFromCurrent, StartProgress and StopProgress properties. All these properties and methods are in the Animation property of the TSkAnimatedImage and TSkAnimatedPaintBox.
    • Improved automatic tests; [Tests]
    • Fixed issue in edit controls with emoji or Chinese char; (#159) [Render]
    • Fixed custom fonts on Android deployed to assets\internals that was not automatically loaded; (#153) [Render]
    • Fixed webinar demo splashscreen; [Samples]
    • Fixed exception loading images from stream or bytes; (#111) [Framework]
    • Fixed TSkAnimatedImage exceeding bounds in some WrapMode [Framework]
    • Fixed TBitmap.SkiaDraw issues in VCL; [Framework]
    • Fixed TBitmap.ToSkImage AV in VCL; [Framework]
    • Fixed flicker problem in TSkAnimatedImage in VCL; [Framework]
    • Fixed text print; (RSP-16301) [Render]
    • Fixed TSkAnimatedImage with 90° rotation that fails to play; [Framework]
    • Fixed high DPI issues of TSkLabel in VCL; [Framework]
    • Fixed high DPI issues in VCL demo; [Samples]
    • Fixed SkRegion.IsEqual; [API]
    • Fixed link with runtime packages; (#163) [Setup]
    • Fixed big GIF issue; (#118) [API]
    • Fixed wrong pixel format on Android in Delphi 10.3 Rio; [Render]
    • Minor improvements and fixes.

      Skia version: 107.0.0

     

    Compatibility break

    We are in continuous development, so some updates will bring compatibility breaks. So, pay attention to version numbers, we use semantic versions (for major versions there is some compatibility break). See some breaking changes in this version:

    • No longer use TSkAnimatedImage.Enabled to start or stop an animation. Now use TSkAnimatedImage.Animation.Enabled.
    • The class TSkTypefaceManager is deprecated in favor to TSkDefaultProviders;
    • Several changes in API (Skia.pas);

     

    Supported platforms

    • RAD Studio 11 Alexandria: All platforms
    • RAD Studio 10.3 Rio or newer: Windows and Android
    • RAD Studio XE7 or newer: Windows

     

    Github: github.com/skia4delphi/skia4delphi

    Website: skia4delphi.org

     

    • Like 12
    • Thanks 3

  11. 51 minutes ago, Linuxuser1234 said:

    @vfbb ok so i added that to my dbr project file so in my unit7 file how would i apply that font to TLabel2 

    You should use the font family name (which is not necessarily the same as the file name) in family property of controls. 

    One problem you will face is that this property in designtime only lists the fonts registered on your system, so you must install the font on your system (by double clicking on it), and reopen your IDE, so that you can select your font on the Family property.

     

    Note: only you will install the font on the system (to be able to select it inside the IDE), your clients will not need it.


  12. @Linuxuser1234 To be clearer, follow the steps:

    1. Install Skia4Delphi via GetIt or by downloading the installer from github.
    2. Enable the use of Skia in your project: right click on the project > "Enable Skia"
    3. Open your project's dpr to enable Skia as your app's renderer and to register the custom font you want:
    uses
      System.StartUpCopy,
      FMX.Forms,
      Skia, // <<
      Skia.FMX, // <<
      Unit1 in 'Unit1.pas' {Form1};
    
    {$R *.res}
    
    begin
      GlobalUseSkia := True; // <<
      TSkTypefaceManager.RegisterTypeface('C:\Boltgui\Popups\Font\DSEG14ClassicMini-Bold.ttf'); // <<
      Application.Initialize;
      ...

     


  13. You can try with refit unit https://github.com/viniciusfbb/ipub-refit

    The implementation could be something like this:

     

    unit MerchantApi;
    
    interface
    
    uses
      iPub.Rtl.Refit; // https://github.com/viniciusfbb/ipub-refit
    
    type
      TCountry = (MG);
      TCurrency = (MGA);
    
      TPaymentSubscriber = record
        Country: TCountry;
        Currency: TCurrency;
        Msisdn: Cardinal;
      end;
    
      TPaymentTransaction = record
        Amount: Integer;
        Country: TCountry;
        Currency: TCurrency;
        Id: string;
      end;
    
      TPaymentRequest = record
        Reference: string;
        Subscriber: TPaymentSubscriber;
        Transaction: TPaymentTransaction;
      end;
    
      [BaseUrl('https://API_server_host/merchant/v1')]
      IMerchantApi = interface(IipRestApi)
        ['{1D10C463-1567-4DE0-88F2-099CC0442E43}']
    
        [Post('/payments')]
        [Headers('Authorization', 'Bearer {AuthToken}')]
        [Headers('X-Country', '{XCountry}')]
        [Headers('X-Currency', '{XCurrency}')]
        function Payments(AXCountry: TCountry; AXCurrency: TCurrency; const ABody: TPaymentRequest): string;
    
        function GetAuthToken: string;
        procedure SetAuthToken(const AValue: string);
        property AuthToken: string read GetAuthToken write SetAuthToken;
      end;
    
    var
      FMerchantApi: IMerchantApi;
    
    implementation
    
    initialization
      FMerchantApi := GRestService.&For<IMerchantApi>;
    end.

     

    And your code could be this:

     

     

    uses
      MerchantApi;
    
    procedure TForm1.FormCreate(Sender: TObject);
    var
      LPaymentRequest: TPaymentRequest;
    begin
      LPaymentRequest.Reference := 'Testing API';
      LPaymentRequest.Subscriber.Country := TCountry.MG;
      LPaymentRequest.Subscriber.Currency := TCurrency.MGA;
      LPaymentRequest.Subscriber.Msisdn := 331170348;
      LPaymentRequest.Transaction.Amount := 1000;
      LPaymentRequest.Transaction.Country := TCountry.MG;
      LPaymentRequest.Transaction.Currency := TCurrency.MGA;
      LPaymentRequest.Transaction.Id := 'FE9833FE-D5A3-4450-9786-90735F75EBFB';
    
      FMerchantApi.AuthToken := 'koeQidreesddfzsbxOXKjccccccc';
      ShowMessage(FMerchantApi.Payments(TCountry.MG, TCurrency.MGA, LPaymentRequest));
    end;

     


  14. On 9/6/2022 at 2:43 PM, dkprojektai said:

    Can you share an example?

     

    Yes! See a very simple sample:
     

    uses
      System.Net.HttpClient, System.Net.Mime, Skia, Skia.FMX {or Skia.Vcl};
    
    function SendBitmap(const AUrl: string; ABitmap: TBitmap): string;
    var
      LRequest: THTTPClient;
      LFormData: TMultipartFormData;
      LResponse: TStringStream;
    begin
      LRequest := THTTPClient.Create;
      LFormData := TMultipartFormData.Create;
      LResponse := TStringStream.Create;
      try
        LFormData.AddBytes('img', ABitmap.ToSkImage.EncodeToStream(LImageStream, TSkEncodedImageFormat.WEBP, 80));
        LRequest.Post(AUrl, LFormData, LResponse);
        Result := LResponse.DataString;
      finally
        LFormData.Free;
        LResponse.Free;
        LRequest.Free;
      end;
    end;

     

    This is a simple example for you to understand how it works. In practice I use something different. On the client (API consumer), I declare the whole API in a single unit using the Refit library. This removes a lot of complexity throughout the project, as it already magically serializes records and classes, query parameters, headers automatically.

     

    The example above using Refit would look like this:

     

    This is the unit of your api for the client-side (consumer):

    unit MyApiConsumer;
    
    interface
    
    uses
      System.SysUtils, iPub.Rtl.Refit; // https://github.com/viniciusfbb/ipub-refit
    
    type
      [BaseUrl('http://localhost/api/v1')]
      IMyAPI = interface(IipRestApi)
        ['{1D10C463-1567-4DE0-88F2-099CC0442E43}']
    
        [Post('/image-upload')]
        [ContentType(TBodyKind.MultipartFormData)]
        function TryImageUpload(const [Body] AImg: TBytes; out AResponse: string): Boolean;
      end;
    
    var
      FMyApi: IMyAPI;
    
    implementation
    
    initialization
      FMyApi := GRestService.&For<IMyAPI>;
    end.

    And in your code:

    uses
      MyApiConsumer, Skia, Skia.FMX {or Skia.Vcl};
    
    function SendBitmap(ABitmap: TBitmap): string;
    begin
      if not FMyApi.TryImageUpload(ABitmap.ToSkImage.EncodeToStream(LImageStream, TSkEncodedImageFormat.WEBP, 80), Result) then
        Result := 'Failed!';
    end;

     


  15. Also Skia4Delphi (FMX & VCL). If it's just VCL, SVGIconImageList is the one that has better integration with Delphi controls because it has a TSVGIconImageCollection and TSVGIconVirtualImageList.

    • Like 1
    • Thanks 1

  16. I've never tried to print anything on Android, but on iOS, when sharing a PDF, the "Print" option appears in the system menu. If this happens on Android, it would be a very simple solution to implement. To make the PDF just use Skia4delphi, and to share the PDF, it's very simple, I even have a code ready (if you confirm that this solution works, I'll send it to you).

    • Like 1

  17. 31 minutes ago, Vincent Parrett said:

    I recently spent an entire week trying to fix a bug where in heavily threaded situations customers were seeing random av's. The av's and the stack traces were very random, which made it very difficult to pin down. Debugging threads in delphi is painful at best - any changes to timing can completely mask bugs so using breakpoints was not going to work (and the bug would occur in around 4 out of 40 identical threads).  After spending days adding even more (pointless as it turned out) locks all over the show I wasnt' much closer to figuring it out.

     

    I suspected it could be a reference counting issue (since I use interfaces a lot), so started sprinkling some FreeAndNils around the code (in destructors) - suddenly those random av's turned into nil pointer exceptions that were much less random. That confirmed to me that the issue was with accessing objects already free'd. The problem turned out to be that I was using weak references where I really needed strong references - a 70hr week of frustration turned into a 4 line change 🤦‍♂️

     

    That's why I made a topic warning that Weak is not thread safe (confirmed by @Dalija Prasnikar). So cast Weak to strong reference, and even if the strong reference is not nil, it can represent a destroyed object, generating a totally random AV, and this is not documented anywhere on the internet. More information: https://en.delphipraxis.net/topic/4020-weak-reference-is-dangerous/?tab=comments#comment-34379


  18. @3delite 

    Loading dynamic libraries on Android is not that trivial, you will still have problems on some devices of some manufacturers. Here are 3 main tips:

     

    1) Filename: ALWAYS suffix "lib", like "libbass.so"

     

    2) Deployment:

    • On 32bit, the remote path "library\lib\armeabi-v7a\"
    • On 64bit, the remote path "library\lib\arm64-v8a\"
    • Also on 64bit, add the 32bit binary with the remote path "library\lib\armeabi-v7a\" and the condition "'$(AndroidAppBundle)''==''true'" (with the quotes). The condition you can only change via ToolsApi or manually in .dproj.

    See how we do it: https://github.com/skia4delphi/skia4delphi/blob/eed4afbf8a34137a9bfa308bcb5ef87cee84abcb/Source/VCL/Designtime/Skia.Vcl.Designtime.ProjectMenu.pas#L219-L221

     

    3) Loading:
    First try to load using only the filename, and in case of failure use the library path + filename.
    See how we do it: https://github.com/skia4delphi/skia4delphi/blob/eed4afbf8a34137a9bfa308bcb5ef87cee84abcb/Source/Skia.API.pas#L2119-L2124

     

     

×