-
Content Count
266 -
Joined
-
Last visited
-
Days Won
30
Posts posted by vfbb
-
-
Open your Android manifest template, and inside the activity tag, put the line:
android:exported="true"
-
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:
- 2
- 1
-
FMX does not natively support RTL. However, it is possible to use third-party libraries that enable RTL in FMX. Skia4Delphi is one of them: https://github.com/skia4delphi/skia4delphi#right-to-left
- 1
-
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.
- 2
-
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).
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.
-
@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.
-
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;
- 2
- 1
-
47 minutes ago, Anders Melander said:How is that relevant?
He needs to draw paths in Winding mode but doesn't want to change the FMX source. This is one of the alternatives, but there are other possibilities.
- 1
-
@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:
The result after enable Skia in the project:
The project is attached.
-
@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. -
Hi David! What is the exact version you are using? It looks like 11.2, but here on 11.2 Enterprise it works fine. Does this occur on a blank project? Have you tried deleting the output folder of the project? (maybe there is conflict with old dcu)
-
- 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
- 2
-
- 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
- 12
- 3
-
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.
-
@Linuxuser1234 To be clearer, follow the steps:
- Install Skia4Delphi via GetIt or by downloading the installer from github.
- Enable the use of Skia in your project: right click on the project > "Enable Skia"
- 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; ...
-
Another option that works in XE7+ and cross-platform is use the Skia4delphi as your app render. Then you only need to add the follow code in the app initialization:
initialization
TSkTypefaceManager.RegisterTypeface('Material Design Icons Desktop.ttf');- 1
-
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;
-
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;
-
Don't use json. I usually send via MultipartFormData, encoded in WebP with 80% quality, as it is practically identical to the original. See attached the original png image of 2292 KB and the WebP with 80% quality resulting in 61 KB.
- 1
-
svg
in Windows API
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.
- 1
- 1
-
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).
- 1
-
19 minutes ago, John van de Waeter said:I installed skia4delphi a couple of months ago, (not via GetIt) and I'm not sure if it's the latest version.
Where can I see the installed version number?
Skia.pas has a version: https://github.com/skia4delphi/skia4delphi/blob/d6feb7784c90623cef5b8948b12a5239eea2e4a0/Source/Skia.pas#L36
The latest version is 3.4.0. We will release a major version in few weeks.
- 1
-
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
-
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
Upload Google Play android FMX app problem
in FMX
Posted · Edited by vfbb
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.