PICTools Programmer's Reference
OP_UTL

OP_UTL: DIB Color reduction utility functions

See the UTL_STRUC: OP_UTL section for additional information about the color reduction utility functions.

OP_UTL provides a number of color reduction utility functions.  A specific color reduction function is selected by setting u.UTL.SubCode to the number corresponding to the function.

The color reduction utility functions include:

Subcode 0: Increase DIB Pixel Depth

The input DIB bit depth may be 1, 4, or 8 bits per pixel.  The output DIB bit depth must be greater than the input DIB.  The output DIB bit depth may be 4, 8 or 24 bits per pixel.

If u.UTL.RetainPalette is not zero for a 24-bit output DIB, then the input palette is retained in the output, even though it is not necessary.  If PF_IncludeBMPHead is set, then the output BMP will include the input palette. Whether or not PF_IncludeBMPHead is set, u.UTL.BiOut.biClrUsed and u.UTL.BiOut.biClrImportant will be the same as Head.biClrUsed and Head.biClrImportant.

Otherwise, if u.UTL.RetainPalette is not zero for a 24-bit output DIB, then u.UTL.BiOut.biClrUsed and u.UTL.BiOut.biClrImportant will both be set to 0.  If PF_IncludeBMPHead is set, the output BMP will not include the input palette.

Subcode 1: Add Color Histogram Data from a DIB

Before calling OP_UTL subcode 1, an array must be allocated and cleared to 0's.  u.UTL.ptr1 must be set to point to this array. This array can be sized to 32,768 WORDs, 65,536 WORDS, or, for a color-mapped image, the number of input color WORDS. HistogramSize is set to 32,768, 65,536 or the number of input colors. On RES_DONE after REQ_DONE, each histogram array element will have been incremented by the number of occurrences of each color in the DIB.

Each 24-bit RGB color value which is present in the DIB is first converted to a 15-bit RGB color value by setting bits 0-4 of the color value to the 5 most significant bits for blue, bits 5-9 to the 5 most significant bits of green and bits 10-14 to the 5 most significant bits for red.  The resulting 15-bit color value is used as an index for the histogram array element corresponding to the original 24-bit color.  If a 15-bit color value occurs more than 65,535 times, it will be reported in the histogram as having occurred 65,535 times.

It is possible - and useful - to accumulate histogram data across a number of DIBs.  This feature might be used to build one palette which is optimum for displaying those DIBs.  This would be accomplished by clearing the histogram array before processing the first DIB with subcode 1, and then processing the additional DIBs with subcode 1 using the same histogram buffer, but without clearing the histogram buffer before the additional DIBs.

Subcode 2: Create an Optimal Palette from Color Histogram Data

Before calling OP_UTL subcode 2, a color histogram array is created. This array is sized as discussed in the Subcode 1 section above. Ordinarily, this histogram data will be computed from a DIB using subcode 1.  u.UTL.ptr1 is set to point to this histogram data.  u.UTL.NumColors is set to the number of colors desired in the palette. 

After RES_DONE after REQ_EXEC, u.UTL.NumColors will be set to the actual number of colors in the palette. This will be less than the requested number of colors if the image actually uses fewer 15-bit RGB colors than the desired number.

The optimal palette is output in ColorTable. The colors in the palette should not be regarded as being in any particular order by index.

Subcode 3: Create a Color Map from a Palette

Before calling OP_UTL subcode 3, a buffer is allocated to hold the returned color map. By default, a 32,768 byte buffer, to hold a RGB555 color map, should be allocated. A 4096 buffer, to hold a RGB444 color map, can alternately by allocated. In this case, set PF2_ColorMap444 in u.UTL.PicFlags2. u.UTL.ptr2 is set to point to this buffer. ColorTable has the palette from which to create the color map. u.UTL.NumColors specifies the number of colors in ColorTable.

The color map is useful (and required) only when calling OP_UTL subcode 4 to palettize a DIB to a palette. Subcode 3 is separate from subcode 4 solely to improve the performance of palettizing some number of DIBs to the same palette.

Subcode 4: Palettize a DIB to a Palette

PF_ConvertGray is not set in u.UTL.PicFlags when palettizing a DIB to a specific color palette.  The input DIB may be 1, 4, 8 or 24 bits per pixel.  The output DIB bit depth is 1, 4 or 8 bits per pixel according to the setting of u.UTL.OutBpp.

The output DIB palette is an RGBQUAD color table array pointed to by u.UTL.ptr3.  A color map created by subcode 3 for the output DIB palette is pointed to by u.UTL.ptr2. If this is a RGB444 color map, then set PF2_ColorMap444 in u.UTL.PicFlags2. The number of colors in the output DIB palette is be set in u.UTL.NumColors.  This must be the same as the u.UTL.NumColors specified when the color map was created.

The output image is dithered if PF_Dither is set in u.UTL.PicFlags. Otherwise the output image is not dithered.

For input, color-mapped DIBs of 8bpp or less, an error threshold can be specified by setting u.UTL.ReduceError to the desired threshold and setting PF2_ApplyReduceErrorThreshold in u.UTL.PicFlags2. The operation will be aborted if the threshold is exceeded, and ERR_THRESHOLD_EXCEEDED will be returned. The error threshold is the mean square error in RGB-space over all pixels.

For input, color-mapped DIBs of 8bpp or less, to compute and obtain the color reduction error, set PF2_ShowReduceError in u.UTL.PicFlags2 and set u.UTL.ptr1 to point to a histogram.  he color reduction error will be returned in u.UTL.ReduceError.

Subcode 5: Convert a DIB to Gray Scale

To convert a DIB to gray scale, set PF_ConvertGray in u.UTL.PicFlags.  The input DIB can be 1, 4, 8, or 24 bits per pixel.  The output DIB is 1, 4, or 8 bits per pixel according to the setting of u.UTL.OutBpp.  u.UTL.NumColors specifies the number of levels to be used in the output DIB.

The output image is dithered if PF_Dither is set in u.UTL.PicFlags.  Otherwise the output image is not dithered.

The gray level palette is not returned from subcode 4.  An appropriate gray level palette can be constructed as:

 
Copy Code

for ( n = 0; n < PicParm.u.UTL.NumColors; n++ )

{

  ColorTable[n].rgbRed =

  ColorTable[n].rgbBlue =

  ColorTable[n].rgbGreen =

    ( n * 255 ) / ( PicParm.u.UTL.NumColors - 1 );

  ColorTable[n]rgbReserved = 0;

}

Subcode 6: Convert a Color Palette to a Gray Scale Palette

All 272 RGB color elements of ColorTable are converted to equivalent gray level values.

Subcode 7: Palettize a DIB to its Optimal Palette

OP_UTL subcode 7 combines subcodes 1, 2, 3 and 4 into a single function.  The input DIB may be 1, 4, 8 or 24 bits per pixel.  The output DIB is 1, 4 or 8 bits per pixel according to the setting of u.UTL.OutBpp.  An optimal palette consisting of at most u.UTL.NumColors is created and the input DIB is palettized into the output DIB using that optimal palette.  The actual number of colors in the optimal palette is returned in u.UTL.NumColors.  The optimal palette is returned in ColorTable.  Note that, if PF_IncludeBMPHead is not set, and the input DIB is not 24 bits per pixel, then the input DIB color palette in ColorTable is replaced by the output DIB color palette.

The output image is dithered if PF_Dither is set in u.UTL.PicFlags.  Otherwise the output image is not dithered.

For input, color-mapped DIBs of 8bpp or less, an error threshold can be specified by setting u.UTL.ReduceError to the desired threshold and setting PF2_ApplyReduceErrorThreshold in u.UTL.PicFlags2. The operation will be aborted if the threshold is exceeded, and ERR_THRESHOLD_EXCEEDED will be returned. The error threshold is the mean square error in RGB-space over all pixels.

For input, color-mapped DIBs of 8bpp or less, to compute and obtain the color reduction error, set PF2_ShowReduceError in u.UTL.PicFlags2 and set u.UTL.ptr1 to point to a 32k histogram. The color reduction error will be returned in u.UTL.ReduceError.

Subcode 8: Palettize a DIB to an Arbitrary Palette

OP_UTL subcode 8 combines subcodes 3 and 4 into a single function.  It operates exactly the same as subcode 4 except that a color map is not needed so u.UTL.ptr2 must be 0.

General Notes

If PF_IncludeBMPHead is set in u.UTL.PicFlags, then any input in the Get queue is expected to be in BMP format starting with a BITMAPINFOHEADER (following the BITMAPFILEHEADER), possibly followed by a color table array, followed by the DIB image pixel data.  In this case, Head and ColorTable don't need to be initialized to describe the input DIB image data.

When PF_IncludeBMPHead is set, any output in the Put queue will also be a BMP image of the output starting with the BITMAPINFOHEADER.  u.UTL.BiOut will be set to the BITMAPINFOHEADER data for the output BMP image data even when PF_IncludeBMPHead is set.

If PF_IncludeBMPHead is not set, then the input in the Get queue is expected to be the DIB pixel data only.  In that case, Head must be initialized to a BITMAPINFOHEADER describing the DIB image data.  ColorTable must be initialized to the DIBs color palette.

When PF_IncludeBMPHead is not set, the output in the Put queue will also be DIB pixel data only.  u.UTL.BiOut will be set to the BITMAPINFOHEADER data for the output image.  ColorTable will retain the input image color table and will also apply to the output image if the output bit depth is 4 or 8.

Get and Put Queue Operations

OP_UTL queue processing policy differs from all other opcodes. The difference is that OP_UTL treats its Get and Put buffers as strict circular queues with a sentinel byte. Front and Rear pointers are allowed to wrap around from End back to start.  So the state when Rear == Front is an empty queue state, i.e., no data is present in the queue. This is the same as with all the other opcodes.  But the state where Front == Start and Rear == End is also an empty queue state because Rear == End is regarded as the same as Rear == Start.  For the same reason Front == End and Rear == Start is an empty queue state.  A full queue state where no more data can be added to the queue, occurs when Front == Start and Rear == End - 1.  It also occurs whenever Front - Rear == 1.

Note that OP_D2F and OP_F2D have the same default strict queue policy as OP_UTL. However, for OP_F2D, the strict queue policy can be bypassed by using the F_RelaxedQueue flag. Details are provided in the OP_F2D section. OP_UTL does not support the F_RelaxedQueue flag.

Frequently an application will use this circular queue as if it were a linear buffer.  The recommended approach is to increment End by one even though that makes it look like the queue is one byte larger than it really is. However, the extra byte will not be read nor written by the opcode.  The code would look like this:

 
Copy Code

Get.Start = Buffer;

Get.End = Buffer + Buffer_Size + 1;

Get.Front = Get.Start;

Get.Rear = Get.Start;

And then, initially and whenever the application gets a RES_GET_NEED_DATA response, the processing should look like this: 

 
Copy Code

If ( Get.Front != Get.Rear )

    Unexpected_error;

Buffer_Length = Fill_Buffer(Buffer, Buffer_Size);

Get.Front = Get.Start;

// reset back to start because RES_GET_NEED_DATA

// left it == Get.Rear == Get.End - 1)

Get.Rear = Get.Front + Buffer_Length;

 

 

 

 


©2022. Accusoft Corporation. All Rights Reserved.

Send Feedback