Jump to content

Copying to clipboard with plugin


MJW

Recommended Posts

bool firstRun = true;

void Render(Surface dst, Surface src, Rectangle rect)
{
    if (firstRun)
    {
        SetClipboardImage(src.CreateAliasedBitmap());
        firstRun = false;
    }
    
    ColorBgra CurrentPixel;
    for (int y = rect.Top; y < rect.Bottom; y++)
    {
        if (IsCancelRequested) return;
        for (int x = rect.Left; x < rect.Right; x++)
        {
            CurrentPixel = src[x,y];
            dst[x,y] = CurrentPixel;
        }
    }
}

void SetClipboardImage(Bitmap bitmap)
{
  try
  {
    // Accessing the clipboard requires STA apartment state.	
    System.Threading.Thread t = new System.Threading.Thread(() => Clipboard.SetData(DataFormats.Bitmap, bitmap));
    t.SetApartmentState(System.Threading.ApartmentState.STA);
    t.Start();
    t.Join();
  }
  catch
  {
  }
}

Note that this method will not preserve transparency.

  • Like 1

PdnSig.png

Plugin Pack | PSFilterPdn | Content Aware Fill | G'MICPaint Shop Pro Filetype | RAW Filetype | WebP Filetype

The small increase in performance you get coding in C++ over C# is hardly enough to offset the headache of coding in the C++ language. ~BoltBait

 

Link to comment
Share on other sites

Don't forget error handling.

 

If you don't have some kind of try/catch around your clipboard calls, you WILL cause a crash. The clipboard is a cantankerous old jerk.

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

Though for the particular use I have in mind, preserving transparency isn't necessary, I do have a couple of questions in that regard:

1) Is it possible to preserve transparency?

2) (Mostly out of curiosity) What is it about the given code that prevents it from preserving transparency?

Link to comment
Share on other sites

I have another question which is more pertinent. Suppose I want to save the destination image in the clipboard -- which, in fact, I do. The obvious solution is to do all the rendering in OnSetRenderInfo, then copy it to the clipboard when finished. Is there any way to let the normal render loops run, then when they're complete with the entire image, have some routine copy the result to the clipboard. I don't know of a way to recognize that the complete image has been successfully rendered, and I think I'd know it there were, but hope springs eternal.

Link to comment
Share on other sites

17 minutes ago, MJW said:

Is there any way to let the normal render loops run, then when they're complete with the entire image, have some routine copy the result to the clipboard.

 

I haven't tested this, but I think it should work.

protected override void OnRender(Rectangle[] renderRects, int startIndex, int length)
{
    if (length == 0) return;
    for (int i = startIndex; i < startIndex + length; ++i)
    {
        Render(DstArgs.Surface, SrcArgs.Surface, renderRects[i]);
    }

    SetClipboardImage(DstArgs.Bitmap);
}

 

Edited by toe_head2001

(September 25th, 2023)  Sorry about any broken images in my posts. I am aware of the issue.

bp-sig.png
My Gallery  |  My Plugin Pack

Layman's Guide to CodeLab

Link to comment
Share on other sites

Let me explain more what I have in mind, just to make sure Rick Brewster considers it kosher. I don't want to create a plugin that can't be distributed.

 

What I intend to do is write a plugin that takes the selected image, transforms it into an image of a different size, and places that image in the clipboard. Then the user would use Paste into New Image to create the transformed image. The original image would be unchanged.

Link to comment
Share on other sites

11 minutes ago, toe_head2001 said:

 

I haven't tested this, but I think it should work.

. . .

 

At the risk of showing how little I know about PDN's multithreading, I was under the impression that the OnRender routine was run separately on multiple threads, so that the completion of the loop could occur multiple times for a frame.

Link to comment
Share on other sites

2 minutes ago, MJW said:

I always thought that the OnRender routine was run separately on multiple threads, so that the completion of the loop could occur multiple times for a frame.

oh, yeah... I guess you'd have to use EffectFlags.SingleThreaded. Slower, but should work.

(September 25th, 2023)  Sorry about any broken images in my posts. I am aware of the issue.

bp-sig.png
My Gallery  |  My Plugin Pack

Layman's Guide to CodeLab

Link to comment
Share on other sites

I hadn't considered using SingleThreaded (which I tend to forget about). Is the advantage of running single threaded over doing the computations in OnSetRenderInfo, that the progress indicator will be updated correctly? I have no idea how that works. What updates the progress bar, anyway? How do it know?

 

EDIT: I think that before doing the final operation, IsCancelRequeted should be checked to make sure the operation wasn't aborted.

Link to comment
Share on other sites

You can't use the clipboard in OnRender. You can only use the clipboard from an STA thread, which includes the UI thread. This is a limitation of Windows.

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

47 minutes ago, MJW said:

I hadn't considered using SingleThreaded (which I tend to forget about). Is the advantage of running single threaded over doing the computations in OnSetRenderInfo, that the progress indicator will be updated correctly?

 

Even if you set the SingleThreaded flag your Render method will be called multiple times.

 

On 6/9/2006 at 5:09 PM, Rick Brewster said:

There is no way to get your Render method to be called only once. That would completely break progress reporting, the ability for the user to cancel, and multithreading performance benefits (assuming you are not using EffectDirectives.SingleThreaded).

PdnSig.png

Plugin Pack | PSFilterPdn | Content Aware Fill | G'MICPaint Shop Pro Filetype | RAW Filetype | WebP Filetype

The small increase in performance you get coding in C++ over C# is hardly enough to offset the headache of coding in the C++ language. ~BoltBait

 

Link to comment
Share on other sites

6 minutes ago, Rick Brewster said:

You can't use the clipboard in OnRender. You can only use the clipboard from an STA thread, which includes the UI thread. This is a limitation of Windows.

 

I thought the trick is that instead of directly calling the clipboard routine, the OnRender thread starts a STA thread that does the actual clipboard calls, then waits for it to complete. I think that's what toe_head2001 had in mind..

Link to comment
Share on other sites

15 minutes ago, null54 said:

Even if you set the SingleThreaded flag your Render method will be called multiple times.

 

I know that, but wasn't considering calling the clipboard routines from the Render routine. My comment referred to toe_head2001's example where it's called at the end of OnRender.

Link to comment
Share on other sites

46 minutes ago, Rick Brewster said:

You can't use the clipboard in OnRender. You can only use the clipboard from an STA thread, which includes the UI thread. This is a limitation of Windows.

 

I know this is a naive question, but is OnSetRenderInfo part of the UI thread?

Link to comment
Share on other sites

4 hours ago, MJW said:

I know this is a naive question, but is OnSetRenderInfo part of the UI thread?

 

No, it is not.

 

Rick is stating that the UI thread is one of the threads that uses STA mode and that any clipboard access must be performed from a STA thread.

 

In the example I posted the SetClipboardImage method creates a new STA thread when it accesses the clipboard.

The following line configures the thread to use STA mode.

t.SetApartmentState(System.Threading.ApartmentState.STA);

PdnSig.png

Plugin Pack | PSFilterPdn | Content Aware Fill | G'MICPaint Shop Pro Filetype | RAW Filetype | WebP Filetype

The small increase in performance you get coding in C++ over C# is hardly enough to offset the headache of coding in the C++ language. ~BoltBait

 

Link to comment
Share on other sites

  • 4 years later...

I was asked in a private message about how to write to the clipboard with the new PDN methods. I thought I'd copy my reply here.

 

---------------------------------------------

I haven't yet tried to write an image to the clipboard. However, I have successfully written text to the clipboard using the new PDN routines. Here is the code I wrote to call the PDN routines.

 

        public bool SetClipboardText(string s)
        {
            try
            {
                Services.GetService<IClipboardService>().SetText(s);
                return true;
            }
            catch
            {
                return false;
            }
        }

 

I disassembled the PDN clipboard code with ILSpy, to find out how to write an image. I believe the following should work:

 

        public bool SetClipboardImage(Image i)
        {
            try
            {
                Services.GetService<IClipboardService>().SetImage(i);
                return true;
            }
            catch
            {
                return false;
            }
        }

 

There are also overloads of SetImage() to handle Bitmaps and PDN Surfaces.

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