Skip to content
radfahrer edited this page Sep 12, 2012 · 28 revisions

What is apophnia

Apophnia is a dedicated image server. Designed to solve all of the common image serving problems that are a pain to deal with for anyone that has a large web presence.

Requirements

Image Serving Problems

  • Various sizes of images are needed for various purposes.
  • Various miscellaneous transformations of images are needed for special purposes.
  • Image serving must be fast. An ideal web page will probably serve dozens of images, even with 1 compacted html file.
  • Images should have their own caching rules because how they change is different from the text content.
  • Images need to be dealt with in a way that doesn’t break file systems because of their massive volume.
  • Images should have restful URLs to be saved to disk easily and ready for SEO.

What apophnia tries to achieve:

  • Be able to use new resolutions on the fly.
  • Have these dynamically created images cached.
  • Incur at most a one-time overhead in the process.
  • Have a dedicated image web server or a web server module to do it.

What an apophnia request looks like

  1. Look for myimage_r500x500.jpg.
  2. If not found, back up, try myimage.jpg
  3. See that (_r500x500) is a resize directive
  4. Dynamically resize myimage.jpg to 500×500, serve that image
  5. Save a new file to disk myimage_r500x500.jpg so that when it is requested again … it’s easy

Directives

Supported Directives

  • RESIZE r[HEIGHT(xWIDTH)]
    example myfile_r1000x800.jpg myfile_r400.jpg (creates a 400×400)
  • OFFSET o[HEIGHTxWIDTH [ [p|m] VERTICAL ( [p|m] HORIZONTAL) ]
    Note the syntax is “p” and “m”, not “+” and “-” because of HTML escape sequences
    example myfile_o100x100p100p50.jpg myfile_o400x400m10m40.jpg. It mattes white.
  • QUALITY qINTERGER (0 lowest, 99 highest)
    example myfile_q60.png myfile_q54.jpg
  • NOP _
    example myfile________q60.png myfile__q54.jpg
  • FORMAT if x is specified and doesn’t exist, then seek out other images in the order of y
    • GIF: png, bmp, jpg, jpeg, fail
    • JPG: jpeg, png, bmp, gif, tga, tiff, fail
    • PNG: gif, bmp, jpg, jpeg, tiff, fail
    • JPEG: jpg, png, bmp, gif, tga, tiff, fail
    • BMP: png, jpg, gif, jpeg, fail
      BMP Note: DIB v.5 (Win98/2K+) supports BMP being a container format for both PNG and JPEG images and still being a valid BMP. Since JPEG has no alpha channel and BMP’s alpha channel is the same engine as PNG’s in IE 6, when a BMP is requested it will be a v.5 DIB encapsulated PNG to preserve the space, unless otherwise specified by the true_bmp configuration option.

Proposed Directives

Notes

Chaining

Directives can of course be chained. If you have a file, say, a 2000×2000 file, myfile.bmp then you can do
myfile_r1000x1000_o250x250p250p250_q50.png
Here’s the steps:

  1. myfile_r1000x1000_o250x250p250p250_q50.png is sought out, fails. quality 50 is pushed on the stack. IOCount = 1
  2. myfile_r1000x1000_o250x250p250p250.png fails. 250×250 at offset 250×250 is pushed on the stack. IOCount = 2
  3. myfile_r1000x1000.png fails. resize as 1000×1000 is pushed on the stack. IOCount = 3
  4. myfile.png fails. emit as png is flagged. IOCount = 4
  5. myfile.gif fails … myfile.bmp succeeds. IOCount = 5
  6. myfile.bmp is opened. IOCount = 6
  7. myfile.bmp is resized to 1000×1000
  8. a 250×250 image is extracted at offset 250×250
  9. it is encoded as png with an aggressiveness level of 4 (0-9 is png)
  10. It is served to the client and asynchronously written to disk at myfile_r1000x1000_o250x250p250p250_q50.png IOCount = 7

As you can see, the first time the image is served, it is quite expensive. But now another client will request the same image:
GET /myfile_r1000x1000_o250x250p250p250_q50.png HTTP/1.1

  1. myfile_r1000x1000_o250x250p250p250_q50.png is sought out, found. Served to client.

Much better the second time around, eh?

Configuration File

The config file is called apophnia.conf and is in JSON format.

Supported Options

  • "port": INTEGER – default: 2345
    The port to run apophnia on.
  • "img_root": STRING – default: “./”
    The root directory of images to serve
  • "proportion": ["squash", "crop", "matte", "seamcarve"] – default: squash. If a 200×1000 image is requested at 200×200, then you can either
    • squash: Squash the image disproportionally
    • crop: Center the content and crop the excess pixels
    • matte: Take the 200×1000 image, resize it to 40×200, center it, and matte it on a 200×200 white background
    • seamcarve: See the wikipedia article
  • "true_bmp:" INTEGER (0/1) – default: 0
    Whether to serve a true, uncompressed bmp, or to encapsulate it in a DIB png
  • "log_level": [0 ... 3] – default: 0
    • 0 – log only crashing conditions.
    • 1 – log file creations and updates
    • 2 – log all requests
    • 3 – log as if it’s not a performance hit
  • "log_file": STRING – default: /dev/stdout
    Where the log files go…

Proposed Options

  • "no_support": Array("DIRECTIVE1", "DIRECTIVE2") – default: empty/everything supported
    Example: To disable the quality and resizing directives, you can use "no_support": ["resize", "quality"]