Jump to content

midora

Members
  • Posts

    1,782
  • Joined

  • Last visited

  • Days Won

    26

Posts posted by midora

  1. Works like a charm.  Useful addition to my toolbox.  Thanks Martin! :)

     

    Danke für die Blumen (this will be difficult to translate because the meaning depends on intonation ;-)

     

    Because I'm lazy I added the possibility to set the default values in the configuration file (I always need Meter, 300dpi, 1:50)

    So there is an update:

     

    1.1 (2.4.2013)

    - Renamed MeasureSelection.txt to MeasureSelection.dlc (please delete MeasureSelection.txt)

    - Added optional default value keys to the .dlc file

    - Moved some information from code to the assembly part of the dll

     

    I hope Rick will include - at some time - the dpi value of the image to the Environment of Effects.

    And to add a scale value to the resize dialog or somewhere else would help to get the scaled values in the status line during selection.

  2. Plugin which allows the digital image editor "Paint.NET" to take measurements of the active selection or of the whole image. This works for regular shapes like rectangles, for irregular ones, and for not connected shapes. You may set unit, dpi and scale if you have to do measurements in a map or a technical drawing.

    Measured values are

    • area and centroid of the selection
    • area, width, height, diagonal, and angles of the bounding rectangle.

    So if you like to measure the distance between two points in the image just use a selection rectangle form one point to the other and check the value for 'Diagonal' in Measure Selection. You may use the resulting angle value to straighten your image using the rotate tool. Or if you need the area of a cirle just use a circle selection.
     

    Download >>    MeasureSelection.Effect v1.5.zip

     

    Example

     

    MeasureSelection.Dialog.jpg

    Installation

    Unzip "MeasureSelection.Effect vX.X.zip" and copy the following files

    • MeasureSelection.dll, MeasureSelection.dlc
      into the Effects folder of your Paint.NET installation.
      A typical location is "C:\Program Files\Paint.NET\Effects".
       
    • OptionBasedLibrary vY.Y.dll, OptionBasedLibrary vY.Y.dlc
      into the folder of your Paint.NET installation (not into the Effect folder!).
      A typical location is "C:\Program Files\Paint.NET".

      Mod note: The OptionBasedLibrary .dll and .dlc are now required to be placed in the Effects folder.


    After a restart of Paint.NET you will find the plugin under Menu->Effects->Tools.

     

    Compatibility

    Paint.NET 3.5.11+
     

    Language support

    • English
    • Deutsch: Ist in Paint.NET als Sprache 'Deutsch' ausgewählt, dann
      sind auch die Dialogtexte und die Texte auf der erzeugten Seite in
      deutscher Sprache.
    • You may add your own translation to MeasureSelection.dlc

    Package content

    • The effect dll file
    • The effect dlc file (unicode txt file containing keywords)
    • The OptionBasedLibrary dll file
    • The OptionBasedLibrary dlc file (unicode txt file containing keywords)
    • A readme file
    • An image of the effect dialog

    Instructions

    1. Do or do not make a selection in an image
       
    2. Open plugin (Menu->Effects->Tools->Measure Selection...)
       
    3. Select unit, resolution, and scale value which will be used to show the results of the measurement.
       
    4. If you close the dialog using OK, the settings of unit, resolution, and scale will be saved and used in the next call of the plugin.

    Release History

     

    1.5 (26.3.2014)
    - Added top/left and bottom/right coordinate
    - Updated to OptionBasedLibrary 0.6

    1.4 (15.10.2013)
    - Patches to support Paint.NET 4.0

    1.3 (12.10.2013)
    - Added angles of the diagonal inside of the minimal bounding rectangle.
    - Replaced simple text controls with a drawing showing the results.

    1.2 (9.5.2013)
    - Added 'Centroid of selection' information
    - Moved the OptionBased part of the plugin to a separate dll.

    1.1 (2.4.2013)
    - Renamed MeasureSelection.txt to MeasureSelection.dlc
    - Added optional default value keys to the .dlc file
    - Moved some information from code to the assembly part of the dll

    1.0 (1.4.2013)
    - Initial release based on OptionBasedEffect library.


     

    • Like 1
    • Upvote 1
  3. I derived a dialog from EffectConfigDialog. The constructor of the dialog gets a description list of controls to create. The list contains the default values of the controls too.

     

    What's the right way to access the list in CreateInitialToken() to set the values of the new token to defaults?

     

    The problem is that the base class constructor of the dialog seems to call CreateInitialToken() to request the new token. But because this constructor will be executed before I can store the list in the new dialog instance , I don't know how to solve this issue.

     

    OK, temporary I'm using a static variable in the dialog class to provide the list to CreateInitialToken(), but this is just to allow me to continue coding...

  4. Sorry but you can not expect that pixel operations with an alpha value will keep the color. Some operations may some may not. This means the color is undefined.

     

    Quite often if the alpha value is zero then there is a shortcut in the code to improve the speed of the operation. This is what a lot of effect plugins are doing.

     

    If the destination pixel of an argb pixel does not support alpha then you have to render the pixel against a solid color which means that you will get the solid color if the alpha value is zero. It is not ok just to remove the alpha value.

     

    I guess Rick tried to say that as long as you are working with a pdn file the color of such a pixel is not of interest.

  5. About PDNAnimator...          

               
    Standalone application which allows to create animated images in PNG or GIF format from Paint.NET PDN files.

    Warning: This tool is in a quite early state of development. Feedback is welcome.

    Compared to a flat image file format the layers in a PDN image file provide the flexibility to combine the layers with opacity and blendmodes respecting the alpha values of layer pixels. This provides a quite good fundament which can be used by an application to create animations. PDNAnimator is such an application. You can not edit pixels in PDNAnimator (use Paint.NET to do this job) but you are able to combine the layers in a different way to create animations.

    But how is the animation controlled? The user can edit the layer names in Paint.NET to add animation information about backgrounds, foregrounds, shifting, blending and timings. PDNAnimator uses this information coded in the names of the layers to create the frames of an animation. PDNAnimator also shows the animation and allows to export it to the standard animation formats used in the web.
    (In the moment just apng).

    Here is how PDNAnimator works. Starting from thevbottom layer up to the top layer the application checks the names of the layers and create frames for the animation (the visibility flags of the layers will be ignored).

    The important character in the name is the '!' character. This character starts the frame information part of the name.
    If a layer name does not contain a '!' then the layer will be added as the next frame to the animation.
    The characters after the '!' define what should be done with the layer content.

    See the help entry in the application menu for a summary of commands:
    Background frame, Foreground frame, Default frame, Clipping, scaling down, flipping, moving, fading, timing.

    Why isn't this tool implemented as a Paint.NET plugin? The plugin inferface of Paint.NET is limited to filetype and effect plugins. To integrate the animation part would be a big hack.

    That's it. Enough information for the moment icon_e_wink.gif
     
  6. @ midora, I am not sure if we should start a new thread to discussing your great plugin the PDNanimator, or just continue it in another place, so we don't spam Simon 's thread and confuse people between the two?

     

    No I'm sure we should do this. I guess I stated this earlier. Would be nice if a moderator could propose a solution or open such a thread at the right place. There is then the possibility always to add a link here to the new thread.

  7. Entering a large value for pan x crashes Paint.NET.

    OK, nobody will do this, just me ;-)

     

    Exception details:
    System.OverflowException: Overflow error.
       at System.Drawing.Graphics.CheckErrorStatus(Int32 status)
       at System.Drawing.Graphics.DrawLine(Pen pen, Single x1, Single y1, Single x2, Single y2)
       at PaintDotNet.Effects.PanControl.DrawToGraphics(Graphics g) in D:\src\pdn\pdn_35x\src\Effects\PanControl.cs:line 247
       at PaintDotNet.Effects.PanControl.CheckRenderSurface() in D:\src\pdn\pdn_35x\src\Effects\PanControl.cs:line 160
       at PaintDotNet.Effects.PanControl.DoPaint(Graphics g) in D:\src\pdn\pdn_35x\src\Effects\PanControl.cs:line 168
       at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
       at System.Windows.Forms.Control.WmPaint(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

  8. Here a little bit code which may be used to add funtionality to the NumericUpDown Controls:

    Unit specifier, Wraping modes (which is usefull for angle stuff) and increment lists.

    I used it for this:

     

    post-79572-0-98407400-1361646996_thumb.j

     

    using System;
    using System.Globalization; // CulturInfo
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Windows.Forms;
    
    namespace ControlExtensions
    {
    
        public enum WrapMode
        {
            None,
            UseOpposite,
            UseIncrement
        }
    
        public sealed class ControlNumericUpDown
            : NumericUpDown
        {
    
            // ----------------------------------------------------------------------
            /// <summary>
            /// Gets or sets wraping behaviour if Value reaches Minimum or Maximum
            /// </summary>
            public WrapMode Wrap
            {
                get { return _wrap; }
                set { _wrap = value;}
            }
            private WrapMode _wrap = WrapMode.None;
    
            // ----------------------------------------------------------------------
            /// <summary>
            /// Gets or sets a list of values to be used by the up and down buttons
            /// </summary>
            public double[] UpDownList
            {
                get { return _upDownList; }
                set {
                    for (int i = value.Length - 1; i > 0; i--)
                    {
                        if (value[i] <= value[i - 1])
                            throw new ArgumentException("UpDownList must be ordered from low to high value");
                    }
                    if ((value[0] < (double)Minimum) || (value[value.Length - 1] > (double)Maximum))
                        throw new ArgumentException(String.Format("UpDownList out of range [{0} {1}]", Minimum, Maximum));
                    _upDownList = value;
                }
            }
            private double[] _upDownList = null;
    
            // ----------------------------------------------------------------------
            /// <summary>
            /// UpButton which supports wrapping
            /// </summary>
            public override void UpButton()
            {
                if (UserEdit)
                {
                    ParseEditText();    // finish user edit
                }
    
                try // Operations on Decimals can throw OverflowException.
                {
                    switch (_wrap)
                    {
                        case WrapMode.None:
                            if ((_upDownList != null) && (_upDownList.Length > 0))
                            {
                                int i;
                                for (i = 0; i < _upDownList.Length; i++)
                                {
                                    if ((double)Value < _upDownList[i]) break;
                                }
                                i = (i >= _upDownList.Length) ? _upDownList.Length - 1 : i;
                                Value = (decimal)_upDownList[i];
                                return;
                            }
                           break;
                        case WrapMode.UseOpposite:
                            if (Value + Increment > Maximum)
                            {
                                Value = Minimum;
                                return;
                            }
                            break;
                        case WrapMode.UseIncrement:
                            if (Value + Increment > Maximum)
                            {
                                Value = Minimum + (Value + Increment - Maximum);
                                return;
                            }
                            break;
                    }
                }
                catch (OverflowException)
                {
                    Value = Maximum;
                    return;
                }
                base.UpButton();
            }
    
            // ----------------------------------------------------------------------
            /// <summary>
            /// DownButton which supports wrapping
            /// </summary>
            public override void DownButton()
            {
                if (UserEdit)
                {
                    ParseEditText();    // finish user edit
                }
    
                try // Operations on Decimals can throw OverflowException.
                {
                    switch (_wrap)
                    {
                        case WrapMode.None:
                            if ((_upDownList != null) && (_upDownList.Length > 0))
                            {
                                int i;
                                for (i = _upDownList.Length - 1; i >= 0; i--)
                                {
                                    if ((double)Value > _upDownList[i]) break;
                                }
                                i = (i < 0) ? 0 : i;
                                Value = (decimal)_upDownList[i];
                                return;
                             }
                             break;
                        case WrapMode.UseOpposite:
                            if (Value - Increment < Minimum)
                            {
                                Value = Maximum;
                                return;
                            }
                            break;
                        case WrapMode.UseIncrement:
                            if (Value - Increment < Minimum)
                            {
                                Value = Maximum + (Value - Increment - Minimum);
                                return;
                            }
                            break;
                    }
                }
                catch (OverflowException)
                {
                    Value = Minimum;
                    return;
                }
                base.DownButton();
            }
    
    
            // ----------------------------------------------------------------------
            /// <summary>
            /// OnEnter select the whole text without the unit
            /// </summary>
            protected override void OnEnter(EventArgs e)
            {
                Select(0, TextWithoutUnit().Length);
                base.OnEnter(e);
            }
    
    
            // ----------------------------------------------------------------------
            /// <summary>
            /// Gets or sets the unit string of the numericupdown control
            /// </summary>
            public String Unit
            {
                get { return _unit; }
                set
                {
                    _unit = (value == null) ? null : String.Copy(value);
                    UpdateEditText();
                }            
            }
            private String _unit;
    
            // ----------------------------------------------------------------------
            /// <summary>
            /// Catches the value in the minimum to maximum range
            /// </summary>
            private Decimal Constrain(Decimal value)
            {
                if (value < Minimum) return Minimum;
                if (value > Maximum) return Maximum;
                return value;
            }
    
            // ----------------------------------------------------------------------
            /// <summary>
            /// Returns the text w/o the unit suffix
            /// </summary>
            private String TextWithoutUnit()
            {
                if (string.IsNullOrEmpty(Text)) return String.Empty;
                String text = String.Copy(Text).Trim();
                if (!string.IsNullOrEmpty(Unit))
                {
                    if (text.EndsWith(Unit))
                    {
                        text = text.Remove(text.Length - Unit.Length);
                        text = text.Trim();
                    }
                }
                return text;
            }
    
            // ----------------------------------------------------------------------
            /// <summary>
            /// Converts number to a text
            /// </summary>
            private string GetNumberText(decimal num)
            {
                string text;
    
                if (Hexadecimal)
                {
                    text = ((Int64)num).ToString("X", CultureInfo.InvariantCulture);
                }
                else
                {
                    text = num.ToString((ThousandsSeparator ? "N" : "F") + DecimalPlaces.ToString(CultureInfo.CurrentCulture), CultureInfo.CurrentCulture);
                }
                return text;
            }
    
            // ----------------------------------------------------------------------
            /// <summary>
            /// Converts 'Text' member to 'Value' member
            /// </summary>
            private new void ParseEditText()
            {
                String numericText = TextWithoutUnit();
                try
                {
                    // VSWhidbey 173332: Verify that the user is not starting the string with a "-"
                    // before attempting to set the Value property since a "-" is a valid character with
                    // which to start a string representing a negative number.
                    if (!string.IsNullOrEmpty(numericText) &&
                        !(numericText.Length == 1 && numericText == "-"))
                    {
                        if (Hexadecimal)
                        {
                            Value = Constrain(Convert.ToDecimal(Convert.ToInt32(numericText, 16)));
                        }
                        else
                        {
                            Value = Constrain(Decimal.Parse(numericText, CultureInfo.CurrentCulture));
                        }
                    }
                }
                catch
                {
                    // Leave value as it is
                }
                finally
                {
                    UserEdit = false;
                }
            }
    
            // ----------------------------------------------------------------------
            /// <summary>
            /// Converts 'Value' member to 'Text' member.
            /// If the user just edited the text then the text will be parsed.
            /// </summary>
            protected override void UpdateEditText()
            {
                if (UserEdit)
                {
                    ParseEditText();    // finish user edit
                }
    
                ChangingText = true;
                String text = GetNumberText(Value);
                if (Unit == null)
                {
                    Text = text;
                }
                else
                {
                    Text = text + " " + Unit;
                }
            }
    
            // ----------------------------------------------------------------------
            /// <summary>
            /// Converts 'Text' member to 'Value' member and back to 'Text' member
            /// </summary>
            protected override void ValidateEditText()
            {
                // Remark: Same as base function but calls local ParseEditText
                ParseEditText();
                UpdateEditText();
            }
    
        }
    }
    
    
     

     

     

  9. I'm no programmer, but from a user's point of view, I find it much more convenient to just click the reset buttons if I want to get to zero, anyways.

     

    That's how a good user interface should work. Every user should be able to use his preferred way to do things. Or?

     

    And the zero value is just an example of the issue.

  10. One issue which disturbs me using the PanAndSlider property is that if you are panning then it is not possible to drag back to the 0/0 center. You are getting values like 0.02 or -0.01 always.

     

    The reason for this is that the calculation of the rectangle for the embedded pan control always sets the value to odd (using  |= 1).

    Because of this it is not possible to pan to a center value of 0/0 with the mouse.

  11. OnSetRenderInfo provides you the properties you should use to render to the destination surface.

     

    You should not execute all the rendering in OnSetRenderInfo because your plugin would not profit from multi core support.

    But if it is possible to split the algorithm in a pre calculation and a pixel calculation phase then it makes sense to do the pre calculation in OnSetRenderInfo and restrict the pixel calculations to the rectangle provided to Render.

  12. For sure

     

    1) post-79572-0-92739100-1360957988_thumb.j

     

    In the meantime I guess that the larger bottom margin only happens if the effect dialog is sizable.

    And there are not a lot effects allowing this.

     

    2) post-79572-0-30457500-1360958006_thumb.j

     

    Here you can see that firefox restores its glass area fine after resuming Windows. Just Paint.NET fails to do it.

  13. 1) The bottom margin of the OK and Cancel buttons in effect dialogs is much larger than in other dialogs (like 'Resize'). Looks like that there is a missing correction in setting of the button location if glass buttons are enabled.

     

    2) After "Resuming Windows" an open dialog shows no longer the extended glass area. The background of the button area is black and the buttons are still aligned to the right border w/o a margin. Closing and reopening fixes the issue. Maybe a driver issue: Windows7, 64bit, Hp Touchsmart 2. But you should check.

     

    I have to add that 2) also happens with the extended glass frame on the top of the main window.

    Is anybody else able to reproduce this?

×
×
  • Create New...