Share

Bitmap Gamma and MAXScript

The handling of Bitmap Gamma in MAXScript has been overhauled in 3ds Max 2014 to solve several long-standing issues.

The Past Problems

In versions prior to 3ds Max 2014, MAXScript had limited access to the Gamma settings of the Bitmap Values loaded from files, created by a script, or saved to disk bitmap files in various formats.

Here is a list of some of the problems:

  • When loading a Bitmap Value from a bitmap file, MAXScript had no access to the BitmapInfo describing meta-data including the Gamma.
  • Similarly, when saving a bitmap value to a bitmap file, MAXScript could only provide the file name, but not the relevant meta-data including the actual Gamma loaded from disk.
  • Copying a bitmap value to a new value using MAXScript would set the copied data to linear internally.
  • Since MAXScript does not support the saving of a bitmap value loaded from a bitmap file, a copy of the bitmap value has to be created before saving, but because of the previous issue with copying bitmap values, the gamma was changed implicitly.
  • The .gamma property of the MAXScript bitmap value attempted to represent both the loading and saving gamma, which was incorrect or misleading in many cases.
  • Access to pixel data via the getPixels() function was always working with the raw data and had no way to respect the Gamma settings.
  • Similarly, the compareBitmaps() function would produce false when comparing a JPG (which loads with a gamma of 2.2) to its own copy with would have a gamma of 1.0.

To solve the above issues, MAXScript was extended in 3ds Max 2014 to let scripts properly handle the Gamma of Bitmap Values.

In all cases, the additions have been implemented as extensions, in other words old scripts will remain syntactically correct.

Gamma Modes - Auto, Override and Default

In 3ds Max 2014 and higher, the Gamma of a Bitmap Value can be controlled in three ways - as #auto , #default or an override.

  • #auto is the new, intelligent mode. It uses the file information when present, or intelligently chooses gamma based on whether the file is Floating point or not. This is the default behavior.
  • If gamma is an override, an actual floating point value is used.
  • #default is actually the old legacy mode which only exists for completeness and for loading old files.

The following extensions have been implemented:

The openBitmap() function now accepts an optional gamma: keyword argument, so you can say

FOR EXAMPLE:

a = openBitmap "test.jpg" gamma:#auto -- auto mode 
b = openBitmap "test.exr" gamma:1.0 -- an override

Similarly, the bitmap save() method has been extended with an optional gamma: keyword, so you can say:

save a gamma:#auto -- auto mode 
save b gamma:1.0 -- an override

In addition, the save() function now provides a metadata: optional keyword which can be used to pass the dialog settings acquired from the various bitmap filename picking functions - SelectSaveBitmap() , getBitmapSaveFilename() and getBitmapOpenFilename() . See further on this page for details.

If you render to a file using the render() function, you can also set the Gamma using the optional gamma: keyword:

FOR EXAMPLE:

render filename:"something.exr" gamma:#auto -- auto mode 
render filename:"somotherthing.jpg" gamma:1.0 -- an override

New and Modified Bitmap Value Gamma Properties

The existing .gamma property has been modified to represent the ACTUAL gamma of the bitmap. In the past, it confused output and input gamma into one parameter, which was problematic.

For this reason, two new properties have been added to explicitly address the input gamma, and how that gamma was obtained:

.inputGamma will inform you of the gamma of the file that was loaded. It will return either #auto, #default or the override value. This can be used to display e.g. where the gamma info comes from. It can also be used to make sure to save a bitmap the same as it was loaded, for example.

.inputGammaValue just returns the actual value that was used, e.g. for #auto it would return 1.0 or 2.2 depending on file type, for #default it would return 2.2, and for an override it returns the override value.

Bitmap File Open and Save Dialogs Meta-Data Access

Features have been added to the MAXScript bitmap file dialogs to return as an optional by-reference output parameters the Gamma values, as well as the dialog's setup data.

When these optional parameters are used, the gamma options are visible and work. When they are not used, the Gamma options will be grayed out in the file dialog.

The functions that have been extended are:

getBitmapOpenFilename()
getBitmapSaveFilename() 
SelectSaveBitmap()

In each one of these functions, an optional keyword argument gamma: can refer to a by-reference variable that will return #auto , #default or a numeric value:

FOR EXAMPLE:

x = SelectSaveBitmap caption:"Select a file" gamma:&gma

If the function returns successfully, the variable 'gma' will contain the gamma value from the dialog.

Similarly, bitmap Save dialogs can return the meta-data stored by the "Setup" button, by requesting it via the metadata: by-reference optional argument:

FOR EXAMPLE:

x = SelectSaveBitmap caption:"Select a file" gamma:&gma metadata:&data

Upon success, the 'gma' variable will contain the gamma, and the 'data' variable will contain an array of data stored by the bitmap plugin. This data can then be used in bitmap save operations, for example:

bitmap.filename = SelectSaveBitmap caption:"Select a file" gamma:&gma metadata:&data
if (bitmap.filename) do save bitmap gamma:gma metadata:data

Pixels Access - Linear vs. Raw

The function getPixels() have been extended with the optional linear: boolean parameter:

FOR EXAMPLE:

a = openBitmap "hello.jpg" gamma:#auto --this will set gamma to 2.2
p = getPixels a [0,0] 50 linear:true  --get the linear pixel values (gamma 1.0)
p[1].r *= 2.0 --make first pixel twice as red...

The following example script goes through all Bitmap Textures and if they are set to #default (legacy mode), changes the Gamma to an override of 2.2.

Note that you cannot change the Gamma of a bitmap value (this gets burned in when loading it), but you can simply re-load it with the new Gamma from the original source file.

SCRIPT:

for tmap in (getClassInstances BitmapTexture) where (tmap.bitmap.inputGamma == #default) do 
  tmap.bitmap = openBitmap tmap.bitmap.filename gamma:2.2

Was this information helpful?