summaryrefslogtreecommitdiffstats
path: root/hl/tools/h52jpeg/h52jpeg.c
diff options
context:
space:
mode:
Diffstat (limited to 'hl/tools/h52jpeg/h52jpeg.c')
-rw-r--r--hl/tools/h52jpeg/h52jpeg.c695
1 files changed, 695 insertions, 0 deletions
diff --git a/hl/tools/h52jpeg/h52jpeg.c b/hl/tools/h52jpeg/h52jpeg.c
new file mode 100644
index 0000000..05a3e80
--- /dev/null
+++ b/hl/tools/h52jpeg/h52jpeg.c
@@ -0,0 +1,695 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* From jpeg documentation
+ *
+ * Include file for users of JPEG library.
+ * You will need to have included system headers that define at least
+ * the typedefs FILE and size_t before you can include jpeglib.h.
+ * (stdio.h is sufficient on ANSI-conforming systems.)
+ * You may also wish to include "jerror.h".
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#include "jpeglib.h"
+#include "jerror.h"
+
+#include "H5private.h"
+#include "h5tools.h"
+#include "h5tools_utils.h"
+#include "h5trav.h"
+#include "H5IMpublic.h"
+
+
+const char *progname = "h52jpeg";
+int d_status = EXIT_SUCCESS;
+
+/* command-line options: The user can specify short or long-named parameters */
+static const char *s_opts = "hVvi:t:";
+static struct long_options l_opts[] = {
+ { "help", no_arg, 'h' },
+ { "version", no_arg, 'V' },
+ { "verbose", no_arg, 'v' },
+ { "image", require_arg, 'i' },
+ { "type", require_arg, 't' },
+ { NULL, 0, '\0' }
+};
+
+
+/* a structure that contains h52jpeg options */
+typedef struct
+{
+ const char *file_name;
+ const char *template_name;
+ const char *image_name;
+ int image_type;
+ int verbose;
+} h52jpeg_opt_t;
+
+
+/* prototypes */
+static void usage(const char *prog);
+static int h52jpeg(h52jpeg_opt_t opt);
+static void make_jpeg_name( const char* template_name, const char* image_name, char* jpeg_name);
+static int do_image(hid_t fid, h52jpeg_opt_t opt, const char* image_name);
+static void write_JPEG_file(char *filename, JSAMPLE *image_buffer, int image_height, int image_width, int planes);
+
+/*-------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose: h52jpeg main program
+ *
+ * Programmer: Pedro Vicente, pvn@hdfgroup.org
+ *
+ * Date: May 30, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+int main(int argc, const char *argv[])
+{
+ h52jpeg_opt_t opt;
+ const char *image_type = NULL;
+ int op;
+
+ /* initialze options to 0 */
+ memset(&opt,0,sizeof(h52jpeg_opt_t));
+
+ /* parse command line options */
+ while ((op = get_option(argc, argv, s_opts, l_opts)) != EOF)
+ {
+ switch ((char)op)
+ {
+ case 'h':
+ usage(progname);
+ exit(EXIT_SUCCESS);
+ case 'V':
+ print_version(progname);
+ exit(EXIT_SUCCESS);
+ case 'v':
+ opt.verbose = 1;
+ break;
+ case 'i':
+ opt.image_name = opt_arg;
+ break;
+ case 't':
+ image_type = opt_arg;
+
+
+ if ( HDstrcmp( image_type, "grey" ) == 0 )
+ {
+ opt.image_type = 0;
+ }
+ else if ( HDstrcmp( image_type, "true" ) == 0 )
+ {
+ opt.image_type = 1;
+ }
+ else
+ {
+ printf("<%s> is an invalid image type\n", image_type);
+ exit(EXIT_FAILURE);
+ }
+
+ break;
+
+ } /* switch */
+
+
+ } /* while */
+
+ /* check for file names to be processed */
+ if ( argv[ opt_ind ] != NULL && argv[ opt_ind + 1 ] != NULL )
+ {
+ opt.file_name = argv[ opt_ind ];
+ opt.template_name = argv[ opt_ind + 1 ];
+ }
+
+ else
+ {
+ usage(progname);
+ exit(EXIT_FAILURE);
+ }
+
+ if ( h52jpeg(opt) < 0 )
+ return 1;
+
+
+ return 0;
+}
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: usage
+ *
+ * Purpose: print usage
+ *
+ * Return: void
+ *
+ *-------------------------------------------------------------------------
+ */
+static void usage(const char *prog)
+{
+ printf("usage: %s [OPTIONS] file template\n", prog);
+ printf(" file HDF5 file name\n");
+ printf(" template Name template for jpeg images\n");
+ printf(" OPTIONS\n");
+ printf(" -h, --help Print a usage message and exit\n");
+ printf(" -v, --verbose Verbose mode, print object information\n");
+ printf(" -V, --version Print HDF5 version number and exit\n");
+ printf(" -i, --image Image name (full path in HDF5 file)\n");
+ printf(" -t T, --type=T Type of image (graycolor or truecolor)\n");
+
+ printf("\n");
+
+ printf(" T - is a string, either <grey> or <true>\n");
+
+}
+
+/*-------------------------------------------------------------------------
+ * Function: h52jpeg
+ *
+ * Parameters: OPT, options at command line
+ *
+ * Purpose: traverse the HDF5 file, save HDF5 images to jpeg files, translate
+ * 2D datasets of classes H5T_INTEGER and H5T_FLOAT to image data and save them
+ * to jpeg files
+ *
+ * Return: 0, all is fine, -1 not all is fine
+ *
+ *-------------------------------------------------------------------------
+ */
+static int h52jpeg(h52jpeg_opt_t opt)
+{
+ hid_t fid;
+ trav_table_t *travt = NULL;
+ size_t i;
+
+
+ /* open the HDF5 file */
+ if (( fid = h5tools_fopen(opt.file_name, H5F_ACC_RDONLY, H5P_DEFAULT, NULL, NULL, (size_t)0)) < 0)
+ {
+ error_msg(progname, "cannot open file <%s>\n", opt.file_name );
+ return -1;
+ }
+
+ /*-------------------------------------------------------------------------
+ * image/dataset name was specified at command line
+ *-------------------------------------------------------------------------
+ */
+
+ if ( opt.image_name )
+ {
+
+ /* read HDF5 image/dataset, save jpeg image */
+ do_image(fid, opt, opt.image_name);
+
+ }
+
+ /*-------------------------------------------------------------------------
+ * image name was not specified; traverse the file
+ *-------------------------------------------------------------------------
+ */
+
+ else
+
+ {
+
+ /* initialize traversal table */
+ trav_table_init(&travt);
+
+ /* get the list of objects in the file */
+ if ( h5trav_gettable(fid, travt) < 0 )
+ goto out;
+
+ /* search for images/datasets in file */
+ for ( i = 0; i < travt->nobjs; i++)
+ {
+
+ switch ( travt->objs[i].type )
+ {
+ default:
+ goto out;
+
+ case H5TRAV_TYPE_GROUP:
+ case H5TRAV_TYPE_NAMED_DATATYPE:
+ case H5TRAV_TYPE_LINK:
+ case H5TRAV_TYPE_UDLINK:
+
+ break;
+
+ case H5TRAV_TYPE_DATASET:
+
+ /* read HDF5 image/dataset, save jpeg image */
+ do_image(fid, opt, travt->objs[i].name);
+
+ break; /* H5TRAV_TYPE_DATASET */
+
+ } /* switch */
+
+ } /* i */
+
+
+ /* free table */
+ trav_table_free(travt);
+
+ } /* image_name */
+
+
+ /* close */
+ if ( H5Fclose(fid) < 0 )
+ return -1;
+
+ return 0;
+
+out:
+ H5E_BEGIN_TRY
+ {
+ H5Fclose(fid);
+
+ } H5E_END_TRY;
+
+
+ return -1;
+}
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: do_image
+ *
+ * Parameters: HDF5 file id, command line options, an image name
+ *
+ * Purpose: read HDF5 image/dataset, save jpeg image
+ *
+ * Return: int
+ *
+ *-------------------------------------------------------------------------
+ */
+static
+int do_image(hid_t fid, h52jpeg_opt_t opt, const char* image_name)
+{
+ hsize_t width;
+ hsize_t height;
+ hsize_t planes;
+ char interlace[20];
+ hssize_t npals;
+ unsigned char* buf=NULL;
+ H5T_class_t tclass;
+ hid_t sid;
+ hid_t did;
+ hid_t tid;
+ int rank;
+ hsize_t dims[H5S_MAX_RANK];
+ hsize_t maxdim[H5S_MAX_RANK];
+ size_t size;
+ hsize_t nelmts;
+ const char* name;
+ size_t i;
+ int j;
+ int done;
+ char jpeg_name[1024];
+
+ name = image_name;
+
+ /* build the jpeg file name */
+ make_jpeg_name( opt.template_name, image_name, jpeg_name);
+
+ done = 0;
+
+ if ( opt.verbose)
+ {
+ printf("%s ...", name );
+ }
+
+ /*-------------------------------------------------------------------------
+ * HDF5 Image
+ *-------------------------------------------------------------------------
+ */
+
+ if ( H5IMis_image( fid, name ) )
+ {
+
+ if ( H5IMget_image_info( fid, name, &width, &height, &planes, interlace, &npals ) < 0 )
+ goto out;
+
+ if (NULL == (buf = HDmalloc( (size_t)width * (size_t)height * (size_t)planes )))
+ goto out;
+
+ if ( H5IMread_image( fid, name, buf ) < 0 )
+ goto out;
+
+ /* write the jpeg file */
+ write_JPEG_file (jpeg_name,
+ buf,
+ (int) height,
+ (int) width,
+ (int) planes);
+
+
+ free( buf );
+ buf = NULL;
+
+ done = 1;
+
+
+
+ }
+
+ /*-------------------------------------------------------------------------
+ * HDF5 Image palette, ignore
+ *-------------------------------------------------------------------------
+ */
+
+ else if ( H5IMis_palette( fid, name ) )
+ {
+
+ }
+
+ /*-------------------------------------------------------------------------
+ * regular dataset
+ *-------------------------------------------------------------------------
+ */
+
+ else
+ {
+
+ unsigned char* image_buffer = NULL;
+
+ if (( did = H5Dopen2( fid, name, H5P_DEFAULT )) < 0)
+ goto out;
+ if (( sid = H5Dget_space( did )) < 0 )
+ goto out;
+ if (( rank = H5Sget_simple_extent_ndims(sid)) < 0 )
+ goto out;
+ if (( tid = H5Dget_type( did )) < 0 )
+ goto out;
+ if (( tclass = H5Tget_class(tid)) < 0)
+ goto out;
+
+ if ( ( H5T_FLOAT == tclass || H5T_INTEGER == tclass) &&
+ ( rank == 2 ) )
+ {
+
+ if ( H5Sget_simple_extent_dims( sid, dims, maxdim ) < 0 )
+ goto out;
+
+ size = H5Tget_size( tid );
+
+ nelmts = 1;
+ for ( j = 0; j < rank; j++)
+ {
+ nelmts *= dims[j];
+ }
+
+ if ( NULL == (buf = HDmalloc( (size_t)nelmts * size )))
+ goto out;
+ if ( H5Dread(did,tid,H5S_ALL,H5S_ALL,H5P_DEFAULT,buf) < 0 )
+ goto out;
+
+ height = dims[0];
+ width = dims[1];
+
+ if ( opt.image_type == 0 )
+ planes = 1;
+ else if ( opt.image_type == 1 )
+ planes = 3;
+
+
+ if ( NULL == (image_buffer = HDmalloc( (size_t)nelmts * sizeof (unsigned char) )))
+ {
+ goto out;
+ }
+
+ /*-------------------------------------------------------------------------
+ * convert the data to unsigned char
+ *
+ *-------------------------------------------------------------------------
+ */
+
+ {
+ double min = DBL_MAX;
+ double max = -DBL_MAX;
+ double ratio;
+
+ /* search for the minimum and maximum */
+ for ( i = 0; i < nelmts; i++)
+ {
+ if ( buf[i] < min) min = buf[i];
+ if ( buf[i] > max) max = buf[i];
+ }
+ /* converts the data based on the ratio to a 0-255 range */
+ ratio = (min == max) ? 1.0 : (double)(255.0/(max-min));
+ for ( i = 0; i < nelmts; i++)
+ {
+ image_buffer[i] = (unsigned char)ceil( (( buf[i] - min ) / ratio) );
+ }
+
+ }
+
+ /* write the jpeg file */
+ write_JPEG_file (jpeg_name,
+ image_buffer,
+ (int) height,
+ (int) width,
+ (int) planes);
+
+
+ free( image_buffer );
+ free( buf );
+ buf = NULL;
+ image_buffer = NULL;
+ done = 1;
+
+ }
+
+
+
+ H5Sclose(sid);
+ H5Tclose(tid);
+ H5Dclose(did);
+
+
+
+
+ } /* else */
+
+
+ if ( opt.verbose)
+ {
+ if ( done )
+ {
+ printf("saved to %s\n", jpeg_name );
+ }
+ else
+ {
+ printf("\n");
+ }
+
+ }
+
+ return 0;
+
+out:
+ H5E_BEGIN_TRY
+ {
+
+ H5Sclose(sid);
+ H5Tclose(tid);
+ H5Dclose(did);
+
+ } H5E_END_TRY;
+
+ if ( buf != NULL )
+ free( buf );
+
+
+ return -1;
+
+}
+
+/*-------------------------------------------------------------------------
+ * Function: make_jpeg_name
+ *
+ * Parameters: template name (IN), image name (IN), jpeg name (IN/OUT)
+ *
+ * Purpose: build a name for the jpeg image file upon a template name
+ * and the HDF5 image name
+ *
+ * Return: void
+ *
+ *-------------------------------------------------------------------------
+ */
+static
+void make_jpeg_name( const char* template_name, const char* image_name, char* jpeg_name)
+{
+ int j;
+ int len;
+
+ HDstrcpy( jpeg_name, template_name );
+ HDstrcat( jpeg_name, image_name );
+ HDstrcat( jpeg_name, ".jpeg" );
+ len = HDstrlen( jpeg_name);
+
+ /* HDF5 path names might contain '/', replace with '_' */
+ for (j = 0; j < len; j++)
+ {
+ if (jpeg_name[j] == '/')
+ {
+ jpeg_name[j] = '_';
+ }
+ }
+
+}
+
+
+
+/*
+ * Sample routine for JPEG compression.
+ *
+ * IMAGE DATA FORMATS:
+ *
+ * The standard input image format is a rectangular array of pixels, with
+ * each pixel having the same number of "component" values (color channels).
+ * Each pixel row is an array of JSAMPLEs (which typically are unsigned chars).
+ * If you are working with color data, then the color values for each pixel
+ * must be adjacent in the row; for example, R,G,B,R,G,B,R,G,B,... for 24-bit
+ * RGB color.
+ *
+ * For this example, we'll assume that this data structure matches the way
+ * our application has stored the image in memory, so we can just pass a
+ * pointer to our image buffer.
+ */
+
+static
+void write_JPEG_file(char *filename,
+ JSAMPLE *image_buffer, /* Points to large array of R,G,B-order data */
+ int image_height, /* Number of rows in image */
+ int image_width, /* Number of columns in image */
+ int planes) /* # of color components per pixel */
+{
+ /* This struct contains the JPEG compression parameters and pointers to
+ * working space (which is allocated as needed by the JPEG library).
+ * It is possible to have several such structures, representing multiple
+ * compression/decompression processes, in existence at once. We refer
+ * to any one struct (and its associated working data) as a "JPEG object".
+ */
+ struct jpeg_compress_struct cinfo;
+ /* This struct represents a JPEG error handler. It is declared separately
+ * because applications often want to supply a specialized error handler
+ * (see the second half of this file for an example). But here we just
+ * take the easy way out and use the standard error handler, which will
+ * print a message on stderr and call exit() if compression fails.
+ * Note that this struct must live as long as the main JPEG parameter
+ * struct, to avoid dangling-pointer problems.
+ */
+ struct jpeg_error_mgr jerr;
+ /* More stuff */
+ FILE * outfile; /* target file */
+ JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
+ int row_stride; /* physical row width in image buffer */
+
+ /* Step 1: allocate and initialize JPEG compression object */
+
+ /* We have to set up the error handler first, in case the initialization
+ * step fails. (Unlikely, but it could happen if you are out of memory.)
+ * This routine fills in the contents of struct jerr, and returns jerr's
+ * address which we place into the link field in cinfo.
+ */
+ cinfo.err = jpeg_std_error(&jerr);
+ /* Now we can initialize the JPEG compression object. */
+ jpeg_create_compress(&cinfo);
+
+ /* Step 2: specify data destination (eg, a file) */
+ /* Note: steps 2 and 3 can be done in either order. */
+
+ /* Here we use the library-supplied code to send compressed data to a
+ * stdio stream. You can also write your own code to do something else.
+ * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
+ * requires it in order to write binary files.
+ */
+ if ((outfile = fopen(filename, "wb")) == NULL) {
+ fprintf(stderr, "can't open %s\n", filename);
+ exit(1);
+ }
+ jpeg_stdio_dest(&cinfo, outfile);
+
+ /* Step 3: set parameters for compression */
+
+ /* First we supply a description of the input image.
+ * Four fields of the cinfo struct must be filled in:
+ */
+ cinfo.image_width = image_width; /* image width and height, in pixels */
+ cinfo.image_height = image_height;
+ cinfo.input_components = planes; /* # of color components per pixel */
+
+ /* colorspace of input image */
+ if (planes == 3)
+ cinfo.in_color_space = JCS_RGB;
+ else if (planes == 1)
+ cinfo.in_color_space = JCS_GRAYSCALE;
+
+ /* Now use the library's routine to set default compression parameters.
+ * (You must set at least cinfo.in_color_space before calling this,
+ * since the defaults depend on the source color space.)
+ */
+ jpeg_set_defaults(&cinfo);
+ /* Now you can set any non-default parameters you wish to.
+ * Here we just illustrate the use of quality (quantization table) scaling:
+ */
+ jpeg_set_quality(&cinfo, 100, TRUE /* limit to baseline-JPEG values */);
+
+ /* Step 4: Start compressor */
+
+ /* TRUE ensures that we will write a complete interchange-JPEG file.
+ * Pass TRUE unless you are very sure of what you're doing.
+ */
+ jpeg_start_compress(&cinfo, TRUE);
+
+ /* Step 5: while (scan lines remain to be written) */
+ /* jpeg_write_scanlines(...); */
+
+ /* Here we use the library's state variable cinfo.next_scanline as the
+ * loop counter, so that we don't have to keep track ourselves.
+ * To keep things simple, we pass one scanline per call; you can pass
+ * more if you wish, though.
+ */
+ row_stride = image_width * planes; /* JSAMPLEs per row in image_buffer */
+
+ while (cinfo.next_scanline < cinfo.image_height) {
+ /* jpeg_write_scanlines expects an array of pointers to scanlines.
+ * Here the array is only one element long, but you could pass
+ * more than one scanline at a time if that's more convenient.
+ */
+ row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
+ (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ }
+
+ /* Step 6: Finish compression */
+
+ jpeg_finish_compress(&cinfo);
+ /* After finish_compress, we can close the output file. */
+ fclose(outfile);
+
+ /* Step 7: release JPEG compression object */
+
+ /* This is an important step since it will release a good deal of memory. */
+ jpeg_destroy_compress(&cinfo);
+
+ /* And we're done! */
+}
+