Gamma-correcting bitmap-members

or

How to save 50 Euro using lingo?

 

Table of contents

Gamma-correction with Lingo instead of the faster FilterFactory...

My first thought was to use the FilterFactory to build a useful gamma-correction tool. But the FF unfortunately doesn't have the mathematical functions implemented that are necessary for this. Another alternative would be a commercial Xtra, for example the Gamma-Xtra offered by http://www.magisterludi.com/xtras/gammaxtra.html for the price of 50 Euro. By using the getpixel/setpixel-commands of Director 8, there's a third way to do it - coding it in lingo.

First a few words concerning this "gamma"-issue:

 

What does 'gamma' mean?

The gamma-equation looks like this:

y = x power (1 / gamma)

It is basically a mathematical function that is used to approximately describe the brightness-distribution from pure black (with x = 0) to pure white (with x = 1) of a standard monitor. The value for x is the "input" - the signal strength that the monitor recieves from the Mac/PC, the value for y is the brightness that is produced by the monitor in reality. A linear gradient from black to white is therefore perceived brighter in the mid-gray areas when displayed on a monitor (gamma usually about 2.2 to 2.5) than on a printed sheet. To compensate for this hardware characteristic, gamma correction is available in Photoshop for example and even in some operating systems. The gamma-correction does not change the white or black areas in an image, just how the gray values are distributed between them..

Roughly speaking, a gamma of
0...1 darkens an image
> 1 brightens an image
= 1 does not change anything
< 0 is not at all useful ;-)

More in-depth information about gamma can be found here:
ftp://ftp.igd.fhg.de//pub/doc/colour/GammaFAQ.pdf
ftp://ftp.igd.fhg.de//pub/doc/colour/ColorFAQ.pdf
(Note: You may have to manually set your ftp-transfer mode to "binary")

 

Are Macintosh-monitors brighter than PC-monitors?

It is sometimes read in newsgroups that Mac monitors are "set" or "adjusted" brighter than PC monitors, which causes problems in the designer-client workflow. This is of course not the case, as a monitor connected to a Mac displays the same black than a PC monitor (if it were set too bright, the black would become a dark gray). Additionally, if the very same monitor is connected to a Mac and a PC without touching any of the monitor's dials, the picture is brighter when connected to the Mac. The reason for this is built into the deepest levels of the Macintosh operating system, into the so-called "QuickDraw"-layer, which is among other purposes responsible for transfering the image data to the monitor outlet. TheQuickDraw-system routines themselves apply a consistent gamma correction of about 1.4 to all output-signals (independent of any control panel settings or installed system extensions) - the monitor therefore displays an image brighter than the same image is displayed by a PC.

To correct for this, a designer working on a Mac cannot simply turn down the brightness setting of his monitor, as this just tunes the white level down to some light gray, but does not influence the distribution of luminance throughout the range from black to white. So if the client or the designer wants to have an optimal appearance of the design elements both on a Mac and a PC, there are only two alternatives:

  1. choosing a medium gamma, which is displayed a bit too dark on a Mac and a bit too light on a PC
  2. create two versions of the design, one optimized for each platform...

In any case, a subsequent gamma correction can be necessary, and I wanted to implement this with lingo.

 

Gamma-correcting 16 and 32 bit members

In Director 8, the "getpixel()"-function returns a color object of the type #rgb when used on 16- or 32-bit bitmaps:

put getPixel(someMemberImageObject,x,y)
-- rgb(255,255,255)

So to implement a gamma correction, one just has to read each pixel's color with the "getpixel()"-function, apply the necessary math to this color and write it back into the same pixel using "setpixel()".

A complete lingo handler that does this looks like this:

on gammaCorrection gamma, m

  -- m: castmember to apply correction to

  invGamma = 1/float(gamma)

  reScale = 255/power(255,invGamma)
  -- this is needed to obtain result values
  -- ranging from 0...255 from the formula

  h = member(m).height - 1
  w = member(m).width - 1
  img = member(m).image

  repeat with y = 0 to h
    repeat with x = 0 to w

      origRGB = img.getpixel(x,y)
      origRGB.colorType = #rgb
      -- if the bitmap is using a palette

      corrRed = integer(power(origRGB.red, invGamma)*reScale)
      corrGreen = integer(power(origRGB.green,invGamma)*reScale)
      corrBlue = integer(power(origRGB.blue, invGamma)*reScale)
      -- calculate the 3 colors separately, as a "power(rgb(...),invGamma)"
      -- causes a runtime error ("wrong type")

      img.setpixel(x,y,rgb(corrRed, corrGreen, corrBlue))

    end repeat
  end repeat

  member(m).image = img

end

 

Here's an example of a gradient bitmap (member 1, colordepth 32 Bits) when typing

gammaCorrection 1.8, 1

into the message window:

Bitmap (linear gradient) before

Bitmap after gamma-correction with 1.8

Black and white pixels remain unchanged, just the mid-gray pixels are lightened.

 

Gamma-correcting 8 bit and less (palette-indexed bitmaps)

IMPORTANT! If you're planning to call the "gammaCorrection"-handler with an indexed bitmap, you have to switch the movie palette (in the "movie properties"-window) to the palette of the bitmap member!

The reason for this is that using the "setpixel()"-command there's no way of passing the target palette, to which the color (index or rgb) should be mapped. Director always uses the movie-palette for this. After the handler was executed, the movie palette can be switched back of course.

For colordepths of 8 Bits or less, the above "gammaCorrection"-handler can produce awful results! This is due to the fact that only colors which are present in the palette can be used to render the corrected bitmap. This can look ok, but it can also look plain ugly! Two examples to demonstrate this point are shown here:

Example 1 uses the 216 colors websafe-palette, the result is not pretty but acceptable:

Bitmap vorher Bitmap nach Korrektur mit Gamma = 2

 

Example 2 uses a 32 color custom-palette, the result is plain useless:

Bitmap before Bitmap after correction with gamma = 2

(the 32 palette colors)

A solution for this dilemma is to export the palette itself, use a tool like DeBeblizer to adjust the gamma of the palette colors and then to re-import the palette, pasting it over the old one in the Director cast. This way, all bitmap members that use the palette are corrected at once.

 

Comments, suggestions and critique regarding this article are welcome, please send them to:

Joachim Baur | medienwerkstatt | grafik-design