Wet floor effect batch transform using WPF

My wife just took some new photos for her scrapbooking website. I have a coverflow effect on that page, so I needed to apply the wet floor transform to 64 images. Rather than do it all by hand, I wrote some WPF code to do it for me:

public class WetFloor
{
    public static void Render(string source, string target, int targetWidth)
    {
        using (Stream input = File.OpenRead(source))
        {
            // Load the source jpg.
            JpegBitmapDecoder sourceJpg = new JpegBitmapDecoder(input, BitmapCreateOptions.None, BitmapCacheOption.Default);
            if (sourceJpg.Frames.Count != 1)
                throw new Exception(String.Format("I don't know how to handle {0} frames.", sourceJpg.Frames.Count));
            BitmapFrame sourceBitmap = sourceJpg.Frames[0];

            // Create a render target scaled to 400 pixels at 150% the aspect ratio.
            double scale = (double)targetWidth / sourceBitmap.PixelWidth;
            RenderTargetBitmap renderTarget = new RenderTargetBitmap(
                targetWidth, (int)Math.Round(scale * (float)sourceBitmap.PixelHeight * 1.5),
                sourceBitmap.DpiX, sourceBitmap.DpiY,
                PixelFormats.Pbgra32);

            // Paint a rectangle with the source bitmap.
            Rectangle original = new Rectangle()
            {
                Fill = new ImageBrush(sourceBitmap),
                Width = scale * sourceBitmap.Width,
                Height = scale * sourceBitmap.Height
            };

            original.Arrange(new Rect(new Size(scale * sourceBitmap.Width, scale * sourceBitmap.Height)));
            renderTarget.Render(original);

            // Paint a black rectangle.
            Rectangle shade = new Rectangle()
            {
                Fill = new SolidColorBrush(Colors.Black),
                Width = scale * sourceBitmap.Width,
                Height = scale * sourceBitmap.Height
            };

            shade.Arrange(new Rect(new Point(0, scale * sourceBitmap.Height), new Size(scale * sourceBitmap.Width, scale * sourceBitmap.Height)));
            renderTarget.Render(shade);

            // Paint an inverted rectangle with the source bitmap.
            Border reflection = new Border()
            {
                Background = new ImageBrush(sourceBitmap),
                Width = scale * sourceBitmap.Width,
                Height = scale * sourceBitmap.Height,
                RenderTransform = new ScaleTransform(1.0f, -1.0f, scale * sourceBitmap.Width / 2, scale * sourceBitmap.Height / 2),
                OpacityMask = new LinearGradientBrush()
                {
                    StartPoint = new Point(0, 1),
                    EndPoint = new Point(0, 0),
                    GradientStops = new GradientStopCollection(new GradientStop[]
                    {
                        new GradientStop()
                        {
                            Offset = -0.3f,
                            Color = Colors.Black
                        },
                        new GradientStop()
                        {
                            Offset = 0.5f,
                            Color = Colors.Transparent
                        }
                    })
                }
            };

            reflection.Arrange(new Rect(new Point(0, scale * sourceBitmap.Height), new Size(scale * sourceBitmap.Width, scale * sourceBitmap.Height)));
            renderTarget.Render(reflection);

            // Render the final product.
            JpegBitmapEncoder png = new JpegBitmapEncoder();
            png.Frames.Add(BitmapFrame.Create(renderTarget));
            using (Stream fs = File.Create(target))
            {
                png.Save(fs);
            }
        }
    }
}

Enjoy.

Leave a Reply