Author Topic: Image.fill() accepts a signed number  (Read 7414 times)

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Image.fill() accepts a signed number
« on: 2007 October 09 10:15:43 »
Hi mates,

I've just discovered that Image.fill() counterintuitively accepts a signed number as its parameter:

Code: [Select]
When the value is      The image appears
----------------------------------------
-32769                 Black
-32768                 Gray (0.5000 in the normalized range)
-16384                 Gray (0.2500)
-1                     Almost black (0.00002, I had to modify the Readout options to see the 5th decimal)
0                      Black
1                      White
16384                  Gray (0.7500)
32768                  Gray (0.5000)
32769                  Black
65536                  Still black (doesn't begin again from 32768)


I guess that a value of 0 would be black and 65535 (in my 16-bit image) would be white. Is this a bug? Furthermore, is there a way to get a white without knowing the image's bit depth?
--
 David Serrano

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Image.fill() accepts a signed number
« Reply #1 on: 2007 October 09 11:24:39 »
Hi David,

All images are handled uniformly with respect to pixel sample values by PI's JavaScript runtime: floating point values in the normalized [0,1] range. This works transparently on the fly, irrespective of the actual sample data types.

However, the runtime does not impose limits on the values that you can assign to pixel samples. That is, you can freely assign values outside the [0,1] range, as you have verified with your test. This is necessary to allow for temporary values generated during processing routines and calculations involving images. For example, code such as:

Code: [Select]
var a = new Image;
var b = new Image;
// ...
a.apply( b, ImageOp_Add );


can easily generate pixel values greater than one.

The above paragraph is strictly valid only for floating point images. This is because if you assign, say a value of 10^8, to a 16-bit integer image for example, you'll get 65535 (= pure white) due to overflow. Thus, for integer images one should ensure that no pixel is assigned with values outside the [0,1] range from JavaScript code.

Also for the above reason, one should always work with floating point images, as long as possible, and use integer images only to represent the final result, when necessary.
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Image.fill() accepts a signed number
« Reply #2 on: 2007 October 09 14:14:13 »
(Hmm esto trastoca mis planes...)

Thank you for your response. I thought that the parameter to Image.fill() was an UInt32, just like the parameter to Bitmap.fill() or to Pen.color. It seems it isn't ;) so I have another problem now:

I'm using Image.fill() to set the background of a new image, and later I'm drawing a rectangle in a Bitmap. How can I obtain a parameter to Pen.color() that produces the exact same colour as the background one? According to my experiments, it isn't enough to:

Code: [Select]
var pen_color = 0xff * image_fill_parameter;
pen_color = 0xff000000 | pen_color << 16 | pen_color << 8 | pen_color;


because I'm limited to a depth of only 8 bits per channel.
--
 David Serrano

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Image.fill() accepts a signed number
« Reply #3 on: 2007 October 10 01:10:45 »
Hi David,

Bitmaps are indeed 32-bit RGBA images, so each channel is represented by just eight bits (in the format AARRGGBB).

If what you have to draw is (or can be decomposed into a set of) rectangular regions, you can do that very easily with image selections. Here is a little example that will guide you.

Code: [Select]
#include <pjsr/ColorSpace.jsh>

/**
 * A simple region filling primitive.
 */
function FillRegions( image, regions, fillWith )
{
   for ( var i = 0; i < regions.length; ++i )
   {
      image.selectedRect = regions[i];
      image.fill( fillWith );
   }
}

/**
 * Draws a rectangle of thickness t around an inner rectangular region r,
 * filled with a constant value v, over the specified image. This routine
 * fills pixel samples on the currently selected channel of image.
 */
function DrawRect( image, r, t, v )
{
   // Push current image selections so we can restore them on exit.
   image.pushSelections();

   // Fill an array of rectangular regions.
   FillRegions( image, [ new Rect( r.x0-t, r.y0,   r.x0,   r.y1   ),   // left
                         new Rect( r.x1,   r.y0,   r.x1+t, r.y1   ),   // right
                         new Rect( r.x0-t, r.y0-t, r.x1+t, r.y0   ),   // top
                         new Rect( r.x0-t, r.y1,   r.x1+t, r.y1+t ) ], // bottom
                v );

   // Restore original image selections
   image.popSelections();
}

function test( t, v )
{
   var window = ImageWindow.activeWindow;
   if ( window.isNull )
      throw new Error( "No active image window!" );

   with ( window.mainView )
   {
      var center = image.bounds.center;
      var rect = new Rect( Math.floor( center.x - image.width/4 ),
                           Math.floor( center.y - image.height/4 ),
                           Math.ceil(  center.x + image.width/4 ),
                           Math.ceil(  center.y + image.height/4 ) );
      var c0 = 0;
      var c1 = (image.colorSpace == ColorSpace_Gray) ? 0 : 2;

      beginProcess();
      for ( var c = c0; c <= c1; ++c )
      {
         image.selectedChannel = c;
         DrawRect( image, rect, t, v );
      }
      endProcess();
   }
}

test( 20, 0.75 );


I have saved it as DrawThickRect.js.
Juan Conejero
PixInsight Development Team
http://pixinsight.com/