angusj
-
Content Count
132 -
Joined
-
Last visited
-
Days Won
8
Posts posted by angusj
-
-
On 1/28/2023 at 7:22 AM, David Heffernan said:I guess the only real complication I can see here is the PNG format for 256px images.
You can tell by reading the first 4 bytes of the image.
It's $474E5089 when PNG, $00100000 when ICO and $00200000 when CUR.
Unfortunately the TIcon component doesn't do this (at least in Delphi 10.4 upd 2).
The other tricky part is that 256px PNG ico images that aren't transparent frequently use a palette.
This tripped me up recently until I realised, but TPngImage loads paletted PNG images just fine.
-
1 minute ago, Lars Fosdal said:Are there any special attributes on the files not listed?
No. (That was the very first thing I checked.)
-
I recently received an email informing me that not all files were appearing in a FileOpen dialog in one of my applications**.
And this dialog had absolutely no filtering applied (at least when selecting *.* 😜).
The folder given as an example was:
C:\Windows\System32\fr-FR
And I too wasn't seeing all the files in this folder.
Using Delphi 10.4 Update 2 ...
I first tried a completely new VCL application with just a TOpenDialog control (without success).
I then tried a bare bones console application that's a Delphi translation of this C++ code:
https://learn.microsoft.com/en-us/windows/win32/learnwin32/example--the-open-dialog-box
program Project2; {$APPTYPE CONSOLE} {$R *.res} uses Windows, SysUtils, ActiveX, ShlObj; var hr: HRESULT; fileOpen: IFileOpenDialog; item: IShellItem; path: LPWSTR; begin hr := CoInitializeEx(nil, COINIT_APARTMENTTHREADED or COINIT_DISABLE_OLE1DDE); if (SUCCEEDED(hr)) then begin // Create the FileOpenDialog object. hr := CoCreateInstance(CLSID_FileOpenDialog, nil, CLSCTX_ALL, IID_IFileOpenDialog, fileOpen); if (SUCCEEDED(hr)) then begin // Show the Open dialog box. hr := fileOpen.Show(0); // Get the file name from the dialog box. if (SUCCEEDED(hr)) then begin hr := fileOpen.GetResult(item); if (SUCCEEDED(hr)) then begin hr := item.GetDisplayName(SIGDN_FILESYSPATH, path); // Display the file name to the user. if (SUCCEEDED(hr)) then begin MessageBoxW(0, path, 'the path', MB_OK); CoTaskMemFree(path); end; //item._Release; end; end; //fileOpen._Release; end; CoUninitialize(); end; end.
And this problem persists with only about half the files in the folder (mentioned above) being displayed.
However, when I compile the C++ code from the link above in MSVC, the console app. does show all the files (as expected).
Any suggestions?
-
1 hour ago, Lajos Juhász said:I would disagree here, my test bmp was 2.55MB in jpeg it's 277Kb.
Thanks Lajos for the correction. Your are right 😁 and I was wrong 😱.
-
Bernie, it seems that you're trying to maintain 100% quality which defeats the purpose of the JPEG format, since you'll get virtually no compression.
If you really don't want to sacrifice image quality, then you need to think of another image format, eg PNG or even QOI 😁, or just ZIP compress/decompress your BMP files.
-
Clement, there are a number of Delphi graphics libraries that will do what you want, so my answer would depend on the graphics library you're currently using. (IOW, it generally easiest to stick with what your familiar unless there's a good reason to change.)
Edit: What you're generally looking for are image resampling algorithms, of which there are many. But, as almost always, there must be compromises between speed and image quality. And when you're down-sampling (ie making images smaller), then for quality I'd strongly recommend a down-sampling algorithm over a general image resampler.
Bon Noël 🎄
- 1
-
Deleted post to avoid showing my ignorance .
(I confused static linking with static binding.)
- 1
-
11 hours ago, David Heffernan said:Yes it's exceptionally hard. Just put the code in a DLL.
I think David meant it's NOT exceptionally hard. However, you can't export C++ classes in your DLL. You must use simple structures (records) as parameters in your exported functions, ie structures that can be understood by other languages. The other thing to watch our for is memory management because structures created by DLL functions (ie heap allocoated memory) can't be freed using Delphi's memory manager.Here is an example in my Polygon Clipping library and the C++ export header.Edit: And of course Delphi routinely links to numerous operating system DLLs that would have been written in C and C++.Edit2: I haven't properly researched this but it looks like Delphi's FreeMemory function bypasses Delphi's memory manager and frees heap memory directly. So FreeMemory could probably be used to free structures created by (C++) DLLs. Nevertheless, IMHO, all DLLs that create heap allocated structures - ie any structure returned as a pointer - should also export functions to destroy these structures.Edit: The OP was asking about static linked libraries, and my reply was about dynamic libraries. Sorry.
- 1
-
-
Yes, the problem is/was that you were trying to load the same font twice ...
FontManager.Load('Arial')
and this was failing.
Strictly speaking this wasn't a bug but logically it makes sense to return the first loaded font when a fontname is supplied multiple times.
And I've just updated the GitHub repository to address this.
https://github.com/AngusJohnson/Image32
Thanks again for the feedback.
ps: It's better to raise issues with Image32 here:
https://github.com/AngusJohnson/Image32/issues OR
https://github.com/AngusJohnson/Image32/discussions
-
I'm not sure why you're having problems.
I've attached a very simple test that shows text drawing on 2 TImage32Panel controls.
procedure TForm1.FormCreate(Sender: TObject); begin fc := TFontCache.Create(FontManager.Load('Arial'), dpiAware(20)); end; procedure TForm1.FormDestroy(Sender: TObject); begin fc.Free; end; procedure TForm1.FormResize(Sender: TObject); begin with Image32Panel1 do begin Width := self.ClientWidth div 2; //Align = alLeft image.SetSize(InnerClientRect.Width,InnerClientRect.Height); DrawLine(image, Rectangle(0,0,image.Width, image.Height), 10, clRed32, esPolygon); DrawText(Image, Image.Bounds, 'This is Panel1', taCenter, tvaMiddle, fc); end; with Image32Panel2 do begin //Align = alClient image.SetSize(InnerClientRect.Width,InnerClientRect.Height); DrawLine(image, Rectangle(0,0,image.Width, image.Height), 10, clRed32, esPolygon); DrawText(Image, Image.Bounds, 'This is Panel2', taCenter, tvaMiddle, fc); end; end;
-
9 hours ago, Attila Kovacs said:It's a really cool topic, especially the conversation between DH and KW
Thanks. Interesting.
DH implied questioning re needing just a computer name would be something I'd be concerned about too, so KW's reply was reassuring there.
Nevertheless I was sad to see the flaming which to me was not cool.
-
If I understand this thread correctly, Embarcardero / Idera are insisting on an active subscription to validate a reinstallation of a time unlimited licensed product. If this is happening then I agree that it's unconscionable and the matter should be escalated to more senior staff. This sort of problem reinforces my perception that Delphi is fast approaching end of life.
- 1
-
6 minutes ago, Anders Melander said:Um... Unicode, 64 bit, generics, anonymous methods, inlining, record methods....?
I was referring to the Clipper2 library. And Inlining is there for compilers that support it.
Can these other things significantly improve the library's performance?
-
1 hour ago, Anders Melander said:I get it that there are people who are stuck on Delphi 7 and refuse to upgrade but do those people really need your library?
Well surprisingly they do.
And honestly I haven't encountered any newer language features (eg simpler code, better performance) that compel me to ditch support for these very old compilers.
1 hour ago, Anders Melander said:I'd be interested in seeing how the performance compares against C++ and C# at this point. Can you post the updated numbers, please?
-
Thanks again Stephan & Anders.
Unfortunately, the POINTERMATH directive was only introduced with D2009, and I'm still targetting the library back to D7.
So this is where I'm currently at ...
nodeQ: PIntersectNode; nodeI, nodeJ: ^PIntersectNode; op1, op2: POutpt; begin FIntersectList.Sort(IntersectListSort); for i := 0 to FIntersectList.Count - 1 do begin nodeI := @FIntersectList.List[i]; if not EdgesAdjacentInAEL(nodeI^) then begin nodeJ := nodeI; repeat inc(nodeJ); until EdgesAdjacentInAEL(nodeJ^); // now swap intersection order nodeQ := nodeI^; nodeI^ := nodeJ^; nodeJ^ := nodeQ; end;
-
23 minutes ago, Anders Melander said:I just tried using a pointer instead of the list getter inside the loop in ProcessIntersectList and that seems pay off:
Sure did!
-
17 minutes ago, Stefan Glienke said:FWIW I see more improvement after my changes - but that can have various reasons.
I've only tested using 64bit compiles so far (intersecting up to 6000 edges), but I couldn't detect measurable differences between compiles (cleaned and release builds), and just the Chrome browser and Windows Explorer visibly running. Nevertheless, it certainly won't be slower so it's now ready to be committed and uploaded.
17 minutes ago, Stefan Glienke said:What we can clearly see from the results though is that your code has O(n²) - that is where you might want to invest some time into
I thought it's closer to O(n³) but yeah, I'd love to fix that but I haven't been clever enough to figure out how.
-
I've just added in Stefan's changes and, while it's certainly better code, it's made very little difference to performance.
(Unlike avoiding TList.Get which made a very big difference.)
-
Thanks Stepan!
-
4 hours ago, David Heffernan said:I simply don't use the RTL collections anywhere in my code and use my own implementation so I have full control of that.
Yes, sometimes the metaphorical "wheel" isn't very round and while handcrafting one (not so much reinventing it) is time consuming, it will often perform much better.
Edit: I've also avoided many of Delphi's newer language features because I'm targeting the library at a wider user base. (It's my impression that many Delphi die-hards are no longer spending their money upgrading, especially when any improvements are arguably marginal at best. I can't remember seeing any language features since Delphi 7 that are really game changing (apart from Unicode support, and 64bit compiling - so perhaps I'm exagerating slightly), but I expect the compiler has made at least incremental gains since then.) And looking at the TListEnumerator class just now, I'm pretty sure it'd also be less efficient than my UnsafeGet function above since it compares Index with Count for every increment.
-
7 minutes ago, Anders Melander said:one thing I noticed is that you're iterating a list sequentially in ProcessIntersectList. Since TList is basically just a wrapper around a contiguous array, a sequential iteration can be done by just incrementing a pointer inside the loop thus bypassing the getter altogether.
Yes, of course, that'd be better still, and I've done that in lots of places too.
Perhaps I'm getting infected with C# and now and again I'm forgetting to use pointers 😜.
But I will indeed swap over to pointers in due course, but even with just bypassing TList.Get the performance gains I got really surprised me.
15 minutes ago, Anders Melander said:I will try to find time to look at this more closely this week end.
Great. And thanks.
-
Anders said in another thread ...
8 hours ago, Anders Melander said:Hi Anders.
Thanks for the feedback, much appreciated.
Yes, I have profiled my Clipper library's Delphi code (and not infrequently), but until now I haven't profiled into Delphi's Runtime Library.
And I see your point re TList.Get, if you're alluding to its relatively expensive range checking?
However, I can't see an easy hack (eg by overriding Get, since it isn't virtual).
But I could write a wrapper Get function (using TList's public List property) and bypass the default TList.items property altogether.
Is this what you're suggesting, or would you suggest I do something else?
And are you also seeing other "low hanging fruit" that would improve performance?
Edit:
I've replaced all implicit calls to TList.Get with the following function and as a consequence have seen quite a substantial improvement in performance (and Delphi now slightly out-performs C#).
function UnsafeGet(List: TList; Index: Integer): Pointer; inline; begin // caution: no bounds checking Result := List.List[Index]; end;
- 1
-
I particularly like your Iucundae_21_B. Wonderful colours.
FileOpen dialog not showing all files
in General Help
Posted · Edited by angusj
Well done finding that.
But I still don't understand why the different compilers show different folder content when it's virtually the same code.
Edit: Arh, it's the application's 32bit vs 64bit (not the OS). Sorry, a bit slow tonight.