Welcome to Atalasoft Community Sign in | Join | Help

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 represent a pixel.  Mathematically, there are an infinite number of possible pixel formats as color space is as much a space as Cartesian space.  You can create any number of basis sets that map onto any particular color space.  However, only a small subset are actually useful.  In dotImage we represent 12 formats, 3 paletted, 3 gray, and the rest color.

It helps to understand the meaning of pixel formats in terms of quantity of information rather than quality of information.  Having this understanding will help you in avoiding possible problems when processing images or converting from one format to another.

All ImageCommand classes in dotImage advertise a list of all PixelFormats that they operate in.  The property SupportedPixelFormats gives you this list.  You can also call IsPixelFormatSupported() to ask if a specific format is supported.

I would like to say that IsPixelFormatSupported returns true if and only if an ImageCommand natively supports a given PixelFormat.  In most cases this is true, but some older commands (before I got my hands on them) were written to operate on some formats as a convenience, but without letting the caller know.  They still behave exactly as before for compatibility.  ScribbleCommand is an example of this – it will strip out the alpha channel into a temporary image, before performing the operation.

What is true, is that every implementation of SupportedPixelFormats will return the “best” pixel format for the command as the first entry in the list.  This is by convention, but we enforce it strictly.  There’s a reason for this: all ImageCommands have the ability to operate on any pixel format.  This is done by setting the property ApplyToAnyPixelFormat to true.  Then, when the command is executed, if the source image is not in SupportedPixelFormats, the command will create a new version of the image in a better PixelFormat for the command.  This is done internally by the command by calling SelectBestAlternatePixelFormat.  The default implementation is to return the 0th entry in SupportedPixelFormats.

In short, if ApplyToAnyPixelFormat is true, the command will create a new image in the pixel format SupportedPixelFormats[0].  The default value for ApplyToAnyPixelFormat is false.

Wait a minute – this sounds like a tremendously useful feature!  Why would we have it off by default?

There are two reasons: (1) backwards compatibility – where possible we try to assure that all commands in new versions of dotImage operate as they did in the past. (2) “Do No Harm” – changing the PixelFormat of an image may be a lossy operation.  If the amount of information in the source image’s pixel format is greater than the amount of information in the target pixel format, then information has to be discarded in the translation.  How that information is discarded makes all the difference in the world, and the choice that is made should be dependent on the source image domain.  That is, if the image is a photograph, you should use one technique (dithering or another type of halftoning) and if it is a document, you should use another (dynamic or adaptive threshold).

When ApplyToAnyPixelFormat is turned on, ImageCommands will use AtalaImage.GetChangedPixelFormat() to create the new image.  By default (and again, to match legacy behavior), when dotImage reduces a image to 1-bit per pixel, it uses either dithering or color quantization to generate the target image.  This is fine for photographic images, but lousy for documents.  Fortunately, you can change how this change will happen

How can I know if changing a pixel format would be lossy?

You can do that by comparing the number of bits per pixel:

public bool IsPixelFormatChangeLossy(PixelFormat source, PixelFormat target)
{
    return PixelFormatUtilities.BitsPerPixel(source) >
        PixelFormatUtilities.BitsPerPixel(target);
}

and while the accuracy of this predicate is arguable, it will be good enough for most cases.  For the nit pickers, conversion from color to 8 or 16 bpp gray, while lossy is well-defined enough to let it go – although you should be aware that the color conversion is done through a perceptual model, rather than a linear model.  Also, conversions of 24 bit color to 8 bit paletted may be lossless in some cases, but that is more computationally and memory intensive than I’d like to put in such a simple predicate.

As a side node, PixelFormatUtilities is my favorite grab bag of useful functions and predicates based around PixelFormats.  They are akin to the functions in the C routines defined in ctype.h in that they are almost always table driven and operate in constant time.

Posted by Steve Hawley | 0 Comments

When Optimization Pays Off

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil” – Don Knuth

If you are doing image processing, you are firmly in that remaining 3%.  I had some code that I had factored into two major cases: 1 bit per pixel and n bits per pixel (where n is a multiple of 8).  Each chunk of code was more or less parallel in that it did something along the lines of this:

bool PredicateInRow(BYTE *imagePtr, int x, int bytesPerPixel, fPredicate predicate, void *predicateData)
{
    BYTE *pixelPtr = imagePtr + x * bytesPerPixel;
    return predicate(pixelPtr, bytesPerPixel, predicateData);
}
void ProcessRange(BYTE *imagePtr, int height, int width, int bytesPerPixel, int bytesPerRow, fPredicate predicate, void *predicateData)
{
    for (int y=0; y < height; y++) {
        for (int x=0; x < width; x++) {
            if (PredicateInRow(imagePtr, x, bytesPerPixel, predicate, predicateData)) {
                // perform processing
            }
        }
        imagePtr += bytesPerRow;
    }
}

This does some image processing across the whole image based on a predicate using the current pixel’s data.  The predicate has to be vectored out to other code instead of being done inline (technically, there are other ways I can do this, but way of doing it avoids a lot of duplication of effort).  I liked the factoring in that it made the code fairly easy to read, but I knew when I wrote it that I would regret this decision.

After noting that client code of this routine was slower than I preferred it to be, I fired up a profiler and found that PredicateInRow was chewing up a fair amount of the total time and it was being called 50 million times over the comparatively short life of my test application.

I refactored it to this instead:

void ProcessRange(BYTE *imagePtr, int height, int width, int bytesPerPixel, int bytesPerRow, fPredicate predicate, void *predicateData)
{
    for (int y=0; y < height; y++) {
        BYTE *pixelPtr = imagePtr;
        for (int x=0; x < width; x++) {
            if (predicate(pixelPtr, bytesPerPixel, predicateData)) {
                // perform processing
            }
            pixelPtr += bytesPerPixel;
        }
        imagePtr += bytesPerRow;
    }
}

I’ve now lost the PredicateInRow routine, took a hit in readability but the code runs twice as fast now that I eliminated 50 million function calls and 50 million multiplies.

I should note that I tried inlining PredicateInRow which resulted in a negligible increase in performance.  In my actual code, the structure of ProcessRange is much more complex – there are three small state machines that run inside of the y-based for loop and each state machine ended up looking at rows above and below in addition to the current row.  The refactoring was more complicated than the example above, which resulted in two bugs, both of which I found by reading the code closely.

The code of a multiply is tiny, but when you multiply it by 50 million, it becomes significant.  When I wrote this, I knew that the per-pixel accessing was going to slow it down.  Nonetheless, I took the high road of “make it work, then make it fast(er)”.

If need be, I will change the code the work with specific byte per pixel values, removing the predicate call entirely, but that will take a 2x duplication of code (1-bit and n-bit) and turn it into a pentiplication (1 bit, 8 bit, 16 bit, 24 bit, 32 bit)

Posted by Steve Hawley | 0 Comments

Solving Problems, aka, Nobody Codes Like This Anymore

When I was in college, I had a class in machine architecture/assembly language.  At the time that I took it, I knew 6502 already and had published two video games for the Apple II written entirely in assembly.  I love the drunken power of having access to the entire machine and making it do things it wasn’t precisely designed for – so the class was easy to me.  We started off with a fake Von Neumann architecture machine called MANIAC.  MANIAC was a basic accumulator-model machine – not too different from the 6502, so coding for it was familiar ground.

We then transitioned to VAX assembly and were writing code to run directly on the machine.  Compared to the barren wasteland of 6502, VAX was like stepping into Paris.  16 registers?  What the hell am I going to do with them all?  Multiply?  Divide?  Floating point?  SOBGTR (subtract one and branch on greater)?  There was even an instruction to insert into a queue.  Yikes.

In class, the final assignment was to write a program to maintain a family tree.  The program needed to read a line and parse out a set of commands:

  • CREATE name – create a new person named name
  • MARRY name1 name2 – mark persons named name1 and name2 as married
  • CHILD name1 name2 – mark person named name1 as a child of name2
  • GRANDCHILDREN name – prints a list of name’s grandchildren
  • COUSIN name1 name2 – prints TRUE if person named name1 is a cousin of name2

I looked at this task and thought, family tree?  Really?  In assembly?  No.  Wrong approach.

So I first wrote it in Pascal and got it working.  Then I hand compiled each procedure (I didn’t know how compilers worked yet, but I had a pretty good idea).  I noted that many of my peers were struggling with the argument passing in VAX, so I avoided the whole problem and adopted register passing as the protocol where the caller, not the callee was responsible for saving registers.  Every subroutine was clear what it used as arguments and I set aside some registers that were free to be destroyed.

Once I had my “architecture” in place, it was a matter of writing little subroutines that matched the Pascal.  I even included the Pascal in the source as documentation.  The only documentation.  Why would you need more?

It wasn’t without bugs, but it eventually worked just fine and I was done well before most of my peers, even though I technically wrote the program twice.

So, nobody really writes code like this anymore.  Compilers are good enough that unless you doing something like image processing, you don’t really need to drop to the machine level.  That doesn’t mean that we can’t learn something from the process.

This particular problem lent itself to being solved in a particular language domain – Pascal (or your favorite procedural or OOP language).  So much so that writing it in another language was trivial.  It became divide and conquer to factor the tasks out to reasonable pieces: a simple parser, a REPL, a structure definition, and five procedures.  Then I picked a mapping strategy to go from my problem language domain into my solution language domain and followed through on it.  This is still a valid way to solve problems, even though this particular solution language domain is obsolete.  This particular approach is how we end up with domain specific languages and small virtual machines to run them.

Posted by Steve Hawley | 0 Comments

Writing a Composite ImageCommand – Gamma Corrected Resampling

We have a customer who expressed some concern over how our resample command works (and how many similar commands work, in general).  He pointed us to an article here which describes the problem.  The short of it is that the energy in a pixel is an expression of power (Watts) over the area of the pixel and although the scale of the pixel component intensities is represented as linear, it is really exponential.  Averaging a set of power measurements linearly produces results which don’t effectively represent the average power.  The trick is compensate for this is to make the power scale linear by applying an inverse gamma function to the image, then resampling it and finally applying the original gamma function to restore it.

The gamma function looks like this:

pv’ = pvγ

where pv is the normalized value for the channel of a pixel – this means it is a value between 0 and 1 inclusive.  γ is a value > 0, typically 2.2 for most monitors.  So the typical process of converting an 8-bit per channel pixel is something like this:

foreach pixel
   foreach channel
        double normalizedChannel = channel / 255.0;
        double channelPrime = Math.Exp(normalizedChannel, gamma);
        channel = Math.Floor(channelPrime * 255);

DotImage has an ImageCommand for performing this transformation efficiently.  We can do the transformation I’ve described as a sequence of steps, but I thought it would be nice to combine everything into one command.

The first thing to do is to make a subclass of ImageCommand.  ImageCommand is an abstract class which is, more or less the a collection of GoF template methods.  This is to make it easy to implement ImageCommands from scratch.  We’re not doing that – we’re making a composite command.   We’ll implement the abstract methods, but they won’t be needed.  So let’s start off with an outline of what we want:

public class GammaResampleCommand : ImageCommand
{
    GammaCommand _gammaCommand = new GammaCommand();
    ResampleCommand _resampleCommand = new ResampleCommand();
    public GammaResampleCommand()
    {
    }
    public GammaResampleCommand(double gammaLevel, Size destSize, ResampleMethod method)
    {
        GammaLevel = gammaLevel;
       DestSize = destSize;
        Method = method;
    }
    protected override AtalaImage PerformActualCommand(AtalaImage source, AtalaImage dest, System.Drawing.Rectangle imageArea, ref ImageResults results)
    {
        throw new NotImplementedException();
    }
    public override PixelFormat[] SupportedPixelFormats
    {
        get { return _gammaCommand.SupportedPixelFormats; }
    }
    protected override void VerifyProperties(AtalaImage image)
    {
       ImageCommand.ProxyVerifyProperties(_gammaCommand, image);
        ImageCommand.ProxyVerifyProperties(_resampleCommand, image);
    }
    public double GammaLevel
    {
        get { return _gammaCommand.GammaLevel; }
        set { _gammaCommand.GammaLevel = value; }
    }
    public Size DestSize
    {
        get { return _resampleCommand.DestSize; }
        set { _resampleCommand.DestSize = value; }
    }
    public ResampleMethod Method
    {
        get { return _resampleCommand.Method; }
        set { _resampleCommand.Method = value; }
    }
}

You’ll note that rather than implement the properties or VerifyProperties, we’re just acting as a proxy to existing instances of GammaCommand and ResampleCommand.  This means we don’t need to implement error checking on the properties – that will happen for free.  In fact, to implement VerifyProperties, we’re taking advantage of a feature of ImageCommand – ImageCommand has a set of methods named ProxyXXXX, which will call the method XXXX for us, even though it is protected.  This breaks encapsulation, but it is there just for this purpose – creating composite commands.  Finally, you’ll note that PerformActualCommand throws an exception.  That’s OK – we’re going to ensure that it is never called.

What remains is to do the actual work, and for that we’ll override the method Apply().

    public override ImageResults Apply(AtalaImage image)
    {
        using (AtalaImage gammaCorrected = image.Clone() as AtalaImage)
        {
            double gamma = _gammaCommand.GammaLevel;
            double inverseGamma = 1 / gamma;
            GammaLevel = inverseGamma;
            _gammaCommand.Apply(gammaCorrected);
            AtalaImage finalImage = _resampleCommand.Apply(gammaCorrected).Image;
            GammaLevel = gamma;
            _gammaCommand.Apply(finalImage);
            return new ImageResults(finalImage, false);
        }
    }

GammaCommand is InPlaceProcessing = true, which means that it side-effects the source image.  I don’t want this, so I’ll make a copy of the source image using Clone, then apply the inverse gamma to the source, resample it, then apply the normal gamma.

Here is some quick test code for this:

using (AtalaImage image = new AtalaImage(@"..\..\gamma_dalai_lama_gray.jpg"))
{
     GammaResampleCommand resampler = new GammaResampleCommand(2.2,
           new Size(image.Width / 2, image.Height / 2),
           ResampleMethod.LanczosFilter);
     using (AtalaImage smaller = resampler.Apply(image).Image)
     {
         smaller.Save("dalailama.jpg", new JpegEncoder(), null);
     }
}

The input file is this:

 

and the subsequent output is here:

dalailama

Posted by Steve Hawley | 0 Comments

Libpng – You’re Doing It Wrong

I took a three day hiatus from developing DotImage 9.0 to work on an experiment: how would a 100% managed PNG decoder perform, compared to libpng?

Using only C#, I knocked together a very basic chunk of code that has a very strong .NET feel/smell to it to decode PNG images.  Internally, I build a map of the available chunks in the file and then I ask for them by type.  This is different from most PNG consuming code – the spec encourages you to read chunks in possible expected order, which requires a very state machiney layout.  State machines aren’t bad, per se, but they do lead to code that is not always easy to read or maintain.  So instead of waiting for a chunk of the right type to arrive, I just ask for it by name.

For the required zlib compression, I used DotNetZip, in particular the Zlib assembly.  The main reason for this choice was that Ionics implementation is a filter stream.  I give their stream another stream to work with and it will decompress it while I read from it.  This is awesome, because I don’t need to worry about the underlying implementation.

Well, that’s actually a lie.  I do have to worry about it.  PNG allows compressed image data to be spread across multiple PNG chunks in the file.  So I created a ChunkStream that give a stream a List<ChunkDescriptors> that describe where image data chunks reside, it will read/seek through the chunks as needed.

In sum, my reading model for image data is this Stream->ChunkStream->ZLibStream.

So here is my code for decoding a non-interlaced PNG image:

List<ChunkDescriptor> chunks = _chunkMap[ChunkType.IDAT];
ChunkStream chunkstm = new ChunkStream(_stm, chunks);
ZlibStream stm = new ZlibStream(chunkstm, CompressionMode.Decompress);
for (int y = 0; y < Header.Height; y++)
{
    int filter = stm.ReadByte();
    if (filter < 0)
        throw new Exception("unexpected EOF");
    if (!FilterIsValid(filter))
        throw new Exception("invalid filter");
    int count = stm.Read(currLine, 0, bytesPerLine);
    Unfilter(currLine, prevLine, (PngAdaptiveFilter)filter, bytesPerLine);
    OnScanlineRead(new ScanlineEventArgs(y, currLine));
    byte[] temp = prevLine;
    prevLine = currLine;
    currLine = temp;
}

That’s all that it takes – this code is easy to read, easy to maintain, and nicely abstracted.  Do you see the total lack of special case handling?  All that is wrapped up in the stream model and instead, I can concentrate on the decoding.

I did some testing and found that compared with a libpng, this code takes a little less than twice as long.  With some tweaking, I can make it better.  In my case, the bottleneck is not where I expected.  It’s not in I/O.  It’s not in reordering color channels.  It’s not in using an event driven model for reporting scanlines read.  It’s not in mapping out the chunks at the start.  In my particular test case, the bottleneck is the Paeth predictor that was used on the test file to improve compression.

Here is the Paeth predictor as I originally implemented it:

private static int PaethPredictor(int a, int b, int c)
{
    int p = a + b - c;
    int pa = Math.Abs(p - a);
    int pb = Math.Abs(p - b);
    int pc = Math.Abs(p - c);
    if (pa <= pb && pa <= pc)
        return a;
    else if (pb <= pc)
        return b;
    return c;
}

This is very simple code, so it’s hard to imagine how you might make it better.  I took this approach:

private static int PaethPredictor(int a, int b, int c)
{
    int bmc = b - c;
    int pa = bmc < 0 ? -bmc : bmc;
    int amc = a - c;
    int pb = amc < 0 ? -amc : amc;
    int apbmcmc = a + b - c - c;
    int pc = apbmcmc < 0 ? -apbmcmc : apbmcmc;
    if (pa <= Math.Min(pa, pc))
        return a;
    else if (pb <= pc)
        return b;
    return c;
}

I eliminated the calls to Math.Abs, which helps a little.  I also broke apart the expression p which also helped a little bit.  When I say “a little”, I mean that it shaves off maybe a few hundredths of a second.  To read my source image 100 times took 1500ms and after these basic rearrangements, I got it down to 1100ms.  These tiny changes help because the Paeth Predictor gets called 7.5 million times in my test code.  If I inline it (seriously hurting readability), the result is slightly faster.  At this point the pure managed code runs at 1.5x libpng, which is way better than I expected.

I looked at the image decoding in libpng and while the authors clearly went to a great deal of effort to handle errors and special cases and to make the code as readable as possible, ultimately I think they’re doing it wrong.  My code is memory efficient, easy to read, easy to maintain, and will never leak memory

Posted by Steve Hawley | 0 Comments

DataMatrix Described

Saw this great description of Datamatrix encoding via Trivium.

Very good your us visual thinkers.

And if you need it, Atalasoft has tools for both reading and writing Datamatrix 2D barcodes (and other barcodes as well).

Posted by Steve Hawley | 0 Comments

What is /?

I learned something today about the humble slash character: /.

First, let me say that to me, / is always pronounced ‘slash’.  This is due to my first encountering of this character as a path separator in UNIX when I worked at Bell Labs.    The other slash, \, I only knew as back slash.  When I encountered it in DOS paths, I was appalled that people used the name ‘slash’ interchangeably with ‘back slash’ and called ‘/’ ‘forward slash’.  Slash/back slash made sense to me because it fit cleanly with tick/back tick (‘ and ’).

What I learned is that the character that we think of as slash (or forward slash to you heathens) is really called ‘solidus’.

I also found out that the paragraph symbol, ¶, is called ‘pilcrow’ or ‘alinea’.

How about that?

I’ll take “Punctuation Names” for $800, Alex.

Posted by Steve Hawley | 0 Comments

DelegatedImageSource

One common task in working with images is, given a file or a set of files, read in each page, perform some operation on it and write it as a page in a target file.

This is tricky to do out of the box in dotImage in that a lot of the onus of memory management falls onto client code.  The client needs to know how to append images onto a possibly existing file in a way that won’t use up a ton of memory.

Let me give you an example:

TiffDocument doc = new TiffDocument();
for (int i = 0; i < totalPages; i++) {
    AtalaImage page = GetSomePage(i);
    Watermark(page);
    doc.Pages.Add(new TiffPage(page, TiffCompression.Default));
    page.Dispose();
}
doc.Save(someOutputFile);

This is a chunk of code that is meant to loop through some set of pages, watermark each one, add it to a TiffDocument and then save it to a TIFF.  We’re being good in that we’re calling Dispose() on the AtalaImage to let it go.  The problem is that TiffPage allocates memory for the image (in most cases compressed) so if you’re working with a dozen pages or less, you’ll be fine, but if you work with hundreds, you will bring your machine to a crawl.

In thinking about this, I decided that what we needed was a flavor of ImageSource and RandomAccessImageSource that could adapt an existing ImageSource and allow the user to inject code into the process.

To do this, we’ll create a subclass of ImageSource that takes another ImageSource as an argument.  It will let the provided ImageSource do all the heavy lifting, allowing code injection at the appropriate time:

using System;
using Atalasoft.Imaging;
namespace DelegatedImageSource
{
    public class DelegatedImageSource : ImageSource
    {
        Func<AtalaImage, AtalaImage> _imageProc;
        ImageSource _source;
        public DelegatedImageSource(ImageSource source, Func<AtalaImage, AtalaImage> imageProc)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            if (imageProc == null)
                throw new ArgumentNullException("imageProc");
            _imageProc = imageProc;
            _source = source;
        }
        protected override ImageSourceNode LowLevelAcquireNextImage()
        {
            AtalaImage image = _source.AcquireNext();
            AtalaImage processed = _imageProc(image);
            processed = processed ?? image;
            if (processed == image)
            {
                processed = (AtalaImage)image.Clone();
            }
            _source.Release(image);
            return new ImageSourceNode(processed, null);
        }
        protected override void LowLevelDispose()
        {
            _source.Dispose();
        }
        protected override bool LowLevelFlushOnReset()
        {
            return true;
        }
        protected override bool LowLevelHasMoreImages()
        {
            return _source.HasMoreImages();
        }
        protected override void LowLevelReset()
        {
            _source.Reset();
        }
        protected override void LowLevelSkipNextImage()
        {
            _source.Release(_source.AcquireNext());
        }
        protected override int LowLevelTotalImages()
        {
            return _source.TotalImages;
        }
        protected override bool LowLevelTotalImagesKnown()
        {
            return _source.TotalImagesKnown;
        }
    }
}

The main meat of the code is in LowLevelAcquireNextImage, which calls AcquireNext on the provided source, then hands the resulting AtalaImage off to the delegate.  If the delegate returns null or the original image, we return a clone, otherwise we return the image created by user code.

Here is an example snippet which combines a set of images into a single TIFF:

FileSystemImageSource source = new FileSystemImageSource(@"\Images\Documents", "*", true);
DelegatedImageSource dis = new DelegatedImageSource(source,
            (image) => { return null; });
TiffEncoder encoder = new TiffEncoder();
using (FileStream fs = new FileStream("output.tif", FileMode.Create))
{
    encoder.Save(fs, dis, null);
}

which is a sweet little chunk of code to combine image files into one TIFF.  Further, there won’t be the same memory issue as with our naive example because ImageSource handles resource management for you via the Acquire/Release model.  You might ask, “so why do need the TiffDocument class when I can do all the work like this?”  The answer is that when an AtalaImage is created from a TIFF document, the metadata associated with the page (EXIF, etc) is shed.  TiffDocument maintains that information.

Now let’s change our task to be “mark each page with a red X and save as a PDF”.  The code doesn’t change much:

DelegatedImageSource dis = new DelegatedImageSource(source, (image) =>
{
    AtalaImage rgb = null;
    if (image.PixelFormat == PixelFormat.Pixel24bppBgr || image.PixelFormat == PixelFormat.Pixel32bppBgr ||
        image.PixelFormat == PixelFormat.Pixel32bppBgra)
    {
        rgb = image;
    }
    else
    {
        rgb = image.GetChangedPixelFormat(PixelFormat.Pixel24bppBgr);
    }
    using (Graphics g = rgb.GetGraphics())
    {
        using (Pen p = new Pen(Color.Red, 25))
        {
            g.DrawLine(p, 0, 0, rgb.Width, rgb.Height);
            g.DrawLine(p, 0, rgb.Height, rgb.Width, 0);
        }
    }
    return rgb;
});
PdfEncoder encoder = new PdfEncoder();
using (FileStream fs = new FileStream("output.pdf", FileMode.Create))
{
    encoder.Save(fs, dis, null);
}

Note that the save code is identical.  This is because both PdfEncoder and TiffEncoder are MultiFramedEncoder objects which can take an ImageSource in one flavor of Save().

Let’s say that you want instead to overlay a watermark onto each image – the code, again, doesn’t change much:

AtalaImage watermark = new AtalaImage(@"C:\Users\shawley\Pictures\bunny.png");
OverlayCommand overlay = new OverlayCommand(watermark, new Point(20, 20));
overlay.Opacity = 0.50;
overlay.ApplyToAnyPixelFormat = true;
DelegatedImageSource dis = new DelegatedImageSource(source, (image) =>
{
    return overlay.Apply(image).Image;
});
TiffEncoder encoder = new TiffEncoder();
using (FileStream fs = new FileStream("output.tif", FileMode.Create))
{
    encoder.Save(fs, dis, null);
}

In this case, I’m using the captured variable, overlay, to write onto the image, turning the actual watermarking code into a one-liner.

And here, finally, is the same code modified to work specifically for RandomAccessImageSource:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Atalasoft.Imaging;
namespace DelegatedImageSource
{
    public class DelegatedRandomAccessImageSource : RandomAccessImageSource
    {
        Func<AtalaImage, int, AtalaImage> _imageProc;
        RandomAccessImageSource _source;
        public DelegatedRandomAccessImageSource(RandomAccessImageSource source, Func<AtalaImage, int, AtalaImage> imageProc)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            if (imageProc == null)
                throw new ArgumentNullException("imageProc");
            _imageProc = imageProc;
            _source = source;
        }
        protected override ImageSourceNode LowLevelAcquire(int index)
        {
            AtalaImage image = _source[index];
            AtalaImage processed = _imageProc(image, index);
            processed = processed ?? image;
            if (processed == image)
            {
                processed = (AtalaImage)image.Clone();
            }
            _source.Release(image);
            return new ImageSourceNode(image, null);
        }
        protected override ImageSourceNode LowLevelAcquireNextImage()
        {
            AtalaImage image = _source.AcquireNext();
            AtalaImage processed = _imageProc(image, -1);
            processed = processed ?? image;
            if (processed == image)
            {
                processed = (AtalaImage)image.Clone();
            }
            _source.Release(image);
            return new ImageSourceNode(processed, null);
        }
        protected override void LowLevelDispose()
        {
            _source.Dispose();
        }
        protected override bool LowLevelFlushOnReset()
        {
            return true;
        }
        protected override bool LowLevelHasMoreImages()
        {
            return _source.HasMoreImages();
        }
        protected override void LowLevelReset()
        {
            _source.Reset();
        }
        protected override void LowLevelSkipNextImage()
        {
            _source.Release(_source.AcquireNext());
        }
        protected override int LowLevelTotalImages()
        {
            return _source.TotalImages;
        }
    }
}

So we see that by using delegates in tandem with ImageSource objects, we can make repetitive tasks much easier and remove a lot of issues in resource management at the same time.

Posted by Steve Hawley | 1 Comments

Vignettes in DotImage

On Stack Overflow, a user asked how to create vignettes in .NET.  I wrote up this answer, which explains the math and the general approach.

To give you an idea of what this looks like, here is the output of an application which applies the vignette to an image.  This is different from the Stack Overflow answer in that I chose to do this in an ImageRegionCommand from within dotImage.

image

To do this, I created a new class called VignetteCommand, overrode four members and added one utility method.  This command works on 24 bit RGB, 32 bit RGB, and 32 bit RGBA which a limitation imposed by GDI+.  Since this command works by painting on top of an existing image, InPlaceProcessing will be overridden to return true always.  In theory, we could do without, but we’d just be copying the existing image onto the new image, then painting.  We override VerifyProperties to make sure that any user set properties are right. Finally, we override PerformActualCommand to do the actual work.  All the rest of the infrastructure is handled by dotImage.

Here is the code:

 

using System;
using Atalasoft.Imaging;
using Atalasoft.Imaging.ImageProcessing;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace Vignette1
{
    public class VignetteCommand : ImageRegionCommand
    {
        private PixelFormat[] _supportedPixelFormats = new PixelFormat[] {
            PixelFormat.Pixel24bppBgr, PixelFormat.Pixel32bppBgr, PixelFormat.Pixel32bppBgra
        };
        public override PixelFormat[] SupportedPixelFormats { get { return _supportedPixelFormats; } }
        public override bool InPlaceProcessing { get { return true; } }
        protected override void VerifyProperties(AtalaImage image)
        {
            if (Positions == null && Factors == null)
                return;
            if (Positions == null || Factors == null)
                throw new ArgumentException(Positions == null ? "Positions" : "Factors");
            if (Positions.Length != Factors.Length)
                throw new ArgumentException("position and length arrays must be the same length", "Positions");
        }
        protected override AtalaImage PerformActualCommand(AtalaImage source, AtalaImage dest, System.Drawing.Rectangle imageArea, ref ImageResults results)
        {
            using (Graphics g = source.GetGraphics())
            {
                PaintVignette(g, imageArea);
            }
            return null;
        }
        private void PaintVignette(Graphics g, Rectangle bounds)
        {
            Rectangle ellipsebounds = bounds;
            ellipsebounds.Offset(-ellipsebounds.X, -ellipsebounds.Y);
            int x = ellipsebounds.Width - (int)Math.Round(.70712 * ellipsebounds.Width);
            int y = ellipsebounds.Height - (int)Math.Round(.70712 * ellipsebounds.Height);
            ellipsebounds.Inflate(x, y);
            using (GraphicsPath path = new GraphicsPath())
            {
                path.AddEllipse(ellipsebounds);
                using (PathGradientBrush brush = new PathGradientBrush(path))
                {
                    brush.WrapMode = WrapMode.Tile;
                    brush.CenterColor = Color.FromArgb(0, 0, 0, 0);
                    brush.SurroundColors = new Color[] { Color.FromArgb(255, 0, 0, 0) };
                    Blend blend = new Blend();
                    float[] positions = Positions;
                    float[] factors = Factors;
                    if (positions == null || factors == null)
                    {
                        positions = new float[] { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0F };
                        factors = new float[] { 0.0f, 0.25f, 0.5f, 0.75f, 1.0f, 1.0f };
                    }
                    blend.Positions = positions;
                    blend.Factors = factors;
                    brush.Blend = blend;
                    Region oldClip = g.Clip;
                    g.Clip = new Region(bounds);
                    g.FillRectangle(brush, ellipsebounds);
                    g.Clip = oldClip;
                }
            }
        }
        public float[] Positions { get; set; }
        public float[] Factors { get; set; }
    }
}
Posted by Steve Hawley | 0 Comments

The Elements of Programming Style

Many years ago, I had the pleasure of working at Murray Hill Bell Labs.  My job, of all things, was making violins, but that’s a story for another time.  My office was in section D of the 5th floor of building 2, which was also where the UNIX room was.  I learned a lot from looking at the code written by the creators of C and UNIX.

It is terrific to watch Brian Kernighan giving this talk about clarity in code.  A lot of what he shows as bad examples are grist for the mill of the Daily WTF and such sites.  And while I don’t always meet all of the goals of clarity (who does?), I do try to write things so that they can be read.

That’s one of the reasons why I was so pleased when Rick showed me his hill climbing code before he wrote his blog article: it’s beautiful code.  It reads like a textbook algorithm.  Nice job, Rick.

Posted by Steve Hawley | 0 Comments

Support Cases and Mourning

I was thinking about how I handle support cases, and it tickled me that I often follow the Kübler-Ross model of grief, although I prefer the steps outlined by Dr. Hibbert in “The Deadly Blowfish”:

   Dr. H: Now, a little death anxiety is normal.  You can expect to go through
          five stages.  The first is denial.
   Homer: No way!  Because I'm not dying! [hugs Marge]
   Dr. H: The second is anger.
   Homer: Why you little! [steps towards Dr. H]
   Dr. H: After that comes fear.
   Homer: What's after fear?  What's after fear? [cringes]
   Dr. H: Bargaining.
   Homer: Doc, you gotta get me out of this!  I'll make it worth your while!
   Dr. H: Finally, acceptance.
   Homer: Well, we all gotta go sometime.
   Dr. H: Mr. Simpson, your progress astounds me.

 

Denial

“No way!  Because I fixed that bug.  The customer is wrong.”

Anger

“Gah!  This is keeping me from my work!”

Fear

“What if this bug is deeper than it appears?”

Bargaining

“If I can come up with a workaround, they’ll be happy with that, right?”

Acceptance

“Oh well, I’ll put in the fix.”

Posted by Steve Hawley | 1 Comments

More Property Wants – Polymorphic Set

I was writing some property heavy code and I realized that if I can write this code:

public void SetFoo(int x) { }
public void SetFoo(double y) { }
public void SetFoo(Rational z) { }

then I really want to have this syntax:

public int Foo {
    get { /* ... */ }
    set { /* ... */ }
    set (double) { /* ... */ }
    set {Rational) { /* ... */ }
}

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }Because they’re the same, really.

In addition, I was to also see PropertyInfo.IsAssignableFrom(Type t) (although IsSettableFrom is better wording, the former matched the Type.IsAssignableFrom method) so that I can figure out from reflection if a set would throw.

Posted by Steve Hawley | 0 Comments

RC4 in C#

I was working on a project this week that required some RC4 (SARC, ARC4, ARCFOUR) encryption.  In looking around, I didn’t find a public version that I liked, so working from Wikipedia, I created my own.  This version is in C# and I tried to build it so that it is efficient enough, but maximized usability.  Therefore, there are interfaces for byte arrays (immutable and not), Streams, and IEnumerable<byte>.  The code is not thread safe, so use a different instance in any thread that needs it.

Feel free to use the code as your needs and jurisdiction allow.

// This source code is property of Atalasoft, Inc. (www.atalasoft.com)
// No warrantees expressed or implied.
// You are free to use this in your own code, provided that you
// leave this notice in place.

// Change History:
// December 11, 2009 - Initial version, Steve Hawley

using System;
using System.Collections.Generic;
using System.IO;

namespace Atalasoft
{
    public class Rc4
    {
        private byte[] _S;
        int _x, _y;

        public Rc4()
        {
        }

        public Rc4(byte[] key)
            : this(key, key.Length)
        {
        }

        public Rc4(byte[] key, int length)
        {
            SetKey(key, length);
        }

        public void SetKey(byte[] key)
        {
            SetKey(key, key.Length);
        }

        public void SetKey(byte[] key, int length)
        {
            if (_S == null)
                _S = new byte[256];

            if (key == null)
                throw new ArgumentNullException("key");
            if (length < 1 || length > key.Length)
                throw new ArgumentOutOfRangeException("length");

            for (int i = 0; i < 256; i++)
                _S[i] = (byte)i;
            for (int i = 0, j = 0; i < 256; i++)
            {
                j = (j + key[i % length] + _S[i]) & 0xff;
                byte temp = _S[i];
                _S[i] = _S[j];
                _S[j] = temp;
            }
            Reset();
        }

        public void Reset()
        {
            _x = _y = 0;
        }

        private byte GetNextMask()
        {
            _x = (_x + 1) & 0xff;
            _y = (_y + _S[_x]) & 0xff;
            byte temp = _S[_x];
            _S[_x] = _S[_y];
            _S[_y] = temp;
            return _S[(_S[_x] + _S[_y]) & 0xff];
        }

        public IEnumerable<byte> Process(IEnumerable<byte> data)
        {
            if (data == null)
                throw new ArgumentNullException("data");
            if (_S == null)
                throw new Exception("Need to call SetKey before calling Process");

            foreach (byte b in data)
                yield return (byte)(b ^ GetNextMask());
        }

        public void ProcessInPlace(byte[] data)
        {
            ProcessInPlace(data, 0, data.Length);
        }

        public void ProcessInPlace(byte[] data, int index, int length)
        {
            if (data == null)
                throw new ArgumentNullException("data");
            if (_S == null)
                throw new Exception("Need to call SetKey before calling ProcessInPlace");
            if (index < 0 || index >= data.Length)
                throw new ArgumentOutOfRangeException("index");
            if (length <= 0 || index + length > data.Length)
                throw new ArgumentOutOfRangeException("length");

            for (int i = 0; i < length; i++)
                data[i + index] = (byte)(data[i + index] ^ GetNextMask());
        }

        public byte[] Process(byte[] data)
        {
            return Process(data, 0, data.Length);
        }

        public byte[] Process(byte[] data, int index, int length)
        {
            if (data == null)
                throw new ArgumentNullException("data");
            if (_S == null)
                throw new Exception("Need to call SetKey before calling Process");
            if (index < 0 || index >= data.Length)
                throw new ArgumentOutOfRangeException("index");
            if (length <= 0 || index + length > data.Length)
                throw new ArgumentOutOfRangeException("length");

            byte[] output = new byte[length];

            for (int i = 0; i < length; i++)
                output[i] = (byte)(data[i + index] ^ GetNextMask());
            return output;
        }

        public void Process(Stream data, Stream output)
        {
            if (_S == null)
                throw new Exception("Need to call SetKey before calling Process");
            int databyte;
            while ((databyte = data.ReadByte()) >= 0)
                output.WriteByte((byte)(databyte ^ GetNextMask()));
        }

        public void Process(Stream data, Stream output, long length)
        {
            if (length <= 0 || data.Position + length > data.Length)
                throw new ArgumentOutOfRangeException("length");
            if (_S == null)
                throw new Exception("Need to call SetKey before calling Process");

            for (long i = 0; i < length; i++)
            {
                int databyte = data.ReadByte();
                if (databyte < 0)
                    throw new EndOfStreamException("unexpected end of stream processing RC4");
                output.WriteByte((byte)(databyte ^ GetNextMask()));
            }
        }
    }
}
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
Posted by Steve Hawley | 0 Comments

Awesome Support

If you’ve had an issue with one of our products or attended a webinar, chances are you’ve spoken with Elaine.  She is the head of support and works with Kevin to help you, our customers, do what you need to do.  I’m very impressed at how well Elaine works with the people that call in.  At various points, I have worked the support lines and I know that I just don’t do that job nearly as well.  I have a great deal of respect for people who do with alacrity what I cannot.

Elaine carries her support outside of the office as well.  In September, she signed up to help raise money for the Massachusetts Down Syndrome Congress, and played goalie in a hockey game against (retired) Boston Bruins.  This is the second time she has done this, but the first time that she was in the net against the Bruins (in the previous game, she was “traded” for the Bruins goalie to balance things a bit).

Here is a picture of Elaine at work:

elainegoaliethe Bruins were rough on her.  She made some good saves, but they scored pretty heavily – just as you might expect pro players to do on any amateur.  I’m deeply, deeply proud of Elaine for doing this event.  The team raised over $40,000 for the MDSC, and a lot of people got to see her working hard on the ice.  Unfortunately, the power in the arena went out just before the end of the first period, so the game was called.

aliceskating

And while I don’t usually talk about personal issues on my professional blog, I’m doubly proud of her because my older child, Alice, has Down syndrome.  The MDSC has done a great deal to help educate my family and my extended family.  Without their resources, I don’t think that we would have the tools to manage the present or have so hopeful a view of the future for her.  Stepping up and getting involved in this event speaks volumes for her caring and commitment, and I appreciate it greatly.

Posted by Steve Hawley | 0 Comments

A Few Neat Things – Finding Your Way Around

When I was 12, my local PBS station broadcast a program that forever changed the way that I saw science, technology, and history.  It was the show Connections, written and hosted by James Burke.  For me, it was the way that history was no longer presented as a function of time, but as a function of change and influence.  He traced the effects of technological changes especially how they enable more and more technologies.

I thought of that when I was watching this TED talk about the astrolabe.  The astrolabe was an early form of celestial computer that could be used for navigation, surveying, and time keeping.  That reminded me of an episode of connections that covered the challenges of ballistics and surveying, which includes the development of the theodoliteThis is a 10 minute segment from the video – take the time to watch it.

Now compare the ProFORMA project, which using a web cam alone can build a 3D model of a shape in front of a web cam.  The tasks are very similar and a lot of the math will be the same.

Posted by Steve Hawley | 0 Comments
More Posts Next page »