Jump to content

angusj

Members
  • Content Count

    132
  • Joined

  • Last visited

  • Days Won

    8

Posts posted by angusj


  1. 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.

     


  2. 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?

     

     

    **Resource Hacker


  3. 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.


  4. 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 🎄

    • Like 1

  5. 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.

    • Like 1

  6. 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

     


  7. I'm not sure why you're having problems.

    I've attached a very simple test that shows text drawing on 2 TImage32Panel controls.

     

    image32.thumb.png.299bce756e87770b5777a2629f89c692.png

     

    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;

     

    img32_test.zip


  8. 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.


  9. 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.

    • Like 1

  10. 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?


  11. 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?

     

    Performance2.pdf


  12. 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;

     


  13. 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.


  14. 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.


  15. 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.


  16. Anders said in another thread ...

    8 hours ago, Anders Melander said:

    O.T. but have you tried profiling your Delphi code? I just did and there appears to be quite a few low hanging fruits that could improve the performance.

    image.png.f7118335206007825c9bcdabada590e9.png

    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;

     

     

     

    • Like 1
×