Welcome to Atalasoft Community Sign in | Help

Replaceable Image Format Conversion

In working on the 4.0 version of dotImage, I've added the ability to change how all images are converted from one pixel format to another.  I thought I'd post a quick entry to show how this will work in the upcoming release.  If you're interested in trying this out, be sure to get involved in our Beta program.

In order to implement this, I created a class called PixelFormatChanger, which contains one public method for changing an image to another pixel format.  It also defines a protected abstract method for doing the actual work.

The public method handles all the error conditions before handing the image off to the concrete implementation.

AtalaImage now has a static property called PixelFormatChanger which is used by all of dotImage to do pixel format changes.  You can take advantage of this by installing your own version to replace our defaults mechanisms.

Now, to do this properly, it's a big job.  There are 12 pixel formats that should be convertible to each other.  That's 132 possible conversions (12 x 12 = 144, less the 12 identity conversions that are considered illegal), which, trust me, is a lot of typing.

I'm going to show you how you can create a custom PixelFormatChanger that replaces only a portion of the possible conversions, but uses the defaults otherwise.

I'll start with the actual changer:

using System;
using Atalasoft.Imaging;
using Atalasoft.Imaging.ImageProcessing.Document;

namespace PixelFormatReplacement
    public class ThresholdPixelChanger : PixelFormatChanger
        private AdaptiveThresholdCommand _threshold;
        private PixelFormatChanger _originalChanger;

        public ThresholdPixelChanger(PixelFormatChanger originalChanger)
            // we need an original changer to handle things
            // that we can't do.
            if (originalChanger == null)
                throw new ArgumentNullException("originalChanger",
                    "ThresholdPixelChanger requires a base pixel format changer");
            _originalChanger = originalChanger;
            _threshold = new AdaptiveThresholdCommand();

        protected override AtalaImage LowLevelChangePixelFormat(AtalaImage sourceImage,
            PixelFormat targetPixelFormat,
            Atalasoft.Imaging.ColorManagement.ColorProfile destProfile)
            // if the target pixel format is not 1 bit or
            // if the thresholding command doesn't support the
            // source image pixel format, just pass it on
            if (targetPixelFormat != PixelFormat.Pixel1bppIndexed ||
                return _originalChanger.ChangePixelFormat(sourceImage, targetPixelFormat, destProfile);

            // apply the threshold command to the
            // source image, are return the resulting image
            return _threshold.Apply(sourceImage).Image;

        public PixelFormatChanger OriginalChanger { get { return _originalChanger; } }

In this code, the constructor takes a copy of the original PixelFormatChanger and holds on to it.  In this way, we can call its methods to implement what we can't handle.  Note that instead of assuming what the threshold command can handle, I'm letting it tell me via the IsPixelFormatSupported() method.  This will let me change the threshold command without breaking any code.

Essentially, if we're not going to black and white and we can't handle the pixel format, we kick it back to the older command.

So why didn't I just subclass the existing AtalaPixelFormatChanger and override what I wanted and then call base.LowLevelChangePixelFormat() ?  I could have, but I lose flexibility.  In this code, I can override behavior of any exisiting PixelFormatChanger, including those written by outside vendors or any future versions created by Atalasoft.  Using inheritance ties me to one particular base class.

Here's a test rig to try it out:
using System;
using System.IO;
using Atalasoft.Imaging;
using Atalasoft.Imaging.Codec;

namespace PixelFormatReplacement
    class Class1
        static void Main(string[] args)
            // try the built-in pixel format changer
            AtalaImage originalPicture = new AtalaImage("atalapic.jpg");
            AtalaImage originalChangedImage = originalPicture.GetChangedPixelFormat(PixelFormat.Pixel1bppIndexed);
            SaveImage(originalChangedImage, "originalChangedImage.gif");

            // install our new pixel format changer
            ThresholdPixelChanger changer = new ThresholdPixelChanger(AtalaImage.PixelFormatChanger);
            if (changer == null)
                throw new Exception("Couldn't create pixel changer.");
            AtalaImage.PixelFormatChanger = changer;

            // run it.
            AtalaImage thresholdChangedImage = originalPicture.GetChangedPixelFormat(PixelFormat.Pixel1bppIndexed);
            SaveImage(thresholdChangedImage, "thresholdChangedImage.gif");

        private static void SaveImage(AtalaImage image, string filename)
            FileStream stm = new FileStream(filename, FileMode.Create);
            GifEncoder encoder = new GifEncoder();
            encoder.Save(stm, image, null);

And here is the output.

Original Image:

Default conversion to bitonal:

Thresholded replacement:

This capability should prove itself quite handy.  In the upcoming release, nearly all of our image processing commands will have the ability to operate on any pixel format image, but with conversion.  Now the client can have a say as to how this should be done.
Published Monday, June 05, 2006 5:04 PM by Steve Hawley


Tuesday, March 16, 2010 11:53 AM by Steve's Tech Talk

# Why It Helps to Understand Pixel Formats

A pixel format in dotImage is a description of the depth, color space and layout of the memory used to

Anonymous comments are disabled