Jump to content

Clash with System.Drawing.Common


Go to solution Solved by Rick Brewster,

Recommended Posts

I added System.Drawing.Common as a dependency to my project so I could load PNG files. However, this causes loading my Paint.NET filetype plugin to crash with a System.ExecutionEngineException exception. (Net7-Windows) I suspect there's a clash between System.Drawing.Common for Net7 and System.Drawing for Net4.8.

 

What is the preferred way to load a PNG file in Net7? There seem to be several third party libraries, but a recommendation from the horses mouth would be a great place to start without following several dead ends.


Can the Paint.NET API be leveraged to do this simply?

Cheers

John 

 

 

Link to comment
Share on other sites

9 minutes ago, John J Scott said:

Can the Paint.NET API be leveraged to do this simply?

 

Already done.

 

What type of plugin are you writing, an Effect or a Filetype?

 

Where are you trying to load the PNG from, an embedded resource or a file on disk?

 

If an effect, are you writing a Classic effect or a GPU accelerated effect?

 

Link to comment
Share on other sites

You don't need to add System.Drawing.Common. Paint.NET already brings in the .NET runtime+framework, and the Windows Desktop frameworks. Just make sure you're referencing the WindowsDesktop package with these lines at the top of your .csproj

<PropertyGroup>
    <UseWPF>true</UseWPF>
    <ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
    <UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>

 

Also if you need to load PNGs, don't bother with System.Drawing. It's garbage.

 

Use IPngFileType instead https://paintdotnet.github.io/apidocs/api/PaintDotNet.IPngFileType.html . @null54 is using this in one of his plugins. It lets you use PDN's built-in PNG FileType, which does A LOT of things with regards to handling metadata and other weird things you don't want to get buried in figuring out.

 

You get IPngFileType through your Services property, e.g. this.Services.GetService<IPngFileType>()

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

Thanks all!

 

It's validating a filetype plugin for hardware compressed textures. 

In C++:

1. Load in PNG

2. Compress to BC1 (aka DXT1)

3. Save as DDS

4. Save in my custom format.

5. Load my custom format and make sure it's the same (including all mips)

6. Decompress DDS with DirectXTex and save as PNG

In C#:
1. Load DDS

2. Load my custom format in C# and make sure it's the same

3. Decompress custom format to BGRA as part of the filetype plugin

4. Compare my BGRA to the decompressed PNG to make sure they are the same. 

Similar process with ETC, but using KTX images not DDS. ASTC and PVRTC are on the radar, but that's about it.

 

All this is external to Paint.NET - I just use it as my viewer. As such, I don't have access to services for IPngFileType.

 

Even if I had a Document, I seem to need to set each pixel individually, which seems inefficient
 

                BitmapLayer layer = ( BitmapLayer )document.Layers[ 0 ];
                for( int32 x = 0; x < layer.Width; x++ )
                {
                    for( int32 y = 0; y < layer.Height; y++ )
                    {
                        reference_bgra[x + ( y * layer.Width)] = ( int32 )layer.Surface[x, y].Bgra;
                    }
                }


In the end, I opted for LoadFromWICFile:
 

        private static int32[] LoadPNGImage( string fullPNGPath )
        {
            ScratchImage scratch_image = TexHelper.Instance.LoadFromWICFile( fullPNGPath + ".png", WIC_FLAGS.NONE );
            Image image = scratch_image.GetImage( 0 );
            int32[] reference_bgra = new int32[image.Width * image.Height];
            Marshal.Copy( image.Pixels, reference_bgra, 0, image.Width * image.Height );

            return reference_bgra;
        }

 

I'm all ears for better approaches

 

Cheers

John

Link to comment
Share on other sites

The problem there is you're marshaling data through a managed array (int32[]). You can use something like NativeMemory to allocate unmanaged/unsafe memory and copy to/from directly using NativeMemory.Copy().

 

My preferred method would be:

1. Allocate your output buffer using NativeMemory.Alloc()

2. Wrap it in a class that holds the pointer and calls NativeMemory.Free() in its finalizer. I would just derive from SafeHandleZeroOrMinusOneIsInvalid, the runtime has special support for this class (for SafeHandles in general). This makes it substantially less likely you'll leak memory, and makes it very clear how to free the memory (a naked pointer has no allocator attached to it).

3. Use layer.Surface.AsRegionPtr() to obtain a RegionPtr<ColorBgra>, which is a low-level primitive kind of like Span<T> except for 2D bitmap-like regions of memory (pointer, width, height, stride).

4. Create a RegionPtr<ColorBgra> for your output buffer, being sure to pass the object from 2 in as the "owner"

5. Use CopyTo() to copy between the RegionPtr's

6. Return that wrapper class you created in step 2 (instead of the int32[])

 

Edit: See next comment. But, the general idea here is still the right one: don't manually copy pixel by pixel. Use a bulk-copy mechanism. And be sure to respect the stride of a bitmap.

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

  • Solution
8 hours ago, John J Scott said:

Can the Paint.NET API be leveraged to do this simply?

 

Since you said you're not using this inside of Paint.NET then the answer is no. You cannot use Paint.NET's DLLs outside of Paint.NET. You can only use them from a plugin inside of Paint.NET. Both practically and legally speaking.

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...