Jump to content

Anders Melander

Members
  • Content Count

    2375
  • Joined

  • Last visited

  • Days Won

    121

Anders Melander last won the day on May 28

Anders Melander had the most liked content!

Community Reputation

1691 Excellent

Technical Information

  • Delphi-Version
    Delphi 11 Alexandria

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Anders Melander

    Loading and Saving PNG into TBitmap changes the image

    It does complicate things but yes, as you suggested, you could have a structure that contains both an TStream (for persistence) and a TBitmap (for display). The TBitmap would be created and loaded from the TStream once, on-demand, when the image needs to be displayed. This is also the technique used internally by many VCL image containers (e.g. TGIFImage, TPNGImage, TJPEGImage). That at least would mean you only "wasted" memory on the bitmaps that were actually displayed. Not really. The data in the stream is compressed and probably much smaller than the decompressed image data.
  2. Anders Melander

    Loading and Saving PNG into TBitmap changes the image

    I don't use FMX and I haven't looked at the source but as far as I can tell, from your the images and description, the problem is that TBitmap premultiplies on load and unpremultiplies on save. The degradation of pixels with alpha<>255 is caused by the inevitable rounding errors. The VCL TBitmap has the same problem if one messes with the AlphaFormat property. Apparently they didn't learn from their first mistake and instead decided to make it worse. The reason the FMX TBitmap premultiplies the bitmap is probably because it needs that when displaying the bitmap (e.g. when using the Win32 AlphaBlend function). Anyway, the solution to your problem is to not use TBitmap as a storage container. Use TBitmap only for display of the image and use instead use TMemoryStream or something like it for storage.
  3. Anders Melander

    Loading and Saving PNG into TBitmap changes the image

    Please also post the image as it is after you have saved it. My guess is that the load+save premultiplies the RGB with the alpha.
  4. Anders Melander

    Loading and Saving PNG into TBitmap changes the image

    OP is using FMX. You are using VCL...
  5. Anders Melander

    ANN: Better Translation Manager released

    Specify the project Source language. Specify the current Target language. Enter the translations in the grid. I don't know what you mean by "how to use the source". The xlat file is BTM's translation project file; It contain the source texts and the translated texts for all selected target languages of the application being localized. BTM uses the information in this file to build the language modules (which are in fact just code-less DLLs containing the translated resourcestring and DFM resources) that are loaded at run-time by your application. See the Delphi help for info about how the Delphi localization system works (I believe I have some info at the project page too). See: Getting started
  6. Anders Melander

    ANN: Better Translation Manager released

    Not really but it's a very reasonable feature request. Please create an issue for it. I assume you mean a filter on the module list because you can hide already translated entries by filtering on State=Pending in the property list. If so, please create an issue for this too.
  7. Anders Melander

    ANN: Better Translation Manager released

    Your question doesn't make sense. Please rephrase it. You message, before you edited it, said "No HEBREW to translate". If you are asking how to add an additional target language, then that is done by clicking on the little settings button on the Language bar (yes, it's a bad UI, I know): ...and then selecting the desired target languages:
  8. Anders Melander

    ANN: Better Translation Manager released

    The RTLs DFM and resourcestring load mechanisms are separate and, for the most part, completely different. The RTL's resourcestring handling changed in a recent version of Delphi and, assuming your dynamic resource DLL loader doesn't take this into account, I suspect that this is the cause of your problem. The problem is likely that the RTL is caching both the resolved resourcestrings and the resource module, so once a resource module has been loaded and a resourcestring has been resolved it will not be read from the resource module again. My guess is that since your dynamic resource module loader probably executes after the RTL has already loaded the default resource module, your module is ignored. If you place a breakpoint in System.pas LoadResString and run your application you will be able to see the sausages being made. You should end up in DelayLoadResourceModule (via FindResourceHInstance) where the decision is made to reuse an already loaded resource module if there is one or load one if there isn't (FWIW, the DFM loader also goes through this function). Once system.pas has done its thing, sysutils.pas replaces the default resourcestring loader with a caching string loader, so all resourcestrings resolved after that point will be cached. If all my guessed are correct, the solution will be to modify the resource entry of the main module record (maybe your solution already does this). Something like this: var Module: PLibModule := LibModuleList; while (Module <> nil) do begin if (Module.Instance = hInstance) then begin Module.ResInstance := TheModuleHandleOfYourResourceModule; break; end; Module := Module.Next; end; Note that this will not change the already cached resourcestrings. In order to do that you will need to call SysUtils.ResStringCleanupCache If the above doesn't solve the problem for you I will need you to: Create an issue at the bug tracker Attach a minimal reproducible example and I'll see if I can find a solution.
  9. Anders Melander

    Where/how to remove an IDE Plugin?

    A bit more specifics would have been helpful. E.g. a link to the repository, how did you "install" it, etc. Anyway, if it's actually an IDE plugin it's listed in (for Delphi 12): HKEY_CURRENT_USER\SOFTWARE\Embarcadero\BDS\23.0\Known IDE Packages If it's a component package it's listed in: HKEY_CURRENT_USER\SOFTWARE\Embarcadero\BDS\23.0\Known Packages You can just delete it from there. Save a copy of the registry tree (right click the parent node, select export) if you are unsure of what you're doing.
  10. Anders Melander

    how to filter on source files using VTune?

    Well, if you are looking at the bottom-up view then you will get the result ordered by the call tree leaf nodes. As I understand it, you want to trim the tree to remove the low level entries. I think the closest thing to what you're after is to simply use the top-down view instead and drill down to the desired detail level.
  11. Anders Melander

    Tool to sort units used in project by dependency

    Sorted by dependency Sorted by "some other criteria" Pick one
  12. Anders Melander

    how to filter on source files using VTune?

    Assuming you're using map2pdb to generate the PDB-file for VTune, you can specify on the map2pdb command line which units to include and which to exclude. For example, I often use these filters (excludes DevExpress, the VCL, Indy, etc.): -include:0001 -exclude:dx*;cx*;winapi.*;vcl.*;data.*;firedac.*;soap.*;web.*;datasnap.*;id*;vcltee.* However, that will not prevent VTune from profiling that code. It just can't resolve the addresses in those units. As far as I know, the only way to filter data in VTune is to either use the filter fields at the bottom of the Window or to select the lines you'd like to exclude/include, right click and then select Filter In by Selection/Filter Out by Selection from the context menu. https://www.intel.com/content/www/us/en/docs/vtune-profiler/user-guide/2024-2/context-menu-grid.html
  13. Anders Melander

    How to debug a Not Responding program element

    Possible but unlikely. I can compile SuperLemmix but I can't run it since I'm missing all the external assets. So instead I went back and looked at the original FastMM leak report. TGadgetMetaAccessor is owned and destroyed by TGadgetMetaInfo. TGadgetMetaInfo is created in 3 different places; Two of them are inside TGadgetMetaInfoList (a TObjectList) and those appear to be fine. The last is in TNeoPieceManager where we have a case of exception swallowing that will lead to a leak: function TNeoPieceManager.ObtainObject(Identifier: String): Integer; var ObjectLabel: TLabelRecord; MO: TGadgetMetaInfo; begin try ObjectLabel := SplitIdentifier(Identifier); Result := fObjects.Count; MO := TGadgetMetaInfo.Create; MO.Load(ObjectLabel.GS, ObjectLabel.Piece, fTheme); // Leak if exception here fObjects.Add(MO); except Result := -1; end; end; So there's (unsurprisingly) problems with exception handling. With that in mind I searched for "except" and reviewed all the cases of explicit exception handling. Many are misguided but harmless but there are a few serious problems. For example in TBaseAnimationSet.LoadMetaData there's a double-free in case of exception: procedure TBaseAnimationSet.LoadMetaData(aColorDict: TColorDict; aShadeDict: TShadeDict); begin Parser := TParser.Create; try [...] try [...] except Parser.Free; raise EParserError.Create('TBaseAnimationSet: Error loading lemming animation metadata for ' + ANIM_NAMES[i] + '.') end; [...] finally Parser.Free; end; end; In TNeoLevelEntry.LoadLevelFileData there's a leak on exception: procedure TNeoLevelEntry.LoadLevelFileData(aExtent: TNeoLevelLoadState); [...] try TalInfoLevel.LoadFromFile(Path); for i := 0 to TalInfoLevel.Talismans.Count-1 do begin CloneTal := TTalisman.Create; CloneTal.Clone(TalInfoLevel.Talismans[i]); // Leak if exception here fTalismans.Add(CloneTal); end; except // Fail silently. end; [...] TNeoLevelGroup.CleanseLevels is a complete mess and can leak a TStringList on exception. TNeoLevelGroup.LoadUserData will leak a TParser on exception.
  14. Anders Melander

    How to debug a Not Responding program element

    TList<T>.Clear is declared inline and inlined functions will not appear in the call stack. If you compile with inlining disabled it will appear. It can't (unless you disable inlining), but in this case we weren't really interested in where Clear was being called from but rather where/when the object was being destroyed. So, as expected, there's more than one problem. Look at here the Access Violation occurs, examine the call stack, rinse, repeat. The absence of errors without madExcept does not mean that aren't any errors. You just can't see them...
  15. Anders Melander

    How to debug a Not Responding program element

    Oh, I see... So TGadgetAnimations is in fact declared as derived from TObjectList<TGadgetAnimation>. This means that you can catch the destruction of a TGadgetAnimation by overriding the TObjectList<T>.Notify method: type TGadgetAnimations = class(TObjectList<TGadgetAnimation>) [...] protected procedure Notify(const Value: TGadgetAnimation; Action: TCollectionNotification); override; [...] end; procedure TGadgetAnimations.Notify(const Value: TGadgetAnimation; Action: TCollectionNotification); begin if (Action in [cnExtracting, cnDeleting]) and (Value = fPrimaryAnimation) then fPrimaryAnimation := nil; inherited; end; The call to Clear destroys all the objects contained in the list. The call stack shows you exactly how you got from TGadgetAnimations.Clear to TGadgetAnimation.Destroy.
×