Thread: Scaling integer values without FPNs

  1. #1
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733

    Scaling integer values without FPNs

    I'll start with the function so you can see what I'm trying to do:
    Code:
    int SaveImagePPM( IMAGE *Image, FILE *file )
    {
    	ulong Rows = Image->Rows, row;
    	ulong Cols = Image->Cols, col, i;
    	ulong keep = ~(~0UL << Image->Depth);
    
    	fprintf( file, "P3\n%lu %lu\n%u\n", Cols, Rows, 255 );
    
    	for ( row = 0; row < Rows; ++row )
    	{
    		char * whitespace = "\n";
    
    		for ( col = 0; col < Cols; ++col )
    		{
    			for ( i = 0; i < IMAGE_CHANNEL_A; ++i )
    			{
    				ulong index = ImagePixelX( Image, row, col );
    				ulong value = *ImagePixel( Image, index, i ) << 1;
    
    				if ( value )
    				{
    					value = keep / value;
    					value = (value >> 1) + (value & 1);
    				}
    
    				fprintf( file, "%s%5lu", whitespace, value );
    				whitespace = " ";
    			}
    		}
    	}
    
    	fputc('\n', file );
    
    	fflush( file );
    	return 0;
    }
    Previously I've just used the existing depth and values, now I want to learn how to scale the values from their current range to an 8 bit range without the use of floating point, the reason for this is I want the reduce my reliance on FPNs in places where it would be helpful to the porting process to not rely on FPNs, what I mean is that a number of years ago systems had to work without FPNs, this naturally meant even the images and fonts had to be loaded without FPNs and I would like to learn this technique, since I know the image displayed correctly when depth was used as is I figured it would be the best choice to learn the technique on, the above attempt resulted in a black image with barely some grey in the bottom left corner, naturally that wasn't the image I was expecting, is there anyone here familiar with how to do it?

  2. #2
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Never mind I figured it out:

    Code:
    int SaveImagePPM( IMAGE *Image, FILE *file )
    {
    	ulong Rows = Image->Rows, row;
    	ulong Cols = Image->Cols, col, i;
    	ulong keep = ~(~0UL << (Image->Depth + 8));
    
    	fprintf( file, "P3\n%lu %lu\n%u\n", Cols, Rows, 255 );
    
    	for ( row = 0; row < Rows; ++row )
    	{
    		char * whitespace = "\n";
    
    		for ( col = 0; col < Cols; ++col )
    		{
    			for ( i = 0; i < IMAGE_CHANNEL_A; ++i )
    			{
    				ulong index = ImagePixelX( Image, row, col );
    				ulong value = *ImagePixel( Image, index, i );
    				ulong scale = value ? keep / value : 0;
    
    				if ( scale  )
    					value = 0xFFFF / scale;
    
    				fprintf( file, "%s%5lu", whitespace, value );
    				whitespace = " ";
    			}
    		}
    	}
    
    	fputc('\n', file );
    
    	fflush( file );
    	return 0;
    }

  3. #3
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Simplified the math to a single function for ease of use:

    Code:
    uintmax_t ScaleDepthWithoutFPN( uint dstDepth, uint srcDepth, uintmax_t value )
    {
    	uintmax_t limit = 0, scale;
    	limit = ~(~limit << (srcDepth + dstDepth));
    	scale = value ? limit / value : 0;
    	return scale ? limit / scale : 0;
    }

  4. #4
    Registered User
    Join Date
    Sep 2020
    Posts
    425
    The usual way to scale an n-bit value into a 2n-bit value is to multiply by 2^n+1.

    e.g. from a 4-bit value to an 8-bit value is to multiply by 17.

    Coding it is usually a shift-and-add:

    Code:
       eight_bit = (four_bit<<4)+four_bit;

  5. #5
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by hamster_nz View Post
    The usual way to scale an n-bit value into a 2n-bit value is to multiply by 2^n+1.

    e.g. from a 4-bit value to an 8-bit value is to multiply by 17.

    Coding it is usually a shift-and-add:

    Code:
       eight_bit = (four_bit<<4)+four_bit;
    That only works one way though, I was looking for both up and down 1, 2, 4 to 8 or 16 to 8, the gist of it is that I need to be able to convert to byte values when passing to the gpu

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Storage of integer and character values in C
    By Player777 in forum C Programming
    Replies: 1
    Last Post: 12-26-2019, 08:41 AM
  2. Sine values in integer format
    By Satya in forum C Programming
    Replies: 2
    Last Post: 06-02-2017, 02:25 AM
  3. Unique integer values for words
    By nwasiq in forum C++ Programming
    Replies: 1
    Last Post: 03-25-2013, 06:50 PM
  4. checking for non-integer values
    By ibleedart in forum C++ Programming
    Replies: 6
    Last Post: 10-23-2007, 12:37 PM
  5. Strings to integer values
    By Unregistered in forum C Programming
    Replies: 1
    Last Post: 02-05-2002, 12:49 PM

Tags for this Thread