locked
Custom Image Resampling RRS feed

  • Question

  • Is there a way to supply a custom scaling mode (resizing algorithm) to an Image in C# / WPF?

    I'm attempting to draw a high contrast image (imagine a black background with a series of narrow vertical white lines) that I wish to be resizable up to a maximum of screen size whilst maintaining the high contrast details (vertical lines).

    Currently I am using a WriteableBitmap constructed with Width and Height equal to screen resolution. The high contrast image is produced at this resolution so displaying it full screen is pixel perfect.

    However, upon shrinking the image, artifacts of the various BitmapScalingModes become evident:

    NearestNeighbour - This preserves the amplitudes of the vertical lines (as desired) but obviously vertical lines can be lost completely
    Linear - More of the vertical lines are visible but some are of reduced amplitude due to the filter mask applied.
    Fant - This produces the most consistent results, all lines are observable with similar (but reduced form the original) amplitude

    Upon reading up on the Fant resampling algorithm, it appears to be very close to what I desire. Each output pixel is influenced by ALL input pixels in a region of interest (versus 2x2 for Linear / 4x4 for Bicubic).

    Ideally I would want a BitmapScaleMode that is 'MaxOfRegion'. Using the same source region of interest as the Fant resampling algorithm it would return the maximum value instead of a centre weighted average of this region.

    So yeah, any ideas of how I could extend/override/hack! the existing BitmapScaleModes?
    Wednesday, January 20, 2010 3:37 AM

Answers

  • There's no way to manipulate or extend the resampling modes that I'm aware of; the implementations are all buried deep in our rendering stack.  Since you're already using a WriteableBitmap, the only idea I have is to write the resampling code yourself in C#.  Like you state, your WB when created at the Width and Height of the screen looks correct.  You could implement the scaling of the image yourself, instead of just using a RenderTransform, by creating WriteableBitmaps at each intermediate size needed for display instead and writing your own resampling algorithm to read from your full-size WriteableBitmap and write into the smaller ones.  You would probably also want to ensure you snap your images positions to integral values (or use UseLayoutRounding="true" in 4.0 to achieve that) and probably turn NearestNeighbor sampling on since you want to ensure there's no subsequent interpolation on resampling beyond what you're doing yourself.
    Wednesday, January 20, 2010 7:50 PM

All replies

  • There's no way to manipulate or extend the resampling modes that I'm aware of; the implementations are all buried deep in our rendering stack.  Since you're already using a WriteableBitmap, the only idea I have is to write the resampling code yourself in C#.  Like you state, your WB when created at the Width and Height of the screen looks correct.  You could implement the scaling of the image yourself, instead of just using a RenderTransform, by creating WriteableBitmaps at each intermediate size needed for display instead and writing your own resampling algorithm to read from your full-size WriteableBitmap and write into the smaller ones.  You would probably also want to ensure you snap your images positions to integral values (or use UseLayoutRounding="true" in 4.0 to achieve that) and probably turn NearestNeighbor sampling on since you want to ensure there's no subsequent interpolation on resampling beyond what you're doing yourself.
    Wednesday, January 20, 2010 7:50 PM
  • Thanks for the response Brendan,

    The solution you have proposed does seem to be the only practical option. I had hoped to extend the BitmapScalingMode infrastructure mostly for performance and code complexity reasons. But I think with the integration of the Intel Performance Primitives libraries I should be able to come up with a reasonably fast resampler.
    Thursday, January 21, 2010 2:43 AM