EasyPainter Source Pack 3: Adorners, Mouse Cursors and Frames

Mar 17, 2010

Adorners went a long way since their first release few months ago.

They integrate with zoom now, have more options for controlling functionality and can use a shared "cursor plane" for displaying mouse cursors consistently across your application. Extensibility is improved allowing definition of custom adorner frames. There are 7 custom cursors and 4 custom frames to get you started :)

Download source code

I use the same adorner implementation in EasyPainter.

Here's a live demo with different adorner frame for each image:

Features

  • Custom, Extensible Mouse Cursors allow you to use the system or your own mouse cursors even if you don't use the adorner functionality. See CursorPlane.cs for more info

The custom cursors support:

    • Size (for example, bigger cursor for bigger brush size)
    • Rotation (used to make the resize cursor perpendicular to the adorner frame)

The current list supports all system cursors as well as these:

Size, // Size cursor that supports angle
Rotate, // Rotate cursor supporting angle
Move, // Move cursor
Brush, // Brush cursor, supports size
SelectionBrush, // Selection brush cursor
Crosshair, // Crosshair cursor - like the one used on snipers or in image editing programs to pinpoint that pixel
MarkerSelect, // Cursor used to select a marker on the surface (e.g. used to select point for applying origin for zoom blur effect)

To use the cursors you have to set up a cursor plane in XAML:

<adorners:CursorPlane Name='cursorPlane' />

And then initialize it in code-behind:

    InitializeComponent();
    ctlCursorPlane.SetSystemCursorElement(frameRoot);

The frameRoot specifies which control will display the cursors. For example, in EasyPainter the Crop adorner spans only the image (the adorner is parented to a different parent than the cursor plane), but the rotate/resize cursor go outside of the image. The frameRoot is used to calculate the offsets so that the adorners (or someone else using the cursor plane) can account for the different parents and draw the cursors at the correct locations on screen.

  • Customizable Adorners with extensible adorner frames

You can now define your custom adorner frames by creating a UserControl and implementing the functionality you need from the IAdornerFrame interface.

There are 4 existing frames currently: AnimatedRectangleFrame, CropFrame, GlassFrame and PointFrame. The last one is just a dot being used to specify locations of effects in EasyPainter – e.g. Zoom motion effect.

The existing frames can be zoom-aware. For example the CropFrame displays the correct image width and height in the top-left corner regardless of zoom.

/// Represents an adorner frame, e.g. glass border
public interface IAdornerFrame {
    /// Called when the frame is attached to adorner
    void Attached();

    /// Called when the frame is detached from adorner
    void Detached();

    /// Sets the zoom level for this adorner frame. The zoom level is used by the frame to display correct coordinates (e.g. Width and Height)
    void SetZoom(double newZoomLevel);

    void SizeChanged(double newWidth, double newHeight);
}

  • More adorner options: bool CanRotate, CanResize, CanMove, void SetBounds(x, y, width, height), SetZoom(double zoomLevel) allow you to change adorner capabilities, restrict it to specific area, and make it zoom-aware

I didn't have time to add the behaviours back since I don't use those yet and I'm mainly using Visual Studio for development. If anyone is interested in porting these over to the current version Andrej Tozon created the Behaviours for the original version. Here's a link to his version. Thanks Andrej!

The source code is licensed under MS-PL.

Pictures are licensed under the following Creative Commons License: http://creativecommons.org/licenses/by/2.0/
Picture locations:
http://www.flickr.com/photos/proimos/3954987905/
http://www.flickr.com/photos/proimos/4300827122/
http://www.flickr.com/photos/tenioman/2771903123/

Hope you like it! Please comment!

    

EasyPainter Source Pack 2: Flickr, ComboCheckBox and more!

Mar 11, 2010

Yes! EasyPainter Source Pack 2 is here!

This source pack contains Flickr integration sample amongst other also important things (read below).

Download Source Code

The live demo:

Usage

  1. Go to http://www.flickr.com/services/api/, sign up and get an API key for your app
  2. Put the key in Flickr\FlickrHelper.cs
  3. Use the below code behind and XAML:

public MainPage() {
    InitializeComponent();
    Globals.ToolbarRadioButtonStyle = (Style)Application.Current.Resources["ToolbarRadioButton"];
    IGenericUserInterface ui = (IGenericUserInterface)openDialog1;
    ui.Result += new GenericResultHandler(ui_Result);
}

void ui_Result(IGenericUserInterface sender, EasyPainter.Imaging.ResultType result, bool uiDismissed) {
    MessageBox.Show(String.Format("Result type: {0}\nPhoto Url: {1}", result, openDialog1.PhotoUrl));
}

XAML:

<Grid x:Name="LayoutRoot" Background="White">
    <my:OpenDialog x:Name='openDialog1' />
</Grid>

License

The source code of the sample is licensed under MS-PL

Flickr usage is governed by their own license: check the terms of use on http://www.flickr.com/services/api/ for more details.

Source Code Information

Apart from Flickr, there are some other things interesting to developers in this sample:

  • Queuing for WebClient. The WebClient class does not allow to call DownloadStringAsync() while another download using WebClient is in progress. The WebClientQueue class in the sample allows you to queue work items, cancel them, gracefully display and recover from errors and get updates on progress.
  • Caching for WebClient REST API and other requests. The current cache is set in WebClientQeueue to 5 minutes. Huge speed improvement when browsing through the images!
  • ComboCheckBox control (far from perfect, but still usable for some cases)
  • Minimalistic WrapPanel. The 10KB version of the WrapPanel extracted from the Silverlight toolkit that is typically around 280 KB.
  • Lightweight XML parsing. Using XMLReader instead of Linq like other samples do helps shave off about 100KB of size from the sample
  • Small size! Combining the 2 above items, and the XAP file is only 27K (I wish it was less but life if life :))
  • ImageList control for showing and paging through images
  • ImageSwitchHelper – a "fit-and-finish" control that helps avoid "jumping" when the image on the right changes. The control preserves the frame size until the next image is loaded.
  • An easy way to keep UI alive and preserve the dialog view (DialogStore.cs). If you open EasyPainter you'll notice that every time you click "Open from Flickr" you will go to your previous view instead of resetting the UI.
  • IUserInterface – a kind of generic interface for reusable UIs and for connecting UIs with other parts of your program. This interface is used in all dialogs in EasyPainter, for example to update the view when filter values change. It also allows to click through effects without clicking Cancel on each dialog (for example). All EasyPainter filter UI dialogs are built on-the-fly from metadata info assigned to the filter (this would come in another sample sometime).

I almost missed something important: once you have the image Url, you can display it in an Image tag. If you want to use it from within WriteableBitmap though, you'll have to round-trip it through the server that serves the .xap file (in EasyPainter's case that's www.nokola.com).

Also note that Source Pack 1 has a refresh today too containing new features and bug fixes!

I hope this sample will help you make more responsive/pleasing UIs in addition to Flickr!

Hope you like it! Please comment :)

  

EasyPainter Source Pack 1 Refresh

Mar 11, 2010

There were several major bugfixes in EasyPainter controls and few updates.

Here are the main two:

  • Changing the color the first time when using the API in the color picker now works (heh :)).
  • Editable slider has a new DisplayFormat property allowing you to override the format (e.g. DisplayFormat="X: 0.0" – see below)

The sample is also moved to Visual Studio 2010 RC.

Here is a refresh of source pack 1 with the changes:

Download Source Code

The live demo:

EasyPainter: Lion Hair styling

Mar 5, 2010

I am playing with EasyPainter recently :) There are no new additions to the software (yet).

Here's how to apply a hair style to a lion.

Original:

lions

Hair styled:

Lions_after

The original image is from: http://www.flickr.com/photos/wwarby/2404544591/ (search for "lion" in EasyPainter)

I'd say the second one looks way cooler, especially with the blue Raiden-like eyes. Raiden is the god of thunder from Mortal Kombat!

Effects used: Color shift for the eyes, followed by Brigthness. Waves for the "hair" and a finishing touch of Life-like.

  

10 New Effects in EasyPainter

Feb 26, 2010

Yes! :) After spending about 1 hour last night, here are 10 more shaders in EasyPainter.

Since I don't have time to write about each one now, here is a sample image leveraging a few:

Original:

_original

Manipulated:

_severalFilters

  • Zoom Motion in the lower left corner making the trees appear moving fast towards the viewer
  • Ripples in the sea
  • Magnify to enlarge the cloud on the right of the image
  • Pinch to change the shape of the lower coconuts
  • Tint and Color Shift to change the color of the coconuts
  • Sharpen on the houses in the backgroundto make the contrast with Zoom Motion stand out more
  • Magnifier Lens to make the trunk of the palm thinner
  • Life-Like Colors to reveal the missing colors

Shaders now have color pickers (such as Tint), and positions (such as Zoom Motion). The position adorner can be dragged on screen with the mouse.

I also made few bugfixes to the ColorPicker control and the RangeSlider, and will publish these shortly.

Most of the shaders are small modifications or a combination of http://wpffx.codeplex.com shaders and http://shazzam.codeplex.com/.

Moreover, EasyPainter is 12 KB less than its last version, almost 300 KB now. I may still be able to get it in the 250KB range..we'll see.

Hope you like it!

EasyPainter: Watercolor, Blood and Gloom Pixel Shaders

Feb 20, 2010

Click here to try the new effects in EasyPainter.

Download source code.

Original vs Zombie – can you figure out which one is which? :)

nikolami zombie

The new Blood shader works only on skin colors. To use it, you have to use the selection brush to select skin tones from the image.

Here is the Watercolor shader. It's very subtle, but I think it looks nice nevertheless. If anyone has suggestions for improvements, including a proper name for this shader, since it is really subtle - please let me know!

image watercolor

I also added a Gloom effect, the one from http://wpffx.codeplex.com

Little Tech Stuff

The "blood" is in fact the pastel texture from the Pastel effect, blended with Burn.

The watercolor is based on real tutorials on doing water color effects: it is a combination of [cheap horizontal] blur and sobel edge detection. Unfortunately, the blur has to be 2-pass to look good, and span larger area. I might improve it in the future. Anyway, the effect looks pleasing to me for now :)

  

Old Photo, Pastel, and Pencil Sketch Pixel Shaders For Silverlight

Feb 18, 2010

EasyPainter has new filters! Source code below! Try them out here

Edit: I'd actually like to improve the pastel shader further - real-life pastel is usually on white background, and the shaders are on black...

Samples

Original (http://www.flickr.com/photos/-arpi/4280428638/):

Original

Pastel Drawing:

Pastel

Old Photo:

OldPhoto1

Old Photo ("younger"): More...

  

Someone Said it Was Impossible: Hue Shift in Pixel Shader 2.0 (EasyPainter, Silverlight)

Feb 9, 2010

I read somewhere online that Hue changes can't be done in pixel shader 2.0, due to limitation of 64 instructions per slot.

Here's the sample that proves otherwise:

Download source code

Indeed the RGB-to-HSL-to-RGB conversion takes about 100 instructions in its typical implementation. PS 2.0 which is the shader model supported by Silverlight 3 only allows for 64 arithmetic instructions, as outlined in this comparison between pixel shaders on Wikipedia

How can we optimize it?

Optimizing pixel shader instruction slots is nice - in a typical C# world, you'd be adding if() statements to make your code run faster like this:

    if ( HSV.y != 0 )
       QUAD_REAL var_h = HSV.x * 6;
       QUAD_REAL var_i = floor(var_h);   // Or ... var_i = floor( var_h )
       QUAD_REAL var_1 = HSV.z * (1.0 - HSV.y);
       QUAD_REAL var_2 = HSV.z * (1.0 - HSV.y * (var_h-var_i));
       QUAD_REAL var_3 = HSV.z * (1.0 - HSV.y * (1-(var_h-var_i)));
       if      (var_i == 0) { RGB = QUAD_REAL3(HSV.z, var_3, var_1); }
       else if (var_i == 1) { RGB = QUAD_REAL3(var_2, HSV.z, var_1); }
       else if (var_i == 2) { RGB = QUAD_REAL3(var_1, HSV.z, var_3); }
       else if (var_i == 3) { RGB = QUAD_REAL3(var_1, var_2, HSV.z); }
       else if (var_i == 4) { RGB = QUAD_REAL3(var_3, var_1, HSV.z); }
       else                 { RGB = QUAD_REAL3(HSV.z, var_1, var_2); }
   }

Not with pixel shaders. If you look carefully at the bold if statement, removing it does not change the program logic. It just takes an extra instruction slot. In reality, I think the pixel shader code will run with the same speed with or without the if() (not 100% sure so correct me if needed).

With this knowledge, I decided to do these optimizations:

1. Instead of HSL-to-RGB, use HSV-to-RGB. The reference NVidia Shader Library implementation (source code here) of HSV-RGB-HSV takes ~70 or so slots.

2. Combine the min_channel() and max_channel() functions into 1 - saves a couple if() statements

3. Take out the if (x < 0) (x += 1) checks in the RGB-HSV function, and execute them once instead of twice, after the hue is modified.

4. Remove the "obsolete" if()-s like the one above

I was very happy to see that it just fit in the 64-instruction slot of PS 2.0! Note that it hits the limit and more complex Hue stuff may need further optimizations! :) If you do so, please let me know! Anyway hue tricks that don't use more slots are OK.

Here's the complete Shazzam-friendly source of the .fx file (also included in the sample project source above).

/// <summary>Hue shift</summary>
/// <minValue>0</minValue>
/// <maxValue>1</maxValue>
/// <defaultValue>0</defaultValue>
float HueShift : register(c0);
sampler2D Samp : register(S0);
#define QUAD_REAL float
#define QUAD_REAL3 float3
QUAD_REAL3 rgb_to_hsv_no_clip(QUAD_REAL3 RGB)
{
    QUAD_REAL3 HSV;
   
 float minChannel, maxChannel;
 if (RGB.x > RGB.y) {
  maxChannel = RGB.x;
  minChannel = RGB.y;
 }
 else {
  maxChannel = RGB.y;
  minChannel = RGB.x;
 }
 
 if (RGB.z > maxChannel) maxChannel = RGB.z;
 if (RGB.z < minChannel) minChannel = RGB.z;
   
    HSV.xy = 0;
    HSV.z = maxChannel;
    QUAD_REAL delta = maxChannel - minChannel;             //Delta RGB value
    if (delta != 0) {                    // If gray, leave H & S at zero
       HSV.y = delta / HSV.z;
       QUAD_REAL3 delRGB;
       delRGB = (HSV.zzz - RGB + 3*delta) / (6.0*delta);
       if      ( RGB.x == HSV.z ) HSV.x = delRGB.z - delRGB.y;
       else if ( RGB.y == HSV.z ) HSV.x = ( 1.0/3.0) + delRGB.x - delRGB.z;
       else if ( RGB.z == HSV.z ) HSV.x = ( 2.0/3.0) + delRGB.y - delRGB.x;
    }
    return (HSV);
}
QUAD_REAL3 hsv_to_rgb(QUAD_REAL3 HSV)
{
    QUAD_REAL3 RGB = HSV.z;
    //if ( HSV.y != 0 ) { // we don't really need this since it just adds an obsolete instruction slot
       QUAD_REAL var_h = HSV.x * 6;
       QUAD_REAL var_i = floor(var_h);   // Or ... var_i = floor( var_h )
       QUAD_REAL var_1 = HSV.z * (1.0 - HSV.y);
       QUAD_REAL var_2 = HSV.z * (1.0 - HSV.y * (var_h-var_i));
       QUAD_REAL var_3 = HSV.z * (1.0 - HSV.y * (1-(var_h-var_i)));
       if      (var_i == 0) { RGB = QUAD_REAL3(HSV.z, var_3, var_1); }
       else if (var_i == 1) { RGB = QUAD_REAL3(var_2, HSV.z, var_1); }
       else if (var_i == 2) { RGB = QUAD_REAL3(var_1, HSV.z, var_3); }
       else if (var_i == 3) { RGB = QUAD_REAL3(var_1, var_2, HSV.z); }
       else if (var_i == 4) { RGB = QUAD_REAL3(var_3, var_1, HSV.z); }
       else                 { RGB = QUAD_REAL3(HSV.z, var_1, var_2); }
   //}
   return (RGB);
}
float4 main(float2 uv : TEXCOORD) : COLOR
{
 float4 col = tex2D(Samp, uv);
 float3 hsv = rgb_to_hsv_no_clip(col.xyz);
    hsv.x+=HueShift;
    //if ( hsv.x < 0.0 ) { hsv.x += 1.0; }
    if ( hsv.x > 1.0 ) { hsv.x -= 1.0; }
    return float4(hsv_to_rgb(hsv),col.w);
}
 
btw, Visual Studio 2010 RC is out for MSDN subsribers (public tomorrow) and I'm going to publish all samples in VS 2010 from now on :)

Hope you like it!

      

EasyPainter Beta: Top Secret Online Image Editor Announced

Feb 4, 2010

Today I am announcing EasyPainter Beta: The Artist Within. An online image editor that is: Fast. Easy. Made for non-designers. And FREE! :)

Click here to open EasyPainter

Note: send feedback in the comments section of this post.

Unlike other online (or many offline) image editors, EasyPainter offers online effects comparable to powerful desktop apps, integrated search for millions of free-for-commercial or -personal use photos, and instant previews of any changes you make.

Find below:

  • Quick intro to easy painter
  • Many Screenshots
  • Getting Started Tutorials
  • Effect Tutorials
  • Tech Stuff

What Does Easy Painter Offer?

The Basics

  • Reveal the true-to-life colors in photos. Make them look like shot with professional camera. Your friends will be wowed!
    • The life-like photo filter combines several steps of popular GIMP/Photoshop "how to enhance an image" tutorials into one.  Save time with a 1-step effect instead of following an online tutorial.
  • Preview effects and changes instantly. It's OK to change your mind – many times per second. That's why we have computers for :)
  • Find millions of free for commercial use photos for your project from Flickr
    • Also filter by "government use", "non-commercial use", and other
  • Quickly resize, email size. Flip. Rotate. Draw to select objects and crop with a single click.
  • Manipulate huge 25 megapixel panoramas, fast. Powered by bleeding edge Silverlight and Pixel Shader engines.
  • Ease of use: tired of figuring out image programs with "Edge Detect", "Bumpiness factor" and "Directional Blur parameters"?
    • Work with more intuitive language like: "Hollow Outline", "Fast Motion", "Painting"
    • Mix-and-match. Draw on the image while an effect is open at the same time. Switch between effects and see your changes applied instantly

Effects

  • "Paint" with any effect, such as blur, emboss, bloom, saturation, and more
  • Make curves in trees, fluff clouds or perform complex photo manipulations easily by clicking and "drawing" effects with the mouse
    • Preview and change at will. For example, move a slider to bend a straight tree back and forth
  • Make changes that look good every time. Even if you are not a designer. All EasyPainter filters suggest the best values for your image.
  • Compare before and after with a single click on the currently open effect

Screenshots

All images combined are made in less than 25 minutes

The screenshots below are intended to show samples of the functionality. For more tutorials, see the Getting Started and Effects Tutorials sections

Open From Flickr:

.OpenFromFlickr

Painting With Effect:

PaintWithEmboss

Original:

This is the original image being modified in the next screenshots:More...

  

nokola.com | Terms | Log in

Recent

About the author

Happy & enjoying life. Software enthusiast.
The opinions I express here and on nokola.com are mine and not my employeer's (Microsoft).
This is the official blog of nokola.com. You can find Silverlight samples, coding stuff, and hopefully other interesting things here.