home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / modules / libimg / src / il_util.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  16.7 KB  |  502 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /* -*- Mode: C; tab-width: 4 -*-
  20.  *  il_util.c Colormap and colorspace utilities.
  21.  *             
  22.  *   $Id: il_util.c,v 3.1 1998/03/28 03:35:02 ltabb Exp $
  23.  */
  24.  
  25.  
  26. #include "xp_mcom.h"            /* XP definitions and types. */
  27. #include "ntypes.h"             /* typedefs for commonly used Netscape data
  28.                                    structures. */
  29. #include "xp_core.h"
  30.  
  31. /* mwh this is for Win 16 comipler. */
  32. #ifndef TRUE
  33. #define TRUE 1
  34. #endif
  35. #ifndef FALSE
  36. #define FALSE 0
  37. #endif
  38.  
  39. #include "il_util.h"            /* Public API. */
  40. #include "il_utilp.h"           /* Private header file. */
  41.  
  42. /************************* Colormap utilities ********************************/
  43.  
  44. /* Create a new color cube with the specified dimensions, starting at the
  45.    given base_offset.  The total number of colors in the colormap will be
  46.    base_offset + red_size * green_size * blue_size.  The caller is
  47.    responsible for filling in its reserved colors, 0, 1, ..., base_offset-1.
  48.  
  49.    Note: the lookup table used here is of the form we will use when dithering
  50.    to an arbitrary palette. */
  51. static IL_ColorMap *
  52. il_NewColorCube(uint32 red_size, uint32 green_size, uint32 blue_size,
  53.                 uint32 base_offset)
  54. {
  55.     uint8 r, g, b, map_index;
  56.     uint32 i, j, k, size, red_offset, green_offset, dmax_val;
  57.     uint32 trm1, tgm1, tbm1, dtrm1, dtgm1, dtbm1;
  58.     uint32 crm1, cgm1, cbm1, dcrm1, dcgm1, dcbm1;
  59.     uint8 *lookup_table, *ptr, *done;
  60.     IL_RGB *map;
  61.     IL_ColorMap *cmap;
  62.  
  63.     /* Colormap size and offsets for computing the colormap indices. */
  64.     size = base_offset + red_size * green_size * blue_size;
  65.     if (size > CUBE_MAX_SIZE)
  66.         return FALSE;
  67.     red_offset = green_size * blue_size;
  68.     green_offset = blue_size;
  69.  
  70.      /* Operation on lookup table dimensions. */
  71.     trm1 = LOOKUP_TABLE_RED - 1;    dtrm1 = trm1 << 1;
  72.     tgm1 = LOOKUP_TABLE_GREEN - 1;  dtgm1 = tgm1 << 1;
  73.     tbm1 = LOOKUP_TABLE_BLUE - 1;   dtbm1 = tbm1 << 1; 
  74.  
  75.     /* Operations on color cube dimensions. */
  76.     crm1 = red_size - 1;    dcrm1 = crm1 << 1;
  77.     cgm1 = green_size - 1;  dcgm1 = cgm1 << 1;
  78.     cbm1 = blue_size - 1;   dcbm1 = cbm1 << 1; 
  79.  
  80.     /* Operation on target RGB color space dimensions. */
  81.     dmax_val = 255 << 1;
  82.  
  83.     /* We may want to add entries to the map array subsequently, so always
  84.        allocate space for a full palette. */
  85.     map = (IL_RGB *)XP_CALLOC(256, sizeof(IL_RGB));
  86.     if (!map)
  87.         return FALSE;
  88.  
  89.     lookup_table = (uint8 *)XP_CALLOC(LOOKUP_TABLE_SIZE, 1);
  90.     if (!lookup_table)
  91.         return FALSE;
  92.  
  93.     done = (uint8 *)XP_CALLOC(size, 1);
  94.     if (!done)
  95.         return FALSE;
  96.     
  97.     ptr = lookup_table;
  98.     for (i = 0; i < LOOKUP_TABLE_RED; i++)
  99.         for (j = 0; j < LOOKUP_TABLE_GREEN; j++)
  100.             for (k = 0; k < LOOKUP_TABLE_BLUE; k++) {
  101.                 /* Scale indices down to cube coordinates. */
  102.                 r = CUBE_SCALE(i, dcrm1, trm1, dtrm1);
  103.                 g = CUBE_SCALE(j, dcgm1, tgm1, dtgm1);
  104.                 b = CUBE_SCALE(k, dcbm1, tbm1, dtbm1);
  105.  
  106.                 /* Compute the colormap index. */
  107.                 map_index = r * red_offset + g * green_offset + b +
  108.                     base_offset;
  109.  
  110.                 /* Fill out the colormap entry for this index if we haven't
  111.                    already done so. */
  112.                 if (!done[map_index]) {
  113.                     /* Scale from cube coordinates up to 8-bit RGB values. */
  114.                     map[map_index].red =
  115.                         CUBE_SCALE(r, dmax_val, crm1, dcrm1);
  116.                     map[map_index].green = 
  117.                         CUBE_SCALE(g, dmax_val, cgm1, dcgm1);
  118.                     map[map_index].blue =
  119.                         CUBE_SCALE(b, dmax_val, cbm1, dcbm1);
  120.  
  121.                     /* Mark as done. */
  122.                     done[map_index] = 1;
  123.                 }
  124.  
  125.                 /* Fill in the lookup table entry with the colormap index. */
  126.                 *ptr++ = map_index;
  127.             }
  128.     XP_FREE(done);
  129.  
  130.  
  131.     cmap = XP_NEW_ZAP(IL_ColorMap);
  132.     if (!cmap) {
  133.         XP_FREE(map);
  134.         XP_FREE(lookup_table);
  135.         return NULL;
  136.     }
  137.     cmap->num_colors = size;
  138.     cmap->map = map;
  139.     cmap->index = NULL;
  140.     cmap->table = (void *)lookup_table;
  141.  
  142.     return cmap;
  143. }
  144.  
  145. /* Determine allocation of desired colors to components, and fill in Ncolors[]
  146.    array to indicate choice.  Return value is total number of colors (product
  147.    of Ncolors[] values). */
  148. static int
  149. select_ncolors(int Ncolors[],
  150.                int out_color_components,
  151.                int desired_number_of_colors)
  152. {
  153.     int nc = out_color_components; /* number of color components */
  154.     int max_colors = desired_number_of_colors;
  155.     int total_colors, iroot, i, j;
  156.     long temp;
  157.  
  158.         /* XXX - fur .  Is this right ? */
  159.         static const int RGB_order[3] = { 2, 1, 0 };
  160.  
  161.     /* We can allocate at least the nc'th root of max_colors per component. */
  162.     /* Compute floor(nc'th root of max_colors). */
  163.     iroot = 1;
  164.     do {
  165.         iroot++;
  166.         temp = iroot;        /* set temp = iroot ** nc */
  167.         for (i = 1; i < nc; i++)
  168.             temp *= iroot;
  169.     } while (temp <= (long) max_colors); /* repeat till iroot exceeds root */
  170.     iroot--;            /* now iroot = floor(root) */
  171.  
  172.     /* Must have at least 2 color values per component */
  173.     if (iroot < 2)
  174.         return -1;
  175.  
  176.     /* Initialize to iroot color values for each component */
  177.     total_colors = 1;
  178.     for (i = 0; i < nc; i++)
  179.     {
  180.         Ncolors[i] = iroot;
  181.         total_colors *= iroot;
  182.     }
  183.  
  184.     /* We may be able to increment the count for one or more components without
  185.      * exceeding max_colors, though we know not all can be incremented.
  186.      * In RGB colorspace, try to increment G first, then R, then B.
  187.      */
  188.     for (i = 0; i < nc; i++)
  189.     {
  190.         j = RGB_order[i];
  191.         /* calculate new total_colors if Ncolors[j] is incremented */
  192.         temp = total_colors / Ncolors[j];
  193.         temp *= Ncolors[j]+1;    /* done in long arith to avoid oflo */
  194.         if (temp > (long) max_colors)
  195.             break;            /* won't fit, done */
  196.         Ncolors[j]++;        /* OK, apply the increment */
  197.         total_colors = (int) temp;
  198.     }
  199.     return total_colors;
  200. }
  201.  
  202. /* Create a new color map consisting of a given set of reserved colors, and
  203.    a color cube.  num_colors represents the requested size of the colormap,
  204.    including the reserved colors.  The actual number of colors in the colormap
  205.    could be less depending on the color cube that is allocated.
  206.  
  207.    The Image Library will only make use of entries in the color cube.  This
  208.    function represents the current state of affairs, and it will eventually
  209.    be replaced when the Image Library has the capability to dither to an
  210.    arbitrary palette. */
  211. IL_ColorMap *
  212. IL_NewCubeColorMap(IL_RGB *reserved_colors, uint16 num_reserved_colors,
  213.                    uint16 num_colors)
  214. {
  215.     int i;
  216.     IL_RGB *map;
  217.     IL_ColorMap *cmap;
  218.     int Ncolors[3];             /* Size of the color cube. */
  219.     int num_cube_colors;
  220.  
  221.     /* Determine the size of the color cube. */
  222.     num_cube_colors = select_ncolors(Ncolors, 3,
  223.                                      num_colors - num_reserved_colors);
  224.     
  225.     /* Create the color cube.  */
  226.     cmap = il_NewColorCube(Ncolors[0], Ncolors[1], Ncolors[2],
  227.                            num_reserved_colors);
  228.  
  229.     /* Fill in the reserved colors. */
  230.     map = cmap->map;
  231.     for (i = 0; i < num_reserved_colors; i++) {
  232.         map[i].red = reserved_colors[i].red;
  233.         map[i].green = reserved_colors[i].green;
  234.         map[i].blue = reserved_colors[i].blue;
  235.     }
  236.  
  237.     return cmap;
  238. }
  239.  
  240. /* Create an optimal fixed palette of the specified size, starting with
  241.    the given set of reserved colors. */
  242. IL_ColorMap *
  243. IL_NewOptimalColorMap(IL_RGB *reserved_colors, uint16 num_reserved_colors,
  244.                       uint16 num_colors)
  245. {
  246.     /* XXXM12N Implement me. */
  247.     return NULL;
  248. }
  249.  
  250. /* Create an empty colormap.  The caller is responsible for filling in the
  251.    colormap entries. */
  252. IL_ColorMap *
  253. IL_NewColorMap(void)
  254. {
  255.     IL_RGB *map;
  256.     IL_ColorMap *cmap;
  257.  
  258.     cmap = XP_NEW_ZAP(IL_ColorMap);
  259.     if (!cmap)
  260.         return NULL;
  261.  
  262.     /* We always allocate space for a full palette. */
  263.     map = (IL_RGB *)XP_CALLOC(256, sizeof(IL_RGB));
  264.     if (!map) {
  265.         XP_FREE(cmap);
  266.         return NULL;
  267.     }
  268.     
  269.     cmap->num_colors = 0;
  270.     cmap->map = map;
  271.     cmap->index = NULL;
  272.     cmap->table = NULL;
  273.  
  274.     return cmap;
  275. }
  276.  
  277. /* Append the specified color to an existing IL_ColorMap, returning TRUE if
  278.    successful.  The position of the new color in the IL_ColorMap's map array
  279.    is returned in new_color->index.  The caller should also update the
  280.    corresponding entry in the IL_ColorMap's index array,
  281.    cmap->index[new_color->index], if the actual colormap indices do not
  282.    correspond to the order of the entries in the map array.
  283.  
  284.    Note: For now, at least, this function does not cause the Image Library's
  285.    lookup table to be altered, so the Image Library will continue to dither
  286.    to the old colormap.  Therefore, the current purpose of this function is
  287.    to add colors (such as a background color for transparent images) which
  288.    are not a part of the Image Library's color cube. */
  289. int
  290. IL_AddColorToColorMap(IL_ColorMap *cmap, IL_IRGB *new_color)
  291. {
  292.     int max_colors = 256;
  293.     int32 num_colors = cmap->num_colors;
  294.     IL_RGB *map = cmap->map;
  295.     IL_RGB *map_entry;
  296.  
  297.     if (num_colors > max_colors)
  298.         return FALSE;
  299.  
  300.     map_entry = map + num_colors;
  301.     map_entry->red = new_color->red;
  302.     map_entry->green = new_color->green;
  303.     map_entry->blue = new_color->blue;
  304.  
  305.     new_color->index = num_colors;
  306.  
  307.     cmap->num_colors++;
  308.  
  309.     return TRUE;
  310. }
  311.  
  312. /* Free all memory associated with a given colormap.
  313.    Note: This should *not* be used to destroy a colormap once it has been
  314.    passed into IL_CreatePseudoColorSpace.  Use IL_ReleaseColorSpace instead */
  315. void
  316. IL_DestroyColorMap (IL_ColorMap *cmap)
  317. {
  318.     if (cmap) {
  319.         if (cmap->map)
  320.             XP_FREE(cmap->map);
  321.         if (cmap->index)
  322.             XP_FREE(cmap->index);
  323.         if (cmap->table)
  324.             XP_FREE(cmap->table);
  325.         XP_FREE(cmap);
  326.     }
  327. }
  328.  
  329. /* Reorder the entries in a colormap.  new_order is an array mapping the old
  330.    indices to the new indices. */
  331. void
  332. IL_ReorderColorMap(IL_ColorMap *cmap, uint16 *new_order)
  333. {
  334. }
  335.  
  336.  
  337. /************************** Colorspace utilities *****************************/
  338.  
  339. /* Create a new True-colorspace of the dimensions specified by IL_RGBBits and
  340.    set the reference count to 1.  The pixmap_depth is the sum of the bits
  341.    assigned to the three color channels, plus any additional allowance that
  342.    might be necessary, e.g. for an alpha channel, or for alignment.  Note: the
  343.    contents of the IL_RGBBits structure will be copied, so they need not be
  344.    preserved after the call to IL_CreateTrueColorSpace. */
  345. IL_ColorSpace *
  346. IL_CreateTrueColorSpace(IL_RGBBits *rgb, uint8 pixmap_depth)
  347. {
  348.     IL_ColorSpace *color_space;
  349.  
  350.     color_space = XP_NEW_ZAP(IL_ColorSpace);
  351.     if (!color_space)
  352.         return NULL;
  353.  
  354.     color_space->type = NI_TrueColor;
  355.  
  356.     /* RGB bit allocation and offsets. */
  357.     XP_MEMCPY(&color_space->bit_alloc.rgb, rgb, sizeof(IL_RGBBits));
  358.  
  359.     color_space->pixmap_depth = pixmap_depth; /* Destination image depth. */
  360.  
  361.     /* Create the private part of the color_space */
  362.     color_space->private_data = (void *)XP_NEW_ZAP(il_ColorSpaceData);
  363.     if (!color_space->private_data) {
  364.         XP_FREE(color_space);
  365.         return NULL;
  366.     }
  367.         
  368.     color_space->ref_count = 1;
  369.     return color_space;
  370. }
  371.  
  372. /* Create a new Pseudo-colorspace using the given colormap and set the
  373.    reference count to 1.  The index_depth is the bit-depth of the colormap
  374.    indices (typically 8), while the pixmap_depth is the index_depth plus any
  375.    additional allowance that might be necessary e.g. for an alpha channel, or
  376.    for alignment.  Note: IL_ColorMaps passed into IL_CreatePseudoColorSpace
  377.    become a part of the IL_ColorSpace structure.  The IL_ColorMap pointer is
  378.    invalid after the the call to IL_CreatePseudoColorSpace, so it should
  379.    neither be accessed, nor destroyed using IL_DestroyColorMap.  Access to
  380.    the colormap, *is* available through the colormap member of the
  381.    IL_ColorSpace.  Memory associated with the colormap will be freed by
  382.    IL_ReleaseColorSpace when the reference count reaches zero. */
  383. IL_ColorSpace *
  384. IL_CreatePseudoColorSpace(IL_ColorMap *cmap, uint8 index_depth,
  385.                           uint8 pixmap_depth)
  386. {
  387.     IL_ColorSpace *color_space;
  388.  
  389.     color_space = XP_NEW_ZAP(IL_ColorSpace);
  390.     if (!color_space)
  391.         return NULL;
  392.  
  393.     color_space->type = NI_PseudoColor;
  394.     color_space->bit_alloc.index_depth = index_depth;
  395.     color_space->pixmap_depth = pixmap_depth;
  396.  
  397.    /* Copy the contents of the IL_ColorMap structure.  This copies the map
  398.       and table pointers, not the arrays themselves. */
  399.     XP_MEMCPY(&color_space->cmap, cmap, sizeof(IL_ColorMap)); 
  400.     XP_FREE(cmap);
  401.  
  402.     /* Create the private part of the color_space */
  403.     color_space->private_data = (void *)XP_NEW_ZAP(il_ColorSpaceData);
  404.     if (!color_space->private_data) {
  405.         XP_FREE(color_space);
  406.         return NULL;
  407.     }
  408.  
  409.     color_space->ref_count = 1;
  410.     return color_space;
  411. }
  412.  
  413. /* Create a new Greyscale-colorspace of depth specified by index_depth and
  414.    set the reference count to 1.  The pixmap_depth is the index_depth plus
  415.    any additional allowance that might be necessary e.g. for an alpha channel,
  416.    or for alignment. */
  417. IL_ColorSpace *
  418. IL_CreateGreyScaleColorSpace(uint8 index_depth, uint8 pixmap_depth)
  419. {
  420.     IL_ColorSpace *color_space;
  421.  
  422.     color_space = XP_NEW_ZAP(IL_ColorSpace);
  423.     if (!color_space)
  424.         return NULL;
  425.  
  426.     color_space->type = NI_GreyScale;
  427.     color_space->bit_alloc.index_depth = index_depth;
  428.     color_space->pixmap_depth = pixmap_depth;
  429.     color_space->cmap.num_colors = (1 << index_depth);
  430.  
  431.     /* Create the private part of the color_space */
  432.     color_space->private_data = (void *)XP_NEW_ZAP(il_ColorSpaceData);
  433.     if (!color_space->private_data) {
  434.         XP_FREE(color_space);
  435.         return NULL;
  436.     }
  437.  
  438.     color_space->ref_count = 1;
  439.     return color_space;
  440. }
  441.  
  442. /* Decrements the reference count for an IL_ColorSpace.  If the reference
  443.    count reaches zero, all memory associated with the colorspace (including
  444.    any colormap associated memory) will be freed. */
  445. void
  446. IL_ReleaseColorSpace(IL_ColorSpace *color_space)
  447. {
  448.     color_space->ref_count--;
  449.         
  450.     if (color_space->ref_count == 0) {
  451.         IL_ColorMap *cmap = &color_space->cmap;
  452.         il_ColorSpaceData *private_data =
  453.             (il_ColorSpaceData *)color_space->private_data;
  454.  
  455.         /* Free any colormap associated memory. */
  456.         if (cmap->map)  {
  457.             XP_FREE(cmap->map);
  458.             cmap->map = NULL;
  459.         }
  460.         if (cmap->index)    {
  461.             XP_FREE(cmap->index);
  462.             cmap->index = NULL;
  463.         }
  464.         if (cmap->table)    {
  465.             XP_FREE(cmap->table);
  466.             cmap->table = NULL;
  467.         }
  468.         
  469.         if (private_data) {
  470.  
  471.             /* Free any RGB depth conversion maps. */
  472.             if (private_data->r8torgbn) {
  473.                 XP_FREE(private_data->r8torgbn);
  474.                 private_data->r8torgbn = NULL;
  475.             }
  476.             if (private_data->g8torgbn) {
  477.                 XP_FREE(private_data->g8torgbn);
  478.                 private_data->g8torgbn = NULL;
  479.             }
  480.             if (private_data->b8torgbn) {
  481.                 XP_FREE(private_data->b8torgbn);
  482.                 private_data->b8torgbn = NULL;
  483.             }
  484.  
  485.             /* Free the il_ColorSpaceData */
  486.             XP_FREE(private_data);
  487.             color_space->private_data = NULL;
  488.         }
  489.  
  490.         /* Free the IL_ColorSpace structure. */
  491.         XP_FREE(color_space);
  492.     }
  493. }
  494.  
  495.  
  496. /* Increment the reference count for an IL_ColorSpace. */
  497. void
  498. IL_AddRefToColorSpace(IL_ColorSpace *color_space)
  499. {
  500.     color_space->ref_count++;
  501. }
  502.