/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include "dx/dx.h" #include #include "quant.h" static Error traverse(Object *, Object *, int nColors); static Error doLeaf(Object *, Object *, int nColors); /* * Declare the interface routine. */ int QuantizeColors_worker(Object image, int float_pixels, int, ubyte *, int, ubyte *, int); static TreeNode traverse_series_pass1(TreeNode, Object *, int nColors); static int traverse_series_pass2(TreeNode, Object *, Object *); static TreeNode doLeaf_series_pass1(TreeNode, Object *, int); static int doLeaf_series_pass2(TreeNode, Object *, Object *); TreeNode QuantizeColors_series_pass1(TreeNode, int float_pixels, int, ubyte *, int); int QuantizeColors_series_pass2(TreeNode, int float_pixels, int, ubyte *, int, ubyte *); Error m_QuantizeImage(Object *in, Object *out) { int i; int nColors = 256; /* * Initialize all outputs to NULL */ out[0] = NULL; /* * Error checks: required inputs are verified. */ /* Parameter "rgb_image" is required. */ if (in[0] == NULL) { DXSetError(ERROR_MISSING_DATA, "\"rgb_image\" must be specified"); return ERROR; } if (in[1]) { if (! DXExtractInteger(in[1], &nColors) || nColors < 8 || nColors > 256) { DXSetError(ERROR_BAD_PARAMETER, "nColors must be an integer between 8 and 256"); return ERROR; } } /* * Since output "quantized" is structure Field/Group, it initially * is a copy of input "rgb_image". */ out[0] = DXCopy(in[0], COPY_STRUCTURE); if (! out[0]) goto error; /* * If in[0] was an array, then no copy is actually made - Copy * returns a pointer to the input object. Since this can't be written to * we postpone explicitly copying it until the leaf level, when we'll need * to be creating writable arrays anyway. */ if (out[0] == in[0]) out[0] = NULL; /* * Call the hierarchical object traversal routine */ if (!traverse(in, out, nColors)) goto error; return OK; error: /* * On error, any successfully-created outputs are deleted. */ for (i = 0; i < 1; i++) { if (in[i] != out[i]) DXDelete(out[i]); out[i] = NULL; } return ERROR; } static Error traverse(Object *in, Object *out, int nColors) { switch(DXGetObjectClass(in[0])) { case CLASS_FIELD: case CLASS_ARRAY: case CLASS_STRING: /* * If we have made it to the leaf level, call the leaf handler. */ if (! doLeaf(in, out, nColors)) return ERROR; return OK; case CLASS_GROUP: if (DXGetGroupClass((Group)in[0]) == CLASS_SERIES) { int i, j; int memknt; Class groupClass = DXGetGroupClass((Group)in[0]); TreeNode tree = NULL; struct color ubyte_map[256]; int tablesz = 0; Array cmap = NULL; float *f; for (i = 0; i < 8; i++) { depthlist[i].next = NULL; depthlist[i].knt = 0; } nLeaves = 0; DXGetMemberCount((Group)in[0], &memknt); for (i = 0; i < memknt; i++) { Object o = DXGetEnumeratedMember((Group)in[0], i, NULL); if (o) { tree = traverse_series_pass1(tree, &o, nColors); if (! tree) { CleanupNodes(); return ERROR; } } } if (!tree) { CleanupNodes(); return OK; } if (! CreateTable(tree, ubyte_map, nColors, &tablesz)) { CleanupNodes(); return ERROR; } if (tablesz > 256) { DXSetError(ERROR_INTERNAL, "too many leaves in tree: %d\n", tablesz); CleanupNodes(); return ERROR; } for (i = 0; i < memknt; i++) { Object new_in[1], new_out[1]; /* * For all inputs that are Values, pass them to * child object list. For all that are Field/Group, get * the appropriate decendent and place it into the * child input object list. */ /* input "rgb_image" is Field/Group */ if (in[0]) new_in[0] = DXGetEnumeratedMember((Group)in[0], i, NULL); else new_in[0] = NULL; /* * For all outputs that are Values, pass them to * child object list. For all that are Field/Group, get * the appropriate decendent and place it into the * child output object list. Note that none should * be NULL (unlike inputs, which can default). */ /* output "quantized" is Field/Group */ new_out[0] = DXGetEnumeratedMember((Group)out[0], i, NULL); if (! traverse_series_pass2(tree, new_in, new_out)) { CleanupNodes(); return ERROR; } /* * Now for each output that is not a Value, replace * the updated child into the object in the parent. */ /* output "quantized" is Field/Group */ DXSetEnumeratedMember((Group)out[0], i, new_out[0]); } CleanupNodes(); cmap = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3); if (! cmap) return ERROR; if (! DXAddArrayData(cmap, 0, 256, NULL)) { DXDelete((Object)cmap); return ERROR; } f = (float *)DXGetArrayData(cmap); for (i = 0; i < tablesz; i++) { *f++ = ubyte_map[i].r / 255.0; *f++ = ubyte_map[i].g / 255.0; *f++ = ubyte_map[i].b / 255.0; } for ( ; i < 256; i++) { *f++ = 0.0; *f++ = 0.0; *f++ = 0.0; } DXSetAttribute(out[0], "color map", (Object)cmap); DXSetIntegerAttribute(out[0], "direct color map", 1); CleanupNodes(); for (i = 0; i < memknt; i++) { Object o = DXGetEnumeratedMember((Group)out[0], i, NULL); DXSetComponentValue((Field)o, "color map", (Object)cmap); } return OK; } else { int i, j; int memknt; Class groupClass = DXGetGroupClass((Group)in[0]); DXGetMemberCount((Group)in[0], &memknt); /* * Create new in and out lists for each child * of the first input. */ for (i = 0; i < memknt; i++) { Object new_in[1], new_out[1]; /* * For all inputs that are Values, pass them to * child object list. For all that are Field/Group, get * the appropriate decendent and place it into the * child input object list. */ /* input "rgb_image" is Field/Group */ if (in[0]) new_in[0] = DXGetEnumeratedMember((Group)in[0], i, NULL); else new_in[0] = NULL; /* * For all outputs that are Values, pass them to * child object list. For all that are Field/Group, get * the appropriate decendent and place it into the * child output object list. Note that none should * be NULL (unlike inputs, which can default). */ /* output "quantized" is Field/Group */ new_out[0] = DXGetEnumeratedMember((Group)out[0], i, NULL); if (! traverse(new_in, new_out, nColors)) return ERROR; /* * Now for each output that is not a Value, replace * the updated child into the object in the parent. */ /* output "quantized" is Field/Group */ DXSetEnumeratedMember((Group)out[0], i, new_out[0]); } return OK; } case CLASS_XFORM: { int i, j; Object new_in[1], new_out[1]; /* * Create new in and out lists for the decendent of the * first input. For inputs and outputs that are Values * copy them into the new in and out lists. Otherwise * get the corresponding decendents. */ /* input "rgb_image" is Field/Group */ if (in[0]) DXGetXformInfo((Xform)in[0], &new_in[0], NULL); else new_in[0] = NULL; /* * For all outputs that are Values, copy them to * child object list. For all that are Field/Group, get * the appropriate decendent and place it into the * child output object list. Note that none should * be NULL (unlike inputs, which can default). */ /* output "quantized" is Field/Group */ DXGetXformInfo((Xform)out[0], &new_out[0], NULL); if (! traverse(new_in, new_out, nColors)) return ERROR; /* * Now for each output that is not a Value replace * the updated child into the object in the parent. */ /* output "quantized" is Field/Group */ DXSetXformObject((Xform)out[0], new_out[0]); return OK; } case CLASS_SCREEN: { int i, j; Object new_in[1], new_out[1]; /* * Create new in and out lists for the decendent of the * first input. For inputs and outputs that are Values * copy them into the new in and out lists. Otherwise * get the corresponding decendents. */ /* input "rgb_image" is Field/Group */ if (in[0]) DXGetScreenInfo((Screen)in[0], &new_in[0], NULL, NULL); else new_in[0] = NULL; /* * For all outputs that are Values, copy them to * child object list. For all that are Field/Group, get * the appropriate decendent and place it into the * child output object list. Note that none should * be NULL (unlike inputs, which can default). */ /* output "quantized" is Field/Group */ DXGetScreenInfo((Screen)out[0], &new_out[0], NULL, NULL); if (! traverse(new_in, new_out, nColors)) return ERROR; /* * Now for each output that is not a Value, replace * the updated child into the object in the parent. */ /* output "quantized" is Field/Group */ DXSetScreenObject((Screen)out[0], new_out[0]); return OK; } case CLASS_CLIPPED: { int i, j; Object new_in[1], new_out[1]; /* input "rgb_image" is Field/Group */ if (in[0]) DXGetClippedInfo((Clipped)in[0], &new_in[0], NULL); else new_in[0] = NULL; /* * For all outputs that are Values, copy them to * child object list. For all that are Field/Group, get * the appropriate decendent and place it into the * child output object list. Note that none should * be NULL (unlike inputs, which can default). */ /* output "quantized" is Field/Group */ DXGetClippedInfo((Clipped)out[0], &new_out[0], NULL); if (! traverse(new_in, new_out, nColors)) return ERROR; /* * Now for each output that is not a Value, replace * the updated child into the object in the parent. */ /* output "quantized" is Field/Group */ DXSetClippedObjects((Clipped)out[0], new_out[0], NULL); return OK; } default: { DXSetError(ERROR_BAD_CLASS, "encountered in object traversal"); return ERROR; } } } static TreeNode traverse_series_pass1(TreeNode tree, Object *in, int nColors) { switch(DXGetObjectClass(in[0])) { case CLASS_FIELD: return doLeaf_series_pass1(tree, in, nColors); default: DXSetError(ERROR_BAD_CLASS, "encountered in series traversal"); DXPrintV(in[0], "o", NULL); return ERROR; } } static int traverse_series_pass2(TreeNode tree, Object *in, Object *out) { switch(DXGetObjectClass(in[0])) { case CLASS_FIELD: return doLeaf_series_pass2(tree, in, out); default: DXSetError(ERROR_BAD_CLASS, "encountered in series traversal"); return ERROR; } } static TreeNode doLeaf_series_pass1(TreeNode tree, Object *in, int nColors) { int i, result=0; Array array; Field field; Pointer *in_data[1]; int in_knt[1]; Type type; Category category; int rank, shape; Object attr, src_dependency_attr = NULL; char *src_dependency = NULL; int p_knt = -1; int c_knt = -1; int float_pixels; if (DXGetObjectClass(in[0]) != CLASS_FIELD) { DXSetError(ERROR_BAD_CLASS, "\"rgb_image\" should be a field"); goto error; } field = (Field)in[0]; if (DXEmptyField(field)) return tree; /* * Determine the dependency of the source object's data * component. */ src_dependency_attr = DXGetComponentAttribute(field, "colors", "dep"); if (! src_dependency_attr) { DXSetError(ERROR_MISSING_DATA, "\"rgb_image\" data component is missing a dependency attribute"); goto error; } if (DXGetObjectClass(src_dependency_attr) != CLASS_STRING) { DXSetError(ERROR_BAD_CLASS, "\"rgb_image\" dependency attribute"); goto error; } src_dependency = DXGetString((String)src_dependency_attr); array = (Array)DXGetComponentValue(field, "positions"); if (! array) { DXSetError(ERROR_BAD_CLASS, "\"rgb_image\" contains no positions component"); goto error; } DXGetArrayInfo(array, &p_knt, NULL, NULL, NULL, NULL); array = (Array)DXGetComponentValue((Field)in[0], "colors"); if (! array) { DXSetError(ERROR_MISSING_DATA, "\"rgb_image\" has no colors component"); goto error; } if (DXGetObjectClass((Object)array) != CLASS_ARRAY) { DXSetError(ERROR_BAD_CLASS, "colors component of \"rgb_image\" should be an array"); goto error; } /* * get the dependency of the data component */ attr = DXGetAttribute((Object)array, "dep"); if (! attr) { DXSetError(ERROR_MISSING_DATA, "colors component of \"rgb_image\" has no dependency"); goto error; } if (DXGetObjectClass(attr) != CLASS_STRING) { DXSetError(ERROR_BAD_CLASS, "dependency attribute of data component of \"rgb_image\""); goto error; } /* * The dependency of this arg should be positions */ if (strcmp("positions", DXGetString((String)attr))) { DXSetError(ERROR_INVALID_DATA, "colors dependency of \"rgb_image\" must be positions"); goto error; } DXGetArrayInfo(array, &in_knt[0], &type, &category, &rank, &shape); if ((type != TYPE_UBYTE && type != TYPE_FLOAT) || category != CATEGORY_REAL || rank != 1 || shape != 3) { DXSetError(ERROR_INVALID_DATA, "input \"rgb_image\""); goto error; } in_data[0] = DXGetArrayData(array); if (! in_data[0]) goto error; float_pixels = (type == TYPE_FLOAT); /* * Call the user's routine. Check the return code. */ tree = QuantizeColors_series_pass1(tree, float_pixels, in_knt[0], (ubyte *)in_data[0], nColors); if (! tree) if (DXGetError()==ERROR_NONE) DXSetError(ERROR_INTERNAL, "error return from user routine"); /* * In either event, clean up allocated memory */ error: return tree; } static int doLeaf_series_pass2(TreeNode tree, Object *in, Object *out) { int i, result=0; Array array; Field field; Pointer *in_data[1], *out_data[1]; int in_knt[1], out_knt[1]; Type type; Category category; int rank, shape; Object attr, src_dependency_attr = NULL; char *src_dependency = NULL; int p_knt = -1; int c_knt = -1; int float_pixels; if (DXGetObjectClass(in[0]) == CLASS_FIELD) { field = (Field)in[0]; if (DXEmptyField(field)) return OK; /* * Determine the dependency of the source object's data * component. */ src_dependency_attr = DXGetComponentAttribute(field, "colors", "dep"); if (! src_dependency_attr) { DXSetError(ERROR_MISSING_DATA, "\"rgb_image\" data component is missing a dependency attribute"); goto error; } if (DXGetObjectClass(src_dependency_attr) != CLASS_STRING) { DXSetError(ERROR_BAD_CLASS, "\"rgb_image\" dependency attribute"); goto error; } src_dependency = DXGetString((String)src_dependency_attr); array = (Array)DXGetComponentValue(field, "positions"); if (! array) { DXSetError(ERROR_BAD_CLASS, "\"rgb_image\" contains no positions component"); goto error; } DXGetArrayInfo(array, &p_knt, NULL, NULL, NULL, NULL); /* * If there are connections, get their count so that * connections-dependent result arrays can be sized. */ array = (Array)DXGetComponentValue(field, "connections"); if (array) DXGetArrayInfo(array, &c_knt, NULL, NULL, NULL, NULL); } /* * If the input argument is not NULL then we get the * data array: either the object itself, if its an * array, or the data component if the argument is a field */ if (! in[0]) { array = NULL; in_data[0] = NULL; in_knt[0] = NULL; } else { if (DXGetObjectClass(in[0]) == CLASS_ARRAY) { array = (Array)in[0]; } else if (DXGetObjectClass(in[0]) == CLASS_STRING) { in_data[0] = (Pointer)DXGetString((String)in[0]); in_knt[0] = 1; } else { if (DXGetObjectClass(in[0]) != CLASS_FIELD) { DXSetError(ERROR_BAD_CLASS, "\"rgb_image\" should be a field"); goto error; } array = (Array)DXGetComponentValue((Field)in[0], "colors"); if (! array) { DXSetError(ERROR_MISSING_DATA, "\"rgb_image\" has no data component"); goto error; } if (DXGetObjectClass((Object)array) != CLASS_ARRAY) { DXSetError(ERROR_BAD_CLASS, "colors component of \"rgb_image\" should be an array"); goto error; } } /* * get the dependency of the data component */ attr = DXGetAttribute((Object)array, "dep"); if (! attr) { DXSetError(ERROR_MISSING_DATA, "colors component of \"rgb_image\" has no dependency"); goto error; } if (DXGetObjectClass(attr) != CLASS_STRING) { DXSetError(ERROR_BAD_CLASS, "dependency attribute of data component of \"rgb_image\""); goto error; } /* * The dependency of this arg should be positions */ if (strcmp("positions", DXGetString((String)attr))) { DXSetError(ERROR_INVALID_DATA, "colors dependency of \"rgb_image\" must be positions"); goto error; } if (DXGetObjectClass(in[0]) != CLASS_STRING) { DXGetArrayInfo(array, &in_knt[0], &type, &category, &rank, &shape); if ((type != TYPE_UBYTE && type != TYPE_FLOAT) || category != CATEGORY_REAL || rank != 1 || shape != 3) { DXSetError(ERROR_INVALID_DATA, "input \"rgb_image\""); goto error; } in_data[0] = DXGetArrayData(array); if (! in_data[0]) goto error; } float_pixels = (type == TYPE_FLOAT); } /* * Create an output data array typed according to the * specification given */ array = DXNewArray(TYPE_UBYTE, CATEGORY_REAL, 0, 0); if (! array) goto error; /* * This output data array will be dep positions - and sized * appropriately - if the appropriate size is known */ if (p_knt == -1) { DXSetError(ERROR_INVALID_DATA, "cannot make output \"quantized\" dep on positions because no positions were found in input[0]"); goto error; } out_knt[0] = p_knt; if (! DXSetAttribute((Object)array, "dep", (Object)DXNewString("positions"))) goto error; /* * Actually allocate the array data space */ if (! DXAddArrayData(array, 0, out_knt[0], NULL)) goto error; /* * If the output vector slot is not NULL, then it better be a field, and * we'll add the new array to it as its data component (delete any prior * data component so that its attributes won't overwrite the new component's) * Otherwise, place the new array into the out vector. */ if (out[0]) { if (DXGetObjectClass(out[0]) != CLASS_FIELD) { DXSetError(ERROR_INTERNAL, "non-field object found in output vector"); goto error; } if (DXGetComponentValue((Field)out[0], "colors")) DXDeleteComponent((Field)out[0], "colors"); if (! DXSetComponentValue((Field)out[0], "colors", (Object)array)) goto error; } else out[0] = (Object)array; /* * Now get the pointer to the contents of the array */ out_data[0] = DXGetArrayData(array); if (! out_data[0]) goto error; /* * Call the user's routine. Check the return code. */ result = QuantizeColors_series_pass2(tree, float_pixels, in_knt[0], (ubyte *)in_data[0], out_knt[0], (ubyte *)out_data[0]); if (! result) if (DXGetError()==ERROR_NONE) DXSetError(ERROR_INTERNAL, "error return from user routine"); /* * In either event, clean up allocated memory */ error: return result; } static int doLeaf(Object *in, Object *out, int nColors) { int i, result=0; Array array; Field field; Pointer *in_data[1], *out_data[1]; int in_knt[1], out_knt[1]; Type type; Category category; int rank, shape; Object attr, src_dependency_attr = NULL; char *src_dependency = NULL; int p_knt = -1; int c_knt = -1; int float_pixels; if (DXGetObjectClass(in[0]) == CLASS_FIELD) { field = (Field)in[0]; if (DXEmptyField(field)) return OK; /* * Determine the dependency of the source object's data * component. */ src_dependency_attr = DXGetComponentAttribute(field, "colors", "dep"); if (! src_dependency_attr) { DXSetError(ERROR_MISSING_DATA, "\"rgb_image\" data component is missing a dependency attribute"); goto error; } if (DXGetObjectClass(src_dependency_attr) != CLASS_STRING) { DXSetError(ERROR_BAD_CLASS, "\"rgb_image\" dependency attribute"); goto error; } src_dependency = DXGetString((String)src_dependency_attr); array = (Array)DXGetComponentValue(field, "positions"); if (! array) { DXSetError(ERROR_BAD_CLASS, "\"rgb_image\" contains no positions component"); goto error; } DXGetArrayInfo(array, &p_knt, NULL, NULL, NULL, NULL); /* * If there are connections, get their count so that * connections-dependent result arrays can be sized. */ array = (Array)DXGetComponentValue(field, "connections"); if (array) DXGetArrayInfo(array, &c_knt, NULL, NULL, NULL, NULL); } /* * If the input argument is not NULL then we get the * data array: either the object itself, if its an * array, or the data component if the argument is a field */ if (! in[0]) { array = NULL; in_data[0] = NULL; in_knt[0] = NULL; } else { if (DXGetObjectClass(in[0]) == CLASS_ARRAY) { array = (Array)in[0]; } else if (DXGetObjectClass(in[0]) == CLASS_STRING) { in_data[0] = (Pointer)DXGetString((String)in[0]); in_knt[0] = 1; } else { if (DXGetObjectClass(in[0]) != CLASS_FIELD) { DXSetError(ERROR_BAD_CLASS, "\"rgb_image\" should be a field"); goto error; } array = (Array)DXGetComponentValue((Field)in[0], "colors"); if (! array) { DXSetError(ERROR_MISSING_DATA, "\"rgb_image\" has no data component"); goto error; } if (DXGetObjectClass((Object)array) != CLASS_ARRAY) { DXSetError(ERROR_BAD_CLASS, "colors component of \"rgb_image\" should be an array"); goto error; } } /* * get the dependency of the data component */ attr = DXGetAttribute((Object)array, "dep"); if (! attr) { DXSetError(ERROR_MISSING_DATA, "colors component of \"rgb_image\" has no dependency"); goto error; } if (DXGetObjectClass(attr) != CLASS_STRING) { DXSetError(ERROR_BAD_CLASS, "dependency attribute of data component of \"rgb_image\""); goto error; } /* * The dependency of this arg should be positions */ if (strcmp("positions", DXGetString((String)attr))) { DXSetError(ERROR_INVALID_DATA, "colors dependency of \"rgb_image\" must be positions"); goto error; } if (DXGetObjectClass(in[0]) != CLASS_STRING) { DXGetArrayInfo(array, &in_knt[0], &type, &category, &rank, &shape); if ((type != TYPE_UBYTE && type != TYPE_FLOAT) || category != CATEGORY_REAL || rank != 1 || shape != 3) { DXSetError(ERROR_INVALID_DATA, "input \"rgb_image\""); goto error; } in_data[0] = DXGetArrayData(array); if (! in_data[0]) goto error; } float_pixels = (type == TYPE_FLOAT); } /* * Create an output data array typed according to the * specification given */ array = DXNewArray(TYPE_UBYTE, CATEGORY_REAL, 0, 0); if (! array) goto error; /* * This output data array will be dep positions - and sized * appropriately - if the appropriate size is known */ if (p_knt == -1) { DXSetError(ERROR_INVALID_DATA, "cannot make output \"quantized\" dep on positions because no positions were found in input[0]"); goto error; } out_knt[0] = p_knt; if (! DXSetAttribute((Object)array, "dep", (Object)DXNewString("positions"))) goto error; /* * Actually allocate the array data space */ if (! DXAddArrayData(array, 0, out_knt[0], NULL)) goto error; /* * If the output vector slot is not NULL, then it better be a field, and * we'll add the new array to it as its data component (delete any prior * data component so that its attributes won't overwrite the new component's) * Otherwise, place the new array into the out vector. */ if (out[0]) { if (DXGetObjectClass(out[0]) != CLASS_FIELD) { DXSetError(ERROR_INTERNAL, "non-field object found in output vector"); goto error; } if (DXGetComponentValue((Field)out[0], "colors")) DXDeleteComponent((Field)out[0], "colors"); if (! DXSetComponentValue((Field)out[0], "colors", (Object)array)) goto error; } else out[0] = (Object)array; /* * Now get the pointer to the contents of the array */ out_data[0] = DXGetArrayData(array); if (! out_data[0]) goto error; /* * Call the user's routine. Check the return code. */ result = QuantizeColors_worker(out[0], float_pixels, in_knt[0], (ubyte *)in_data[0], out_knt[0], (ubyte *)out_data[0], nColors); if (! result) if (DXGetError()==ERROR_NONE) DXSetError(ERROR_INTERNAL, "error return from user routine"); /* * In either event, clean up allocated memory */ error: return result; } int QuantizeColors_worker(Object image, int float_pixels, int rgb_image_knt, ubyte *rgb_image_data, int quantized_knt, ubyte *quantized_data, int nColors) { /* * The arguments to this routine are: * * * The following are inputs and therefore are read-only. The default * values are given and should be used if the knt is 0. * * rgb_image_knt, rgb_image_data: count and pointer for input "rgb_image" * no default value given. * * The output data buffer(s) are writable. * The output buffer(s) are preallocated based on * the dependency (positions or connections), * the size of the corresponding positions or * connections component in the first input, and * the data type. * * quantized_knt, quantized_data: count and pointer for output "quantized" */ /* * User's code goes here */ Array cmap = NULL; struct color ubyte_map[256]; TreeNode tree = NULL; int i, tablesz = 0; float *f; tree = CreateTree(rgb_image_data, rgb_image_knt, nColors, float_pixels); if (! tree) goto error; if (! CreateTable(tree, ubyte_map, nColors, &tablesz)) goto error; if (tablesz > 256) { DXSetError(ERROR_INTERNAL, "too many leaves in tree: %d\n", tablesz); goto error; } if (! CreateQuantPixels(tree, rgb_image_data, quantized_data, rgb_image_knt, float_pixels)) goto error; cmap = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 1, 3); if (! cmap) goto error; if (! DXAddArrayData(cmap, 0, 256, NULL)) goto error; f = (float *)DXGetArrayData(cmap); for (i = 0; i < tablesz; i++) { *f++ = ubyte_map[i].r / 255.0; *f++ = ubyte_map[i].g / 255.0; *f++ = ubyte_map[i].b / 255.0; } for (i = i; i < 256; i++) { *f++ = 0.0; *f++ = 0.0; *f++ = 0.0; } DXSetComponentValue(image, "color map", (Object)cmap); DXSetIntegerAttribute(image, "direct color map", 1); /* * successful completion */ CleanupNodes(); return 1; /* * unsuccessful completion */ error: CleanupNodes(); DXDelete((Object)cmap); return 0; } TreeNode QuantizeColors_series_pass1(TreeNode tree, int float_pixels, int rgb_image_knt, ubyte *rgb_image_data, int nColors) { tree = AddFieldToTree(tree, rgb_image_data, rgb_image_knt, float_pixels, nColors); return tree; } int QuantizeColors_series_pass2(TreeNode tree, int float_pixels, int rgb_image_knt, ubyte *rgb_image_data, int quantized_knt, ubyte *quantized_data) { if (! CreateQuantPixels(tree, rgb_image_data, quantized_data, rgb_image_knt, float_pixels)) goto error; return 1; /* * unsuccessful completion */ error: CleanupNodes(); return 0; }