Mercantilism

As usual, I was more delayed than warranted with the No Gnus t-shirts. But today! It’s packing time.

Carrying the shirts up to the fourth floor was kinda invigorating.  I.e., woe is me.

Using magical Japanese folding techniques…

Quality entertainment.  (Jeepers Creepers 1 & 2, which I bought because Joss Whedon said they were great on the Cabin in the Woods commentary track.  They weren’t.)

But alcohol helps!

My view for a few hours…

Stacks are a-toppling.

Our model is here sporting the new style while looking very pensive.  Possibly spotting something on the ceiling?

The complicated back shot. Must have been strenuous, what with the mouth breathing?

Anyway, they should be off tomorrow!  If I can get up in time.

Kanpai!

Lyrical

I was out at a show on Friday, and had a few beers, and then suddenly I was home, and I was listening to Xiu Xiu’s version of Fast Car, and I really had to know what the lyrics were.

And before you know it, I had won around fifteen new iPhone 5s from various lyrics sites.

So yesterday I thought there should be a way to display lyrics in Emacs without winning any iPhones, so I went looking for APIs.  First I did MusixMatch before discovering that they only returned 30% of the lyrics.

Lyric Wiki seemed more promising, although heavy on iPhone winnings.  The API doesn’t return much, but I cheated.

The world should be safe now.

Mercantilism

The September t-shirts were finally ready yesterday, so I picked them up today, along with stamps, envelopes, rum, ginger beer, DVDs and other things necessary for packing stuff.

The number of shirts wasn’t enormous (just 30 or 40 or something), so carrying them up the stairs was no problem.

The Norwegian postage system changed since the last time I did this, which has to be more than five years ago.  Using big envelopes is like 2x more expensive than smaller ones…

So I used magical Japanese folding techniques to fold the shirts into the allowed size.

Quality entertainment is necessary when doing repetetive tasks.

Look at all those envelopes!  Gotta love plastics.

And here we see our model modelling the shirt in the traditional Internet manner.  I hope I got all the details right.  Directing is so challenging.

Displaying Animated Images With ImageMagick

The Internet Is Made For Cats

I’ve spent the day adding support for animated GIFs to Emacs via ImageMagick.  Emacs c
an display animated GIFs already, of course, but not via ImageMagick, so we couldn’t scale animated images.  Which is awkward.

An animated GIF is (basically) just a bunch of images in one blob.  However, the “complicated” thing is that all subsequent images may have transparencies.  So to compute image X, you have to unpack image 1 to X, and apply the non-transparent bits in each iteration.  Apparently.

Most of the work was googling around for how to do this, so to spare other people the same pain, I’m posting the (abbreviated) code here.

The weird indentation is because this is from the Emacs source.

To make this usable, you should also add caching so that you don’t have to compute all the overlays every time.

static MagickWand *
imagemagick_compute_animated_image (MagickWand *super_wand, int ino)
{
  int i;
  MagickWand *composite_wand;
  size_t dest_width, dest_height;

  MagickSetIteratorIndex (super_wand, 0);
  composite_wand = MagickGetImage (super_wand);

  dest_width = MagickGetImageWidth (composite_wand);
  dest_height = MagickGetImageHeight (composite_wand);

  for (i = 1; i <= ino; i++)
    {
      MagickWand *sub_wand;
      PixelIterator *source_iterator, *dest_iterator;
      PixelWand **source, **dest;
      size_t source_width, source_height;
      ssize_t source_left, source_top;
      MagickPixelPacket pixel;
      DisposeType dispose;
      int lines = 0;

      MagickSetIteratorIndex (super_wand, i);
      sub_wand = MagickGetImage (super_wand);

      MagickGetImagePage (sub_wand, &source_width, &source_height,
                          &source_left, &source_top);

      dispose = MagickGetImageDispose (sub_wand);

      source_iterator = NewPixelIterator (sub_wand);
      dest_iterator = NewPixelIterator (composite_wand);

      /* The sub-image may not start at origo, so move the destination
         iterator to where the sub-image should start. */
      if (source_top > 0)
        {
          PixelSetIteratorRow (dest_iterator, source_top);
          lines = source_top;
        }

      while ((source = PixelGetNextIteratorRow (source_iterator, &source_width))
             != NULL)
        {
          int x;

          /* Sanity check.  This shouldn’t happen, but apparently
             does in some pictures.  */
          if (++lines >= dest_height)
            break;

          dest = PixelGetNextIteratorRow (dest_iterator, &dest_width);
          for (x = 0; x < source_width; x++)
            {
              /* Sanity check.  This shouldn’t happen, but apparently
                 also does in some pictures.  */
              if (x + source_left > dest_width)
                break;
              /* Normally we only copy over non-transparent pixels,
                 but if the disposal method is “Background”, then we
                 copy over all pixels.  */
              if (dispose == BackgroundDispose ||
                  PixelGetAlpha (source[x]))
                {
                  PixelGetMagickColor (source[x], &pixel);
                  PixelSetMagickColor (dest[x + source_left], &pixel);
                }
            }
          PixelSyncIterator(dest_iterator);
        }

      DestroyPixelIterator (source_iterator);
      DestroyPixelIterator (dest_iterator);
      DestroyMagickWand (sub_wand);
    }

  return composite_wand;
}