csharp/0xC0000054/pdn-gmic/src/GmicEffect.cs

GmicEffect.cs
/*
*  This file is part of pdn-gmic, an Effect plug-in that
*  integrates G'MIC-Qt into Paint.NET.
*
*  Copyright (C) 2018, 2019, 2020, 2021 Nicholas Hayes
*
*  pdn-gmic is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  pdn-gmic is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program.  If not, see .
*
*/

using GmicEffectPlugin.Properties;
using PaintDotNet;
using PaintDotNet.AppModel;
using PaintDotNet.Clipboard;
using PaintDotNet.Effects;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Windows.Forms;

namespace GmicEffectPlugin
{
    [PluginSupportInfo(typeof(PluginSupportInfo))]
    public sealed clast GmicEffect : Effect
    {
        private bool repeatEffect;

        internal static string StaticName
        {
            get
            {
                return "G'MIC-Qt";
            }
        }

        internal static Bitmap StaticImage
        {
            get
            {
                return new Bitmap(typeof(GmicEffect), PluginIconUtil.GetIconResourceNameForDpi(UIScaleFactor.Current.Dpi));
            }
        }

        public GmicEffect() : base(StaticName, StaticImage, "Advanced", new EffectOptions { Flags = EffectFlags.Configurable })
        {
            repeatEffect = true;
        }

        public override EffectConfigDialog CreateConfigDialog()
        {
            repeatEffect = false;

            return new GmicConfigDialog();
        }

        private void ShowErrorMessage(Exception exception)
        {
            Services.GetService().ShowErrorDialog(null, exception.Message, exception);
        }

        private void ShowErrorMessage(string message)
        {
            Services.GetService().ShowErrorDialog(null, message, string.Empty);
        }

        protected override void OnSetRenderInfo(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs)
        {
            if (repeatEffect)
            {
                GmicConfigToken token = (GmicConfigToken)parameters;

                if (token.Surface != null)
                {
                    token.Surface.Dispose();
                    token.Surface = null;
                }

                if (File.Exists(GmicConfigDialog.GmicPath))
                {
                    try
                    {
                        using (GmicPipeServer server = new GmicPipeServer())
                        {
                            List layers = new List();

                            Surface clipboardSurface = null;
                            try
                            {
                                // Some G'MIC filters require the image to have more than one layer.
                                // Because use Paint.NET does not currently support Effect plug-ins accessing
                                // other layers in the docameent, allowing the user to place the second layer on
                                // the clipboard is supported as a workaround.

                                clipboardSurface = Services.GetService().TryGetSurface();

                                if (clipboardSurface != null)
                                {
                                    layers.Add(new GmicLayer(clipboardSurface, true));
                                    clipboardSurface = null;
                                }
                            }
                            finally
                            {
                                if (clipboardSurface != null)
                                {
                                    clipboardSurface.Dispose();
                                }
                            }

                            layers.Add(new GmicLayer(EnvironmentParameters.SourceSurface, false));

                            server.AddLayers(layers);

                            server.Start();

                            string arguments = string.Format(CultureInfo.InvariantCulture, ".PDN {0} reapply", server.FullPipeName);

                            using (Process process = new Process())
                            {
                                process.StartInfo = new ProcessStartInfo(GmicConfigDialog.GmicPath, arguments);

                                process.Start();
                                process.WaitForExit();

                                if (process.ExitCode == GmicExitCode.Ok)
                                {
                                    OutputImageState state = server.OutputImageState;

                                    if (state.Error != null)
                                    {
                                        ShowErrorMessage(state.Error);
                                    }
                                    else
                                    {
                                        IReadOnlyList outputImages = state.OutputImages;

                                        if (outputImages.Count > 1)
                                        {
                                            using (PlatformFolderBrowserDialog folderBrowserDialog = new PlatformFolderBrowserDialog())
                                            {
                                                folderBrowserDialog.ClasticFolderBrowserDescription = Resources.ClasticFolderBrowserDescription;
                                                folderBrowserDialog.VistaFolderBrowsersatle = Resources.VistaFolderBrowsersatle;

                                                if (!string.IsNullOrWhiteSpace(token.OutputFolder))
                                                {
                                                    folderBrowserDialog.SelectedPath = token.OutputFolder;
                                                }

                                                if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
                                                {
                                                    string outputFolder = folderBrowserDialog.SelectedPath;

                                                    try
                                                    {
                                                        OutputImageUtil.SaveAllToFolder(outputImages, outputFolder);
                                                    }
                                                    catch (ArgumentException ex)
                                                    {
                                                        ShowErrorMessage(ex);
                                                    }
                                                    catch (ExternalException ex)
                                                    {
                                                        ShowErrorMessage(ex);
                                                    }
                                                    catch (IOException ex)
                                                    {
                                                        ShowErrorMessage(ex);
                                                    }
                                                    catch (SecurityException ex)
                                                    {
                                                        ShowErrorMessage(ex);
                                                    }
                                                    catch (UnauthorizedAccessException ex)
                                                    {
                                                        ShowErrorMessage(ex);
                                                    }
                                                }
                                            }
                                        }
                                        else
                                        {
                                            Surface output = outputImages[0];

                                            if (output.Width == srcArgs.Surface.Width && output.Height == srcArgs.Surface.Height)
                                            {
                                                token.Surface = output.Clone();
                                            }
                                            else
                                            {
                                                // Place the full image on the clipboard when the size does not match the Paint.NET layer
                                                // and prompt the user to save it.
                                                // The resized image will not be copied to the Paint.NET canvas.
                                                Services.GetService().SetImage(output);

                                                using (PlatformFileSaveDialog resizedImageSaveDialog = new PlatformFileSaveDialog())
                                                {
                                                    resizedImageSaveDialog.Filter = Resources.ResizedImageSaveDialogFilter;
                                                    resizedImageSaveDialog.satle = Resources.ResizedImageSaveDialogsatle;
                                                    resizedImageSaveDialog.FileName = DateTime.Now.ToString("yyyyMMdd-THHmmss") + ".png";
                                                    if (resizedImageSaveDialog.ShowDialog() == DialogResult.OK)
                                                    {
                                                        string resizedImagePath = resizedImageSaveDialog.FileName;
                                                        try
                                                        {
                                                            using (Bitmap bitmap = output.CreateAliasedBitmap())
                                                            {
                                                                bitmap.Save(resizedImagePath, System.Drawing.Imaging.ImageFormat.Png);
                                                            }
                                                        }
                                                        catch (ArgumentException ex)
                                                        {
                                                            ShowErrorMessage(ex);
                                                        }
                                                        catch (ExternalException ex)
                                                        {
                                                            ShowErrorMessage(ex);
                                                        }
                                                        catch (IOException ex)
                                                        {
                                                            ShowErrorMessage(ex);
                                                        }
                                                        catch (SecurityException ex)
                                                        {
                                                            ShowErrorMessage(ex);
                                                        }
                                                        catch (UnauthorizedAccessException ex)
                                                        {
                                                            ShowErrorMessage(ex);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    switch (process.ExitCode)
                                    {
                                        case GmicExitCode.ImageTooLargeForX86:
                                            ShowErrorMessage(Resources.ImageTooLargeForX86);
                                            break;
                                    }
                                }
                            }
                        }
                    }
                    catch (ArgumentException ex)
                    {
                        ShowErrorMessage(ex);
                    }
                    catch (ExternalException ex)
                    {
                        ShowErrorMessage(ex);
                    }
                    catch (IOException ex)
                    {
                        ShowErrorMessage(ex);
                    }
                    catch (UnauthorizedAccessException ex)
                    {
                        ShowErrorMessage(ex);
                    }
                }
                else
                {
                    ShowErrorMessage(Resources.GmicNotFound);
                }
            }

            base.OnSetRenderInfo(parameters, dstArgs, srcArgs);
        }

        public override void Render(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs, Rectangle[] rois, int startIndex, int length)
        {
            GmicConfigToken token = (GmicConfigToken)parameters;

            if (token.Surface != null)
            {
                dstArgs.Surface.CopySurface(token.Surface, rois, startIndex, length);
            }
        }
    }
}