Welcome to Atalasoft Community Sign in | Join | Help

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

Photo Geekery – What To Do With a Dead DVD Drive

A few months back, I saw an article about adding macro capability to cell phone cameras.  I asked Jay, our IT know-it-all if we had any dead drives.  Last week, I got my greedy hands on one and while working on a support case with Elaine, I took it apart and pulled the lens:

cameralens In the drive I took apart, there were two sets of optics.  I tried both and took the larger of the two, which worked better with my cell phone.  This lens has convenient ears that can be used for holding it into the camera with tape, but I just used my fingernail.

Here is a shot of the DVD drive’s front panel circuit board using the unmodded camera (click for full image):

IMAGE_112 It’s OK.  Not great – the camera has a special '”close up” setting and this is about as close as I could get it and stay marginally in focus.

This is shot with the DVD lens over the camera lens:

IMAGE_113 I can now get that chip very clearly in focus.  According to the spec of that chip, the long edge of the chip is a minimum of 4.9mm and a max of 5.0mm.  This means that the field of view in the close-up shot is approximately 18mm x 12.5mm.  In the non-macro shot, the chip appears roughly 1/4 the size, making the field of view 72mm x 50mm.  So the lens adds a nice, cheap 4x for close up work.

But there is a part two to this and a reason why I took a shot of this particular chip on the DVD front panel UI board.  This chip is a stereo headphone amplifier that runs from 3V to 6V (ideally at 5).  Being able to read the chip ID, let me find the data sheet which tells me what the pins are.  If I hack the board down (a la this instructable), solder in a battery clip (anywhere from 2-4 AA batteries will work fine.  The instructable uses a 9V battery with a 5V regulator.  This will work, but is a waste of time – this chip is good up to 6V.  If it were good up to 5V, I’d use 3 AA batteries) and a 1/4” jack, I will now have a guitar headphone amplifier.  I don’t need to add a volume control – it already has one.  And if I choose to use a stereo 1/4 jack, I can use that as a power switch by wiring the negative terminal of the battery connector to the ground of the jack and the non-tip connector of the jack to the ground connection on the board.  There is even an existing LED waiting to be used as a power indicator.

Posted by Steve Hawley | 0 Comments

Loving Your Customers

Very often in this blog, I complain about things that aren’t right.  There’s a certain amount of squeaky wheel in the hopes that things will get better and a certain amount of hope that my readers (all 3 of you) will also register your dissatisfaction.  That’s one way that things will get better.

Another way is to compliment and laud those who are doing things right, and ultimately I think this is the best approach.

I am the father of two children and as such have to deal with the packaging in toys.  Let me give the other parents here a moment to settle through your collective shudder.  I am an engineer and a geek and as a child I got really good at taking things apart and putting them back together again (and still having them work at the end, or start working again when they weren’t before).  I’m sad to say that I no longer have the time to disassemble every electronic device I own.  There was a point, up until I was 22, I think, that I could say with confidence that I had opened up every piece of portable/personal electronics I had just to see what made it tick.

So on Christmas morning during toymageddon, I make sure that I have a pair of dikes handy as well as utility scissors to handle the packaging.  I can usually make quick work of opening the toys, but it’s getting harder, especially with my two year-old son who does the dance of impatience and anticipation and doesn’t want to keep his fingers out of the way.

I understand the goal behind current toy packaging trends.  Companies want the toys to be as exposed as possible to allow a level of try-before-buy and yet be relatively impervious to theft.  I think this is a stupid trend.  It factors in more cost to make all toys demoable instead of allowing the stores the means to present one unit and keep the others boxed with less packaging.  While the wall of Elmos has a certain twisted appeal to me:

 

my personal entertainment is not sufficient incentive to keep packaging items this way.

In steps Amazon.com with Certified Frustration Free Packaging.  To which, I say about effing time, especially for things that are purchased online.  I think it’s great that Amazon is working with its partners to make the packaging simpler and to cut overhead.  I’ll be happier when it stops being an edge case and starts being the norm.

Posted by Steve Hawley | 0 Comments

Building Image Unit Tests

Atalasoft makes heavy use on unit testing in our development.  While we don’t follow the strict regimen of writing the test first, we do write the tests in close conjunction with code being developed.  Similarly, we try for every bug report to have a unit test that reproduces it.

As a result, we also have a tremendously large (and growing) image database that includes both in and out of spec images for testing.

Sometimes you just want a small image with particular contents and it can be a hassle to make these sample images (think MS Paint at full magnification).  Instead, I decided to put together a little chunk of code to do that for me:

AtalaImage FromStringArray(string[] bits);

before I go into the implementation (and I will), let me show you the typical usage (pulled from a unit test)":

string[] im = new string[] {
    "################",
    "+++++++++++++++#",
    "##############+#",
    "#++++++++++++#+#",
    "#+##########+#+#",
    "#+#++++++++#+#+#",
    "#+#+######+#+#+#",
    "#+#+#+#++#+#+#+#",
    "#+#+#+#++#+#+#+#",
    "#+#+#+####+#+#+#",
    "#+#+#++++++#+#+#",
    "#+#+########+#+#",
    "#+#++++++++++#+#",
    "#+############+#",
    "#++++++++++++++#",
    "################",
};
AtalaImage image = FromStringArray(im);

This chunk of code will take the array of strings and create a 1 bit AtalaImage with every + representing a white pixel and every # representing a black pixel.  And before you can say “Holy ASCII art, Batman!” we have a simple way of authoring small images for doing highly specific tests.

The process is simple – find the dimensions of the target image, construct it, then fill in the pixels.

    AtalaImage FromStringArray(string[] bits)
    {
        int height = bits.Length;
        int width = bits[0].Length;
        AtalaImage image = new AtalaImage(width, height, PixelFormat.Pixel1bppIndexed);
        for (int y = 0; y < height; y++)
        {
            string s = bits[y];
            for (int x = 0; x < Math.Min(s.Length, width); x++)
            {
                if (s[x] == '+')
                {
                    SetPixel(image, x, y, false);
                }
                else if (s[x] == '#')
                {
                    SetPixel(image, x, y, true);
                }
                else
                {
                    Assert.Fail();
                }
            }
        }
        return image;
    }

There are a couple of points to note – I assume the width of the image is the width of the first string.  From there on out, for each string I only scan up to the lesser of the width the given string.  This lets the unit test author be a little sloppy in the strings, but it may result it images that are clipped if the first string is particularly short.  This laissez-faire approach is at odds with the Assert.Fail() if an unrecognized character is in the string.  I don’t particularly like that philosophical inconsistency, but so be it.  One could also argue that the better approach to getting the width is to instead use the maximum length of all the strings or to fail if they’re not all the same length.

In addition, you’ll see that I’m specifically NOT using AtalaImage.SetPixelColor().  I could – and that wouldn’t be so bad, but SetPixelColor does have a certain amount of overhead, and I also like to keep my PixelAccessor skills up to date, so I wrote a version:

    byte[] _bits = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 };
    void SetPixel(AtalaImage image, int x, int y, bool set)
    {
        if (image.PixelFormat != PixelFormat.Pixel1bppIndexed)
            Assert.Fail();
        using (PixelAccessor pa = image.PixelMemory.AcquirePixelAccessor())
        {
            byte[] row = pa.AcquireScanline(y);
            int index = x >> 3;
            if (set)
            {
                row[index] |= _bits[(x & 7)];
            }
            else
            {
                row[index] &= (byte)~_bits[(x & 7)];
            }
            pa.ReleaseScanline();
        }
    }

This is a fairly low overhead way to set pixels in a 1-bit image.  Of course, it is not production code – there is no range checking on x and y (AcquireScanline will throw and the array access will throw) and the code doesn’t use the colors in the image’s palette to determine whether it should set or clear the pixel.  This code will work with the default palette (which is the problem domain), but not with the most general cases.  All of these cases are handled by SetPixelColor.

If nothing else, this is a lesson in what not to do and why, but again in this problem domain I think it’s useful to see how one could implement SetPixel using the tools built into dotImage.

In my case, I’m doing some research code which involves a lot of funny edge cases which can be broken out in unit tests much more easily with this tool than otherwise.  It also keeps the source images immune to changes in either images or codecs, which can be very handy.

Posted by Steve Hawley | 0 Comments

Clean Up Day

I’ve been working on a bunch of applied research projects that I would love to talk about – but you know the nature of the game: I have to keep these under wraps.

Whenever I do work of this nature that isn’t necessarily for general consumption, I keep in in My Documents in the Visual Studio project folder where it was created by default.  I also am more careful about my backups.  For backups, I use Macrium Reflect, which has performed admirably.  I should consider getting the full version that does incremental backups, but since I don’t, it means that every backup image includes all the obj files and assemblies that are kicking around my projects.  I was about to start on an app to do that work, but a quick trip to CodeProject turned up a tool to specifically clean up Visual Studio workspaces.  Hooray!  I built it, ran it and lopped of 7G of space hanging around doing nothing.

Posted by Steve Hawley | 0 Comments

How To: Host a Bacon Day

DSC00002

 

Christina put up a blog entry about the historical/social aspects of Bacon Day at Atalasoft.  I’m going to give you a guide for hosting your own Bacon Day.

For Bacon Day you ultimately need three things: good bacon, good people, and a means to cook, but it also takes some basic organization, so here is a guide to help you out.

At least one week in advance, you should do the following:

  1. Get a headcount – this is very important.
  2. Get a list of volunteers for side items and avoid replication – don’t overdo it: bacon, eggs and a choice of one or two starchy items is plenty.
  3. Order bacon, allowing between 4 and 6 ounces (110-170 grams) uncooked bacon per person.  Arrange the arrival day for at least one day before the scheduled bacon day.  Ordering earlier allows cheaper shipping.
    • Note – you don’t need to order bacon, per se.  Be aware that there’s bacon and then there’s bacon.  Most of what you will find in a typical supermarket is bacon in name only.  For Bacon Day at Atalasoft, we have ordered from Burgers’ Smokehouse.  To date, they have been very responsive, reliable, and have shipped terrific quality bacon on time.  We have been satisfied in every way with their business and wouldn’t hesitate to purchase from them in the future.  We typically get a sampler pack of country bacon to let people try different styles of bacon.  Pepper bacon was the most popular with maple bacon running a close second.  I think everyone preferred thick cut over thin cut.

At least two days in advance, you should do the following:

  1. Arrange for eggs to be purchased (if that’s part of your menu) – allow two eggs per head.
  2. Arrange for a griddle, two is ideal
  3. Remind the side item providers
  4. Get at least two volunteers to help clean up

On Bacon Day, you will need:

  1. Bacon
  2. Eggs/other sides
  3. Paper towels
  4. Clean plates
  5. Clean utensils
  6. One or more empty mason jars for grease
  7. Fire extinguisher – just in case.

Tips:

  1. Start the griddles no later than 8:45, 8:30 is ideal.  Good bacon takes time.
  2. Empty the grease traps frequently.
  3. Smile, it’s bacon day!
  4. Take pictures.
  5. Cooks: wash your hands frequently.

Notes:

We used two griddles set to 300F.  We each cooked two packages of bacon (12 ounces), then one cook switched to eggs, cooking them in the bacon grease.  While cooking, I recruited people to make labels for the plates so that people would be able to put a name to what they were eating.  Be sure to ask people how they like their bacon.  I like mine a little chewier – some heathenspeople prefer their bacon extra crunchy.  Part of Bacon Day is a celebration of tastes – cater to other people’s tastes when you can.

Posted by Steve Hawley | 1 Comments

Language Underbelly

For the past week and a half, I’ve been implementing a scripting language as part of some R&D work.  It’s always exciting to make the puppet dance, as it were.  Implementing the language was far easier than in the past as this time around I have generics and lambda expressions at my fingertips.

Languages are funny beasts because there are three goals that are often at odds with each other:

  • Language Purity – how self-consistent is the language and semantically pure is it?
  • Language Pragmatism – how does the language fare when it is used for practical problems?
  • Language Reality – how does the language fare in the reality of oddball hardware and interoperating with legacy systems?

Here is an article that talks about some of the hidden features of C that are in gcc and are leveraged by the Linux kernel.

In most cases, they are handled through macros which, if the underlying option is unavailable, can be set to no-ops or some other equivalent mechanism, but these to me are scary changes as they represent a serious break in language portability.

Where these cases happen there is a conflict between Language Reality and Language Purity.  The use of, for example, the likely() and unlikely() macros are a hack to help the optimizer understand when a branch is more likely to be taken or not, which can help significantly in optimization.  That’s fairly benign as these things go.

Worse are things like ranges in case expressions in switch statements, which will break any other compiler than gcc.  This is dangerous because it inexorably ties Linux to the gcc feature set and not the C feature set.

Historically, the keyword register is a conflict between Language Purity and Language Pragmatism.  Register declarations are a way to hint to the compiler that a particular variable should end up in a register (hopefully for performance).  It has come to pass, however, that the register keyword is pretty much ignored by current compilers.  This is a lesson in short sightedness: avoid adding keywords to your language to solve a short term problem when they adversely affect the language in the long term.

The rub is that while Language Purity is important, languages that are pragmatic don’t get used and die an early death.

Perl is the most prominent example of a language that gave itself over to pragmatics and reality and has nearly no purity.  It the main reason why I feel dirty after I’ve written in Perl.

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