Login
 

Atalasoft Imaging SDK Development Blog

Document Imaging and Developer Commentary

Blog Home RSS Feed Old Archive Atalasoft.com

Quick – take a look at this excerpt from a Dr. Seuss book:









 

ligatures

 

I took this picture with my phone shortly after reading with my son and found this page particularly jarring.  Like many technologies, automated type came from a hand-driven process.  Writing used to be hand done until Gutenberg and then after, it’s been a continual struggle to get technology to be able to create something that can be done by a talented calligrapher.  In this case, the problem is ligatures.  Ligatures are sets of glyphs that are tied together (ligated) by their shapes.  They are necessary because they improve the appearance and readability of a document.  Here is a pretty good blog entry on ligatures.

Now look back at the Seuss.  Here’s what I saw immediately (and I am not a typographer):

ffiflff

which are all pairs which should be replaced with an equivalent ligature.  In particular, the fl is bad because of the f just barely touching the l and in the ffi, the dot from the i is almost but not quite hitting the second f.  It feels off to me.

I first encountered ligatures while I was working on Adobe Acrobat version 1.0.  I was assigned the task of “fixing” the built-in find tool, which as it stood could find a single word in the document and no more.  I built it up to handle phrases and text that was perhaps on a curve (which made maps searchable).  Working on this tool taught me about ligatures because, for example, that ffi in the document was represented by a single character which may or may not bear any relation to the actual glyph.  So the text consuming code had to internally undo the text encoding and then undo the ligature expanding it to something that could be matched, but it had to keep the mapping so that we understood that three characters in the search key might not map to three glyphs on the page for highlighting.  It was interesting and as a result my eye has been trained to spot ligatures, or more precisely to spot when ligatures are not there.

Here is what the above text looks like with ligatures in place – I approximated the font.  It’s not quite right, but it’s close enough so you can see the difference

ligatures

ligatureswith

 

And to its credit, Photoshop did the ligatures for me as I typed in the text.  I’m glad that another engineer has had an eye for this detail. I can’t wait for this to be better supported on the web.  Chrome, Firefox and Safari appear to have support for it on Windows, but not Internet Explorer.

Posted: 5/10/2013 11:26:31 AM by Steve Hawley | with 0 comments


Software engineering is funny.  It shares a lot with Computer Science (which honestly, should be called applied mathematics) and it shares some things with other engineering disciplines.  With other engineering disciplines, it shares the need for clear processes for planning projects, managing work, ensuring quality, and handling defects.  I say that it shares the need because not every shop actually does all of these things and there is certainly no one good standard for any of these.  This is an industry problem.

One of the many nice things about being married to a real engineer is that I get to hear a lot about engineering and manufacturing process and one of the things I’ve heard her (and other engineers) talk about is FMEA: Failure Mode and Effects Analysis.  This is process whereby a component can be analyzed for failure and severity or probability of failure can be reduced or eliminated.  This is what I thought of when one of my LCD monitors failed.

We believe that engineers work better when there is more screen real estate available to them.  We also believe that an investment in a good pair of monitors will pay off in terms of other resources saved.  For example, our office supply sales representative asked us in all honesty if we were buying our paper from another source, since we go through very little paper (but a great deal of coffee).  We purchased a fair number of these LCD monitors from a well-known consumer electronics manufacturer.  In a few years, they started failing.  In the past 6 months we have had 4 fail.  Every single monitor failed in exactly the same way: the display went blank and the power light went off.  After a brief pause, the monitor started back up again.  The frequency of failures increase until the monitor fails to work at all.  This to me screams of being a very analog problem, probably power related.  To date, 68% of our monitors failed this way.

I contacted the manufacturer of these monitors to find out if there are replacement parts available, hoping that they would have an FMEA put together with this device that would pick out the likely culprit.  I received worse than no help from the manufacturer, but Elaine will talk in more detail from a support point of view about what they did wrong and how they could’ve done it right.

Since I’m alone in this I chose to ignore the manufacturer's lawyers. 

image

By the way – unlike this manufacturer, I’m going to say that if you’re deciding to do this, you should understand the risks. Power supplies in electronic devices can have components that will hold onto a charge long after they’ve been shut off. If you’re uncomfortable doing something like rewiring parts of your house, listen to your discomfort and don’t do this since the charge in a typical power supply cap can give you a nice burn or stop your heart. You know, bad things if you’re not appropriately careful.

I took the monitor apart and looked over the various boards to see if anything obvious was out of kilter and here’s what I found:

image

There are three of these capacitors on the board used to drive the CCFL that is used as a backlight to the LCD display.  If you look at the top of the cap, you can see it bulging up.  This is a sign that this part is failing or has failed.  The manufacturer either used the cheapest caps they could find or used underrated parts or both (or heck, even something else).  The point is that all three of the capacitors on this board look like this, and I would expect a large consumer electronics manufacturer to know about this, to admit to it, and to have a well-defined process for managing it, as well as to have fixed the problem in later revisions (and I can tell you that the manufacturing dates indicate on our devices that they likely did nothing of the sort).

Unfortunately, this part isn’t well-marked so I can’t tell you what the capacitance or the rating are, but taking a guess, this particular part probably cost them a few cents in quantity, whereas a higher quality part would have cost roughly 10 cents in quantity.  So someone looked at the design and chose an off-brand manufacturer for the part in order to save 25 cents on the assembly.

The actual cost of this problem was probably far higher in terms of in-warrantee repairs.  Sadly, the most costly loss to this manufacturer is in terms of customer loyalty.  I had a CRT from the same manufacturer that I used for 10 years before replacing it with a smaller footprint, less power-hungry LCD.  That CRT looked every bit as good on the last day as it did on the first day.  The shoddy quality of these LCD devices and the especially poor customer service is such that I will never purchase another product from this manufacturer again and if I have a say in the matter, I will strongly discourage anyone I know or work for from purchasing their products.

By comparison, I have a workstation made by another well-known consumer electronics manufacturer on my desk which I use for my day-to-day work.  The computer shut down without warning.  We reported this to the manufacturer and even though it was out of warrantee, they sent us a replacement motherboard and power supply which arrived the very next day.  When we replaced the board, we noted that the bad motherboard had several capacitors that were bulged up.  The replacement motherboard had caps made by a different manufacturer.

And while a desktop workstation is a different beast than a monitor, the desktop manufacturer demonstrated that the proper way to handle this type of problem is with alacrity not with incompetence.

Posted: 2/19/2013 2:41:27 PM by Steve Hawley | with 0 comments


One of the things that I admire in solid programmers is laziness.  Some programmers will go to extreme lengths to avoid doing certain classes of work and frankly, I can’t blame them really.  For example, if you need to have a set of look up tables in code from some specification, you could just pull of the spec and start typing in the tables.  A clever programmer will look at the task and start asking the following questions:

  1. How much typing will each entry in the table take (and by extension, how long will the whole task take)?
  2. How many mistakes will I make just typing?
  3. How long will it take to find all of them?
  4. How long will it take to fix all of them?
  5. How irate will my customers get because of 3 and 4?

When 1 gets measured in any units greater than ‘minutes’ and 3 gets measured in units of days to years, a very clever programmer will also ask, “how can I automate this?”

This week I was looking at creating a number of tables (22 in all), each of which had somewhere around 200 entries in them.  That’s around 4000-4800 entries to type in.  Yuck.  That’s easily 3 days of typing and the number of mistakes would probably be about 10%, which would easily be another day to catch 95% of those errors and weeks for the rest.

Enter the robot.

First trick, look at your source data and see if you can easily parse it.  For example, I needed to parse Adobe Font Metrics files and the spec is blissfully simple.  It’s mostly a collection of one key/value pair per line as well as a set of separately subsection with differently formatted key/value pairs, several per line.  In this case, I decided to put reflection to work for me, since all of the keys overlapped the set of names allowed in .NET object properties.  On top of that, the tokenization can be done with String.Split().  I’m already on board.  Here’s the guts of the parsing code:


while (true)
{
    string line = reader.ReadLine();
    if (line == null)
        break;
    string[] pieces = line.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
    if (pieces.Length == 0)
        continue;
    string delimeter = pieces[0];
    switch (delimeter)
    {
        case "StartCharMetrics":
            ParseCharMetrics(metrics, reader, GetInteger(pieces[1]));
            break;
        default:
            SetProperty(metrics, delimeter, pieces);
            break;
    }
    if (line == null)
        break;
}

SetProperty is very simple – it just looks for a property named by delimeter with a setter and when it finds it type coerces the string value to the property type and sets it.  Most of the conversion is done with System.Convert, which is easy.

For the main AFM file, I project the data onto an object that looks like this:


class GlobalFontMetrics
{
    public string FontName { get; set; }
    public string FullName { get; set; }
    public string FamilyName { get; set; }
    public string Weight { get; set; }
    public double[] FontBBox { get; set; }
    public string Version { get; set; }
    public string Notice { get; set; }
    public string EncodingScheme { get; set; }
    public int MappingScheme { get; set; }
    public int EscChar { get; set; }
    public string CharacterSet { get; set; }
    public int Characters { get; set; }
    public bool IsBaseFont { get; set; }
    public double[] VVector { get; set; }
    public bool IsFixedV { get; set; }
    public double CapHeight { get; set; }
    public double Ascender { get; set; }
    public double Descender { get; set; }
    public double StdHW { get; set; }
    public double StdVW { get; set; }
    public double XHeight { get; set; }
}

Now, all of this code is scaffolded into my unit tests and the output of each test is one or more .cs file containing code that constructs the tables from the AFM data. These source files are then added into the main project – but not automatically.

Now, suppose that you have source data that isn’t quite so easy to parse as AFM files.  In my case I needed to build encoding tables for the various supported standard encodings in PDF, including StandardEncoding, MacRomanEncoding, and WinAnsiEncoding.  These are listed out in the spec as tables.  Fortunately, I could copy them within Acrobat and then paste them into Excel.  From Excel, I ran a set of functions that transformed the data into abbreviated lists that I could use and then was able to turn that into C# with a handful of regular expressions.  This is not as ideal as the tables are not as easily reproducible, but hopefully this won’t have to be done again.

All in all, the code and Excel chicanery took me two days to implement, verify, and unit test, far less than just typing in the tables and I’m far more confident that the data is correct.

Posted: 1/30/2013 1:18:03 PM by Steve Hawley | with 0 comments


If you’ve written software to manipulate large chunks of data, you’ve likely created temporary files to hold the data for you. And if you’re like me, your machine currently has 2587 files in your personal Temp folder. Why? Chances are there are a ton of apps on your system that are Doing It Wrong. I’m going to talk about how most apps do this, how it goes horribly wrong, and what you can do to mitigate this problem for your own code.

Most apps will get the path to the Temp folder and run a loop creating files based on time stamp or time stamp followed by iteration until they succeed in making a new file. This path (or stream) gets used in the application in some manner and at some point in the future it will get removed. And you can bet that it’s the last step where applications screw up – they don’t (or can’t) clean up after themselves.

If you’re using Path.GetTempFileName(), stop. Seriously. Just stop using it. It’s not appropriate. It tries to create a file in the form tmpXXXX.tmp, where XXXX is a 4 digit hex number. This is not appropriate for a couple reasons. First, in my own folder, there are currently 2516 files that match that pattern. In other words, 2516/65536 or 3.8% of the files are already in use and I swear I cleaned out that folder a couple months ago. In short order, it will fill up. Further, every nth call will take longer, as the first n-1 tries to make the file will fail. On top of that, there is no infrastructure to take care of the temporary file when you’re done with it. The developer is responsible for removing it and we know how well developers remember to do things.

This is a resource problem: a limited number of slots and responsibility to get and release the resource is in the hands of the developer. When you approach this as a resource problem, it becomes a whole lot harder to screw up.

So let’s set a few goals for this task. This code should be:

  • Easy to use
  • Hard to screw up
  • Customizable
  • Better than Path.GetTemporaryFile()

So let’s start with a TemporaryFile object. This is what is going to hold your information about the temporary file. There are a number of ways this could be structured to be more flexible (like a template base class wherein subclasses could be any Stream instead of a FileStream), but it’s called TemporaryFile not TemporaryStream, so let’s keep it simple. Here is TemporaryFile:


    public class TemporaryFile : IDisposable
    {
        public TemporaryFile(string path)
        {
            if (path == null)
                throw new ArgumentNullException("path");
            Path = path;
            TemporaryStream = new FileStream(path, FileMode.Create);
        }

        public Stream TemporaryStream { get; private set; }
        public string Path { get; private set; }
        public override string ToString()
        {
            return Path;
        }

        private bool _disposed = false;
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    TemporaryStream.Dispose();

                    File.Delete(Path);
                }
                _disposed = true;
            }
        }

        ~TemporaryFile()
        {
            Dispose(false);
        }
    }

In this case, I chose to make the class itself immutable and Disposable. As it stands you could use this class as a wrapper around the result from Path.GetTemporaryFile(), but we’ll do better than that. Remember that TemporaryFile is a resource and if that’s the case, it should be IDisposable. We want to do something very specific when the file is closed.  So following the pattern in IDisposable Made E-Z, I’ve made this class do a few things: open the file on construction and on disposal dispose the TemporaryStream and delete the path. According to the spec for Stream.Close(), it is not necessary to call Close() but to instead ensure that Stream.Dispose() gets called. If either Stream.Dispose() or File.Delete() throw an exception, you probably have worse problems on your hands. If you wanted you could add an implementation of Equals and GetHashCode. I chose not to since pointer equality should be good enough.

Where possible, TemporaryFile objects should be scoped within a using() block to ensure they get disposed in a timely manner, otherwise you have to pray that the GC will help you out at the end of app life.

We’re not done yet – as mentioned before, Path.GetTempFileName() gets worse the more you use it. We can fix that too. Also the filenames it generates are not so good in that we can’t fingerprint them as our own so that we can check at a glance that we’re leaking temp files or better yet, write a unit test to take care of them. So how do you make a TemporaryFile? Use a factory:


    public class TemporaryFileFactory
    {
        protected static string kDefaultPrefix = "Tmp";
        protected static string kDefaultSuffix = "";
        protected static string kDefaultExtension = "tmp";
        protected static int kDefaultRetries = 10;

        public static TemporaryFile MakeTemporaryFile(string extension) { return new TemporaryFileFactory(null, null, null, extension, kDefaultRetries).MakeTemporaryFile(); }

        public TemporaryFileFactory(string tempFolder, string prefix, string suffix, string extension, int retries)
        {
            if (retries <= 0) throw new ArgumentOutOfRangeException("retries");
            Retries = retries;
            TempFolder = String.IsNullOrEmpty(tempFolder) ? Path.GetTempPath() : tempFolder;
            if (!Directory.Exists(TempFolder))
                throw new IOException(String.Format("Temporary folder '{0}' does not exist", tempFolder));
            Prefix = String.IsNullOrEmpty(prefix) ? kDefaultPrefix : prefix;
            Suffix = suffix ?? kDefaultSuffix;
            Extension = SanitizeExtension(extension ?? kDefaultExtension);
        }

        private string SanitizeExtension(string ext)
        {
            if (ext.EndsWith("."))
                ext = ext.Substring(0, ext.Length - 1);
            if (ext.StartsWith("."))
                ext = ext.Substring(1);
            if (ext.Length == 0)
                ext = kDefaultExtension;
            return ext;
        }

        public string TempFolder { get; private set; }
        public string Prefix { get; private set; }
        public string Suffix { get; private set; }
        public string Extension { get; private set; }
        public int Retries { get; private set; }

        public TemporaryFile MakeTemporaryFile()
        {
            for (int i = 0; i < Retries; i++)
            {
                string path = GenerateTemporaryPath(i);
                if (!File.Exists(path))
                    return new TemporaryFile(path);
            }
            throw new IOException(String.Format("Unable to create temporary file in {0} after {1} {2}.", TempFolder, Retries, (Retries == 1 ? "try" : "tries")));
        }

        protected const string kDefaultFormat = "{0}{1}{2}.{3}";
        protected virtual string GenerateTemporaryPath(int retry)
        {
            Guid g = Guid.NewGuid();
            string newPath = Path.Combine(TempFolder, String.Format(kDefaultFormat, Prefix, g.ToString("N"), Suffix, Extension));
            return newPath;
        }
    }

In this case, we’re making the factory easy to use if you don’t care about the file name format and easy to customize if you do. The first thing you should know is that I’m defining the format of a temporary file name this way – <Prefix><content><Suffix>.<Extension>. The defaults are such that you should get Tmp<content>.tmp for your temporary file. There is a main constructor that takes values for Prefix and Suffix and Extension and defaults them if they are null (or in some cases null or empty). The constructor also takes a path to the folder you want to use for temporary files, but you can also set this to null and it will use Path.GetTempPath() instead. The question is, what should go in the <content> part of the file? Why not use a GUID? Just from the definition, I’m fairly certain that I only have to check once to see if the path will exist since the GUID should be unique by definition. Still, GenerateTemporaryPath() was made virtual so you could override if this doesn’t suit your particular needs. GenerateTemporaryPath() includes a retry number, so you could reimplement Path.GetTempFileName if you wanted to (but why?). There’s some basic error checking/patching to mitigate pilot error in SanitizeExtension() and finally a nice static factory method that news up a factory for you with defaults and generates a TemporaryFile for you. Here’s my test code:


        static void Main(string[] args)
        {
            List<string> files = new List<string>();

            try
            {
                for (int i = 0; i < 20; i++)
                {
                    using (TemporaryFile tf = TemporaryFileFactory.MakeTemporaryFile(null))
                    {
                        files.Add(tf.Path);
                        Console.WriteLine("Created " + tf.Path);
                        if (i > 18)
                            throw new Exception("no purpose");
                    }
                }
            }
            catch { }
            finally
            {
                foreach (string path in files)
                {
                    if (File.Exists(path))
                        Console.WriteLine("error - file " + path + " still exist.");
                }
            }
        }

which demonstrates how to make TemporaryFiles using the static factory method within a using and throws an exception for no other reason than to demonstrate the IDisposable does what it says on the box.

From an architecture point of view, this is good enough. It could be slightly cleaner and if I were to make any changes at all, I might put the static factory method(s) inside of TemporaryFile instead of TemporaryFileFactory, then I would call the methods Create(). If I wanted to hide the implementation details of TemporaryFile, I would probably make an interface ITemporaryStream and only put the TemporaryStream property in it. Then if you wanted to use a MemoryStream based factory you could. I think this is poor decision for a few reasons:

  • Temporary files are well established in the art
  • MemoryStreams (or other streams) don’t have the same need for a file deletion as a FileStream and fall outside of our problem domain
  • It would necessitate either a factory for specific file streams
  • Existing code isn’t always .NET Stream compatible (for example, a C library that needs a path)

So you see that by looking at the task as a resource problem rather than a temporary file problem, we can make a solution that is as easy to use and more resilient.

Posted: 1/9/2013 2:09:30 PM by Steve Hawley | with 0 comments


I saw this question on Metafilter about what CS courses are necessary to be a software developer and thought I would take the opportunity to expound a bit.

The first non-useful answer is: all of it.  I went to Oberlin, a college that only grants arts degrees, and received a degree in computer science.  In that time, I also took classes in religion, ethnomusicology, physics, media, anthropology, and so on.  Anything that seemed interesting and I could schedule, I tried to take. I honestly believe in the value of breadth in many things and depth in a few things.  The value is especially apparent in software where solutions frequently need to be tailored to the problem domain and the possible number of domains that can be addressed effectively with software grows daily.  If you know about a wide number of things, you can better tailor solutions to those domains.  Being a lifelong learner makes it easier to learn new problem domains.

The second answer, more useful perhaps, is the following.

An intro class in a high-level language – you’ll probably find classes taught in Java, C#, Python, Ruby, or C++.  My first CS class in college was in Pascal.  If you already know a HLL, it’s still worthwhile, especially if it’s a different language.  In fact, you might want to look at the entire course book to see if all the classes are taught in only one or two languages.  That’s a bad sign, especially for a budding software developer where you should expect to need to learn a new language every few years.  I know more than 20 and it is a career skill to pick up a new one in short order.

A class in algorithms and analysis – this is probably the one that I touch on the most without ever really having to crack a book (I do keep the textbook in my office in case), just for the ability to analyze the best, worst and average cases of code I write.  I have encountered code in the wild that search for the first/next instance of a string in a stream that was O(n!) – easy to spot if you know what to look for.

A class in design patterns – I don’t know if this is in any college curriculum, but when I started my professional career, there weren’t any formal design patterns.  They were informal and maybe differently named from shop-to-shop.  I did discover that many of us had invented the same things just to get a job done and the wise ones abstracted them just enough to be able to apply them in many circumstances while keeping them nimble (for example, I had a tight library that was built around the Visitor pattern which was the basis for an entire UI toolkit.

A class in system architecture – in my day, this was called assembly, but I believe that a good solid understanding of the hardware underneath your computer is key to making good high level decisions as well as making you a far better debugger.  It is also necessary for writing a compiler.

The Scheme/Functional class – if you’re lucky, your department will have a Scheme zealot.  I’ll be honest, I hated Scheme.  I’m a very concrete/practical programmer by nature and Scheme drove me crazy.  Not because I didn’t understand it – I did.  It drove me nuts how fluffy the language was in terms for how it worked and how code I wrote would stall for chunks of time while the garbage collector went to work to get rid of all the things I allocated that I couldn’t prevent.  I swear I was the worst offender of using set! and its variants in my code just to avoid wasting time/memory.  Still, in spite of the structural language deficiencies, it is a fabulous language for getting you to stop thinking about problems sequentially.

A class in compilers – this was my hardest class, I think.  I flunked it.  But it was the most valuable class for learning how to debug a high level language from the lowest level.  You should get to the point where you can look at machine generated assembly language and mentally decompile it into the HLL that made it.  For example, I had a third party library that worked most of the time, but crashed at other times.  It turns out that they were using C enums in size-dependent data structure and their compiler chose one size for the enum and my compiler chose a different size.  Without being able to understand what a compiler would have done with code to operate on structs that contained this enum, I would’ve been dead in the water.  I run into this kind of thing All. The. Time.

A class in operating systems – and by extension, this class should cover concurrency and resource management.  You’re writing code and you’re running it on what now?  You should understand how an operating system works, how to write device drivers, and especially concurrency.  When every machine, including your phone, is shipping with a couple cores, you should understand how to best leverage concurrent programming.

Beyond that, everything else is gravy.  Also consider a writing class of some kind. Clear communication is vital and it is one of the things that I use to pick a new hire.

Posted: 1/7/2013 2:52:47 PM by Steve Hawley | with 0 comments


Syndication

Subscribe

Register to receive our monthly newsletter.
preload preload preload