diff options
Diffstat (limited to 'drivers/jpg/loadjpeg.c')
| -rw-r--r-- | drivers/jpg/loadjpeg.c | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/drivers/jpg/loadjpeg.c b/drivers/jpg/loadjpeg.c new file mode 100644 index 000000000..82072d427 --- /dev/null +++ b/drivers/jpg/loadjpeg.c @@ -0,0 +1,341 @@ +/* + * Small jpeg decoder library - testing application + * + * Copyright (c) 2006, Luc Saillard <luc@saillard.org> + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * - Neither the name of the author nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "tinyjpeg.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#define snprintf(buf, size, fmt, ...) sprintf(buf, fmt, __VA_ARGS__) + +static void exitmessage(const char *message) __attribute__((noreturn)); +static void exitmessage(const char *message) +{ + printf("%s\n", message); + exit(0); +} + +static int filesize(FILE *fp) +{ + long pos; + fseek(fp, 0, SEEK_END); + pos = ftell(fp); + fseek(fp, 0, SEEK_SET); + return pos; +} + +/** + * Save a buffer in 24bits Targa format + * (BGR byte order) + */ +static void write_tga(const char *filename, int output_format, int width, int height, unsigned char **components) +{ + unsigned char targaheader[18]; + FILE *F; + char temp[1024]; + unsigned int bufferlen = width * height * 3; + unsigned char *rgb_data = components[0]; + + sprintf(temp, sizeof(temp), filename); + + memset(targaheader,0,sizeof(targaheader)); + + targaheader[12] = (unsigned char) (width & 0xFF); + targaheader[13] = (unsigned char) (width >> 8); + targaheader[14] = (unsigned char) (height & 0xFF); + targaheader[15] = (unsigned char) (height >> 8); + targaheader[17] = 0x20; /* Top-down, non-interlaced */ + targaheader[2] = 2; /* image type = uncompressed RGB */ + targaheader[16] = 24; + + if (output_format == TINYJPEG_FMT_RGB24) + { + unsigned char *data = rgb_data + bufferlen - 3; + do + { + unsigned char c = data[0]; + data[0] = data[2]; + data[2] = c; + data-=3; + } + while (data > rgb_data); + } + + F = fopen(temp, "wb"); + fwrite(targaheader, sizeof(targaheader), 1, F); + fwrite(rgb_data, 1, bufferlen, F); + fclose(F); +} + +/** + * Save a buffer in three files (.Y, .U, .V) useable by yuvsplittoppm + */ +static void write_yuv(const char *filename, int width, int height, unsigned char **components) +{ + FILE *F; + char temp[1024]; + + snprintf(temp, 1024, "%s.Y", filename); + F = fopen(temp, "wb"); + fwrite(components[0], width, height, F); + fclose(F); + snprintf(temp, 1024, "%s.U", filename); + F = fopen(temp, "wb"); + fwrite(components[1], width*height/4, 1, F); + fclose(F); + snprintf(temp, 1024, "%s.V", filename); + F = fopen(temp, "wb"); + fwrite(components[2], width*height/4, 1, F); + fclose(F); +} + +/** + * Save a buffer in grey image (pgm format) + */ +static void write_pgm(const char *filename, int width, int height, unsigned char **components) +{ + FILE *F; + char temp[1024]; + + snprintf(temp, 1024, "%s", filename); + F = fopen(temp, "wb"); + fprintf(F, "P5\n%d %d\n255\n", width, height); + fwrite(components[0], width, height, F); + fclose(F); +} + +/** + * Load one jpeg image, and try to decompress 1000 times, and save the result. + * This is mainly used for benchmarking the decoder, or to test if between each + * called of the library the DCT is corrected reset (a bug was found). + */ +int load_multiple_times(const char *filename, const char *outfilename, int output_format) +{ + FILE *fp; + int count, length_of_file; + unsigned int width, height; + unsigned char *buf; + struct jdec_private *jdec; + unsigned char *components[4]; + + jdec = tinyjpeg_init(); + count = 0; + + /* Load the Jpeg into memory */ + fp = fopen(filename, "rb"); + if (fp == NULL) + exitmessage("Cannot open filename\n"); + length_of_file = filesize(fp); + buf = (unsigned char *)malloc(length_of_file + 4); + fread(buf, length_of_file, 1, fp); + fclose(fp); + + while (count<1000) + { + if (tinyjpeg_parse_header(jdec, buf, length_of_file)<0) + exitmessage(tinyjpeg_get_errorstring(jdec)); + + tinyjpeg_decode(jdec, output_format); + + count++; + } + + /* + * Get address for each plane (not only max 3 planes is supported), and + * depending of the output mode, only some components will be filled + * RGB: 1 plane, YUV420P: 3 planes, GREY: 1 plane + */ + tinyjpeg_get_components(jdec, components); + tinyjpeg_get_size(jdec, &width, &height); + + /* Save it */ + switch (output_format) + { + case TINYJPEG_FMT_RGB24: + case TINYJPEG_FMT_BGR24: + write_tga(outfilename, output_format, width, height, components); + break; + case TINYJPEG_FMT_YUV420P: + write_yuv(outfilename, width, height, components); + break; + case TINYJPEG_FMT_GREY: + write_pgm(outfilename, width, height, components); + break; + } + + free(buf); + tinyjpeg_free(jdec); + return 0; +} + +/** + * Load one jpeg image, and decompress it, and save the result. + */ +int convert_one_image(const char *infilename, const char *outfilename, int output_format) +{ + FILE *fp; + unsigned int length_of_file; + unsigned int width, height; + unsigned char *buf; + struct jdec_private *jdec; + unsigned char *components[3]; + + /* Load the Jpeg into memory */ + fp = fopen(infilename, "rb"); + if (fp == NULL) + exitmessage("Cannot open filename\n"); + length_of_file = filesize(fp); + buf = (unsigned char *)malloc(length_of_file + 4); + if (buf == NULL) + exitmessage("Not enough memory for loading file\n"); + fread(buf, length_of_file, 1, fp); + fclose(fp); + + /* Decompress it */ + jdec = tinyjpeg_init(); + if (jdec == NULL) + exitmessage("Not enough memory to alloc the structure need for decompressing\n"); + + if (tinyjpeg_parse_header(jdec, buf, length_of_file)<0) + exitmessage(tinyjpeg_get_errorstring(jdec)); + + /* Get the size of the image */ + tinyjpeg_get_size(jdec, &width, &height); + + printf("Decoding JPEG image...\n"); + if (tinyjpeg_decode(jdec, output_format) < 0) + exitmessage(tinyjpeg_get_errorstring(jdec)); + + /* + * Get address for each plane (not only max 3 planes is supported), and + * depending of the output mode, only some components will be filled + * RGB: 1 plane, YUV420P: 3 planes, GREY: 1 plane + */ + tinyjpeg_get_components(jdec, components); + + /* Save it */ + switch (output_format) + { + case TINYJPEG_FMT_RGB24: + case TINYJPEG_FMT_BGR24: + write_tga(outfilename, output_format, width, height, components); + break; + case TINYJPEG_FMT_YUV420P: + write_yuv(outfilename, width, height, components); + break; + case TINYJPEG_FMT_GREY: + write_pgm(outfilename, width, height, components); + break; + } + + /* Only called this if the buffers were allocated by tinyjpeg_decode() */ + tinyjpeg_free(jdec); + /* else called just free(jdec); */ + + free(buf); + return 0; +} + +static void usage(void) +{ + fprintf(stderr, "Usage: loadjpeg [options] <input_filename.jpeg> <format> <output_filename>\n"); + fprintf(stderr, "options:\n"); + fprintf(stderr, " --benchmark - Convert 1000 times the same image\n"); + fprintf(stderr, "format:\n"); + fprintf(stderr, " yuv420p - output 3 files .Y,.U,.V\n"); + fprintf(stderr, " rgb24 - output a .tga image\n"); + fprintf(stderr, " bgr24 - output a .tga image\n"); + fprintf(stderr, " gray - output a .pgm image\n"); + exit(1); +} + +/** + * main + * + */ +int main(int argc, char *argv[]) +{ + int output_format = TINYJPEG_FMT_YUV420P; + char *output_filename, *input_filename; + clock_t start_time, finish_time; + unsigned int duration; + int current_argument; + int benchmark_mode = 0; + + if (argc < 3) + usage(); + + current_argument = 1; + while (1) + { + if (strcmp(argv[current_argument], "--benchmark")==0) + benchmark_mode = 1; + else + break; + current_argument++; + } + + if (argc < current_argument+2) + usage(); + + input_filename = argv[current_argument]; + if (strcmp(argv[current_argument+1],"yuv420p")==0) + output_format = TINYJPEG_FMT_YUV420P; + else if (strcmp(argv[current_argument+1],"rgb24")==0) + output_format = TINYJPEG_FMT_RGB24; + else if (strcmp(argv[current_argument+1],"bgr24")==0) + output_format = TINYJPEG_FMT_BGR24; + else if (strcmp(argv[current_argument+1],"grey")==0) + output_format = TINYJPEG_FMT_GREY; + else + exitmessage("Bad format: need to be one of yuv420p, rgb24, bgr24, grey\n"); + output_filename = argv[current_argument+2]; + + start_time = clock(); + + if (benchmark_mode) + load_multiple_times(input_filename, output_filename, output_format); + else + convert_one_image(input_filename, output_filename, output_format); + + finish_time = clock(); + duration = finish_time - start_time; + printf("Decoding finished in %u ticks\n", duration); + + return 0; +} + + + + |
