5
votes

I want to create an effect where I use a quite large image to produce a smaller image with HLSL through a WPF Effect. But it seems that WPF for some reason resizes all input images to the rendered size, which isn't what I want, since it will crop one of my images quite a lot and make my final image look not so good.

This is how I have it set up. I have an image (a video) that is the size of 2592x1944 that is played in a MediaElement. I apply my effect on a Border (or other element) with the size of 800x600 and bind the MediaElement to the effect to be able to send both the surface to render on (the border) and the source to render from (the MediaElement) to the pixel shader.

But the resulting image is very pixelated due to heavy cropping of the source.

Does anyone know if there's a way to get WPF to not crop the pixel shader samples?

I found this blogpost by Greg Schecter that kinda do what I want, but the other way around: http://blogs.msdn.com/b/greg_schechter/archive/2008/09/27/a-more-useful-multi-input-effect.aspx He shrinks an image, but I want to make it bigger I guess. The thing is that he uses an ImageBrush, and I got a VisualBrush since I use UIElements and not images. Don't know if there's a way of doing the stuff he does on a VisualBrush.

1

1 Answers

2
votes

In WPF Visual you can't do anything, because WPF PixelShader lost quality, if your image source has more size, than render size. If your image source has less size, than render size, you can use PaddingTop, PaddingBottom, PaddingLeft and PaddingRight. Only one wayt, which can help you save FULL quality:

Use Image or ImageBrush and set Stretch to None. In this way you send full image (Textura) to PixelShader. You must have DependencyPRoperty in custom ShaderEffect:

public static readonly DependencyProperty ViewAspectProperty = DependencyProperty.Register(nameof(ViewAspect), typeof(Point), typeof(CustomEffect), new UIPropertyMetadata(new Point(1D, 1D), PixelShaderConstantCallback(0)));

    public Point ViewAspect
    {
        get => (Point)GetValue(ViewAspectProperty);
        set => SetValue(ViewAspectProperty, value);
    }

and in Shader.fs:

float2 ViewAspect : register(C0) = float2(1, 1);
sampler2D Input : register(s0);

struct VS_OUTPUT
{
    float4 Position : POSITION;
    float4 Color : COlOR;
    float2 UV : TEXCOORD;
};

float4 main(VS_OUTPUT input) : COlOR
{
  float2 uv = input.UV;  

    uv.x *= ViewAspect.x;
    uv.y *= ViewAspect.y;

    return tex2D(Input, uv);
}

When your render control will change size you need:

        ViewAspectX = ViewWidth > 0 ? FrameWidth / ViewWidth : 1;
        ViewAspectY = ViewHeight > 0 ? FrameHeight / ViewHeight : 1;

where ViewWidth и ViewHeight are sizes of render FrameworkElement, and FrameWidth и FrameHeight are sizes of source image In this way you resize input image without lost quality