diff options
Diffstat (limited to 'source/blender/imbuf/intern/jpeg.c')
-rw-r--r-- | source/blender/imbuf/intern/jpeg.c | 629 |
1 files changed, 629 insertions, 0 deletions
diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c new file mode 100644 index 00000000000..8132997e5cd --- /dev/null +++ b/source/blender/imbuf/intern/jpeg.c @@ -0,0 +1,629 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * jpeg.c + * + * $Id$ + */ + + +/* This little block needed for linking to Blender... */ +#include <stdio.h> +#include "BLI_blenlib.h" + +#include "imbuf.h" +#include "imbuf_patch.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "IMB_jpeg.h" + +#include "jpeglib.h" + +/* the types are from the jpeg lib */ +static void jpeg_error (j_common_ptr cinfo); +static void init_source(j_decompress_ptr cinfo); +static boolean fill_input_buffer(j_decompress_ptr cinfo); +static void skip_input_data(j_decompress_ptr cinfo, long num_bytes); +static void term_source(j_decompress_ptr cinfo); +static void memory_source(j_decompress_ptr cinfo, unsigned char *buffer, int size); +static boolean handle_app1 (j_decompress_ptr cinfo); +static ImBuf * ibJpegImageFromCinfo(struct jpeg_decompress_struct * cinfo, int flags); + + +/* strncasecmp hack */ +#ifdef WIN32 +#define strncasecmp(a, b, n) strncmp(a, b, n) +#endif + +/* + * Er zijn in principe vier verschillende jpeg formaten. + * + * 1. jpeg - standaard drukwerk, u & v op kwart van resolutie + * 2. jvid - standaard video u & v halve resolutie, frame opengeklapt + +type 3 is unsupported as of jul 05 2000 Frank. + + * 3. jstr - als 2, maar dan met twee losse fields weggeschreven + * moet baseline zijn + * moet rgb zijn + * moet samplingfactors goed hebben + + + * 4. jmax - geen scaling in de componenten + */ + +static int jpeg_failed = FALSE; +static int jpeg_default_quality; +static int ibuf_ftype; + +static void jpeg_error (j_common_ptr cinfo) +{ + /* Always display the message */ + (*cinfo->err->output_message) (cinfo); + + /* Let the memory manager delete any temp files before we die */ + jpeg_destroy(cinfo); + + jpeg_failed = TRUE; +} + +//---------------------------------------------------------- +// INPUT HANDLER FROM MEMORY +//---------------------------------------------------------- + +typedef struct { + unsigned char *buffer; + int filled; +} buffer_struct; + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + unsigned char *buffer; + int size; + JOCTET terminal[2]; +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + +static void init_source(j_decompress_ptr cinfo) +{ +} + + +static boolean fill_input_buffer(j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* Since we have given all we have got already + * we simply fake an end of file + */ + + src->pub.next_input_byte = src->terminal; + src->pub.bytes_in_buffer = 2; + src->terminal[0] = (JOCTET) 0xFF; + src->terminal[1] = (JOCTET) JPEG_EOI; + + return TRUE; +} + + +static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + src->pub.next_input_byte = src->pub.next_input_byte + num_bytes; +} + + +static void term_source(j_decompress_ptr cinfo) +{ +} + +static void memory_source(j_decompress_ptr cinfo, unsigned char *buffer, int size) +{ + my_src_ptr src; + + if (cinfo->src == NULL) + { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(my_source_mgr)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; + src->pub.term_source = term_source; + + src->pub.bytes_in_buffer = size; + src->pub.next_input_byte = buffer; + + src->buffer = buffer; + src->size = size; +} + + +#define MAKESTMT(stuff) do { stuff } while (0) + +#define INPUT_VARS(cinfo) \ + struct jpeg_source_mgr * datasrc = (cinfo)->src; \ + const JOCTET * next_input_byte = datasrc->next_input_byte; \ + size_t bytes_in_buffer = datasrc->bytes_in_buffer + +/* Unload the local copies --- do this only at a restart boundary */ +#define INPUT_SYNC(cinfo) \ + ( datasrc->next_input_byte = next_input_byte, \ + datasrc->bytes_in_buffer = bytes_in_buffer ) + +/* Reload the local copies --- seldom used except in MAKE_BYTE_AVAIL */ +#define INPUT_RELOAD(cinfo) \ + ( next_input_byte = datasrc->next_input_byte, \ + bytes_in_buffer = datasrc->bytes_in_buffer ) + +/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available. + * Note we do *not* do INPUT_SYNC before calling fill_input_buffer, + * but we must reload the local copies after a successful fill. + */ +#define MAKE_BYTE_AVAIL(cinfo,action) \ + if (bytes_in_buffer == 0) { \ + if (! (*datasrc->fill_input_buffer) (cinfo)) \ + { action; } \ + INPUT_RELOAD(cinfo); \ + } \ + bytes_in_buffer-- + +/* Read a byte into variable V. + * If must suspend, take the specified action (typically "return FALSE"). + */ +#define INPUT_BYTE(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + V = GETJOCTET(*next_input_byte++); ) + +/* As above, but read two bytes interpreted as an unsigned 16-bit integer. + * V should be declared unsigned int or perhaps INT32. + */ +#define INPUT_2BYTES(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \ + MAKE_BYTE_AVAIL(cinfo,action); \ + V += GETJOCTET(*next_input_byte++); ) + + +static boolean +handle_app1 (j_decompress_ptr cinfo) +{ + INT32 length, i; + char neogeo[128]; + + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + if (length < 16) { + for (i = 0; i < length; i++) INPUT_BYTE(cinfo, neogeo[i], return FALSE); + length = 0; + if (strncmp(neogeo, "NeoGeo", 6) == 0) memcpy(&ibuf_ftype, neogeo + 6, 4); + ibuf_ftype = BIG_LONG(ibuf_ftype); + } + INPUT_SYNC(cinfo); /* do before skip_input_data */ + if (length > 0) (*cinfo->src->skip_input_data) (cinfo, length); + return TRUE; +} + + +static ImBuf * ibJpegImageFromCinfo(struct jpeg_decompress_struct * cinfo, int flags) +{ + JSAMPARRAY row_pointer; + JSAMPLE * buffer = 0; + int row_stride; + int x, y, depth, r, g, b, k; + struct ImBuf * ibuf = 0; + uchar * rect; + + /* eigen app1 handler installeren */ + ibuf_ftype = 0; + jpeg_set_marker_processor(cinfo, 0xe1, handle_app1); + cinfo->dct_method = JDCT_FLOAT; + + if (jpeg_read_header(cinfo, FALSE) == JPEG_HEADER_OK) { + x = cinfo->image_width; + y = cinfo->image_height; + depth = cinfo->num_components; + + if (cinfo->jpeg_color_space == JCS_YCCK) cinfo->out_color_space = JCS_CMYK; + + jpeg_start_decompress(cinfo); + + if (ibuf_ftype == 0) { + ibuf_ftype = JPG_STD; + if (cinfo->max_v_samp_factor == 1) { + if (cinfo->max_h_samp_factor == 1) ibuf_ftype = JPG_MAX; + else ibuf_ftype = JPG_VID; + } + } + + if (flags & IB_test) { + jpeg_abort_decompress(cinfo); + ibuf = IMB_allocImBuf(x, y, 8 * depth, 0, 0); + } else { + ibuf = IMB_allocImBuf(x, y, 8 * depth, IB_rect, 0); + + row_stride = cinfo->output_width * depth; + + row_pointer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, JPOOL_IMAGE, row_stride, 1); + + for (y = ibuf->y - 1; y >= 0; y--) { + jpeg_read_scanlines(cinfo, row_pointer, 1); + if (flags & IB_ttob) { + rect = (uchar *) (ibuf->rect + (ibuf->y - 1 - y) * ibuf->x); + } else { + rect = (uchar *) (ibuf->rect + y * ibuf->x); + } + buffer = row_pointer[0]; + + switch(depth) { + case 1: + for (x = ibuf->x; x > 0; x--) { + rect[3] = 255; + rect[0] = rect[1] = rect[2] = *buffer++; + rect += 4; + } + break; + case 3: + for (x = ibuf->x; x > 0; x--) { + rect[3] = 255; + rect[0] = *buffer++; + rect[1] = *buffer++; + rect[2] = *buffer++; + rect += 4; + } + break; + case 4: + for (x = ibuf->x; x > 0; x--) { + r = *buffer++; + g = *buffer++; + b = *buffer++; + k = *buffer++; + + k = 255 - k; + r -= k; + if (r & 0xffffff00) { + if (r < 0) r = 0; + else r = 255; + } + g -= k; + if (g & 0xffffff00) { + if (g < 0) g = 0; + else g = 255; + } + b -= k; + if (b & 0xffffff00) { + if (b < 0) b = 0; + else b = 255; + } + + rect[3] = 255 - k; + rect[2] = b; + rect[1] = g; + rect[0] = r; + rect += 4; + } + } + } + jpeg_finish_decompress(cinfo); + } + + jpeg_destroy((j_common_ptr) cinfo); + ibuf->ftype = ibuf_ftype; + } + + return(ibuf); +} + +ImBuf * imb_ibJpegImageFromFilename (char * filename, int flags) +{ + struct jpeg_decompress_struct _cinfo, *cinfo = &_cinfo; + struct jpeg_error_mgr jerr; + FILE * infile; + ImBuf * ibuf; + + if ((infile = fopen(filename, "rb")) == NULL) { + /*fprintf(stderr, "can't open %s\n", filename);*/ + return 0; + } + + cinfo->err = jpeg_std_error(&jerr); + jerr.error_exit = jpeg_error; + + jpeg_create_decompress(cinfo); + jpeg_stdio_src(cinfo, infile); + + ibuf = ibJpegImageFromCinfo(cinfo, flags); + + fclose(infile); + return(ibuf); +} + +ImBuf * imb_ibJpegImageFromMemory (unsigned char * buffer, int size, int flags) +{ + struct jpeg_decompress_struct _cinfo, *cinfo = &_cinfo; + struct jpeg_error_mgr jerr; + ImBuf * ibuf; + + cinfo->err = jpeg_std_error(&jerr); + jerr.error_exit = jpeg_error; + + jpeg_create_decompress(cinfo); + memory_source(cinfo, buffer, size); + + ibuf = ibJpegImageFromCinfo(cinfo, flags); + + return(ibuf); +} + + +static void write_jpeg(struct jpeg_compress_struct * cinfo, struct ImBuf * ibuf) +{ + JSAMPLE * buffer = 0; + JSAMPROW row_pointer[1]; + uchar * rect; + int x, y; + char neogeo[128]; + + + jpeg_start_compress(cinfo, TRUE); + + strcpy(neogeo, "NeoGeo"); + ibuf_ftype = BIG_LONG(ibuf->ftype); + + memcpy(neogeo + 6, &ibuf_ftype, 4); + jpeg_write_marker(cinfo, 0xe1, (JOCTET*) neogeo, 10); + + row_pointer[0] = + mallocstruct(JSAMPLE, + cinfo->input_components * + cinfo->image_width); + + for(y = ibuf->y - 1; y >= 0; y--){ + rect = (uchar *) (ibuf->rect + y * ibuf->x); + buffer = row_pointer[0]; + + switch(cinfo->in_color_space){ + case JCS_RGB: + for (x = 0; x < ibuf->x; x++) { + *buffer++ = rect[0]; + *buffer++ = rect[1]; + *buffer++ = rect[2]; + rect += 4; + } + break; + case JCS_GRAYSCALE: + for (x = 0; x < ibuf->x; x++) { + *buffer++ = rect[0]; + rect += 4; + } + break; + case JCS_UNKNOWN: + memcpy(buffer, rect, 4 * ibuf->x); + break; + /* default was missing... intentional ? */ + default: + ; /* do nothing */ + } + + jpeg_write_scanlines(cinfo, row_pointer, 1); + + if (jpeg_failed) break; + } + + if (jpeg_failed == FALSE) jpeg_finish_compress(cinfo); + free(row_pointer[0]); +} + + +static int init_jpeg(FILE * outfile, struct jpeg_compress_struct * cinfo, struct ImBuf *ibuf) +{ + int quality; + + quality = ibuf->ftype & 0xff; + if (quality <= 0) quality = jpeg_default_quality; + if (quality > 100) quality = 100; + + jpeg_create_compress(cinfo); + jpeg_stdio_dest(cinfo, outfile); + + cinfo->image_width = ibuf->x; + cinfo->image_height = ibuf->y; + + cinfo->in_color_space = JCS_RGB; + if (ibuf->depth == 8 && ibuf->cmap == 0) cinfo->in_color_space = JCS_GRAYSCALE; + if (ibuf->depth == 32) cinfo->in_color_space = JCS_UNKNOWN; + + switch(cinfo->in_color_space){ + case JCS_RGB: + cinfo->input_components = 3; + break; + case JCS_GRAYSCALE: + cinfo->input_components = 1; + break; + case JCS_UNKNOWN: + cinfo->input_components = 4; + break; + /* default was missing... intentional ? */ + default: + ; /* do nothing */ + } + jpeg_set_defaults(cinfo); + + /* eigen instellingen */ + + cinfo->dct_method = JDCT_FLOAT; + jpeg_set_quality(cinfo, quality, TRUE); + + return(0); +} + + +static int save_stdjpeg(char * name, struct ImBuf * ibuf) +{ + FILE * outfile; + struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo; + struct jpeg_error_mgr jerr; + + if ((outfile = fopen(name, "wb")) == NULL) return(-1); + jpeg_default_quality = 75; + + cinfo->err = jpeg_std_error(&jerr); + jerr.error_exit = jpeg_error; + + init_jpeg(outfile, cinfo, ibuf); + + write_jpeg(cinfo, ibuf); + + fclose(outfile); + jpeg_destroy_compress(cinfo); + + if (jpeg_failed) remove(name); + return(jpeg_failed); +} + + +static int save_vidjpeg(char * name, struct ImBuf * ibuf) +{ + FILE * outfile; + struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo; + struct jpeg_error_mgr jerr; + + if ((outfile = fopen(name, "wb")) == NULL) return(-1); + jpeg_default_quality = 90; + + cinfo->err = jpeg_std_error(&jerr); + jerr.error_exit = jpeg_error; + + init_jpeg(outfile, cinfo, ibuf); + + /* scalings factoren goedzetten */ + if (cinfo->in_color_space == JCS_RGB) { + cinfo->comp_info[0].h_samp_factor = 2; + cinfo->comp_info[0].v_samp_factor = 1; + } + + write_jpeg(cinfo, ibuf); + + fclose(outfile); + jpeg_destroy_compress(cinfo); + + if (jpeg_failed) remove(name); + return(jpeg_failed); +} + +static int save_jstjpeg(char * name, struct ImBuf * ibuf) +{ + char fieldname[1024]; + struct ImBuf * tbuf; + int oldy; +/* extern rectcpy(); */ + + tbuf = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 24, IB_rect, 0); + tbuf->ftype = ibuf->ftype; + tbuf->flags = ibuf->flags; + + oldy = ibuf->y; + ibuf->x *= 2; + ibuf->y /= 2; + + /* extra argument assumed to be 0 (nzc) */ +/* rectop(tbuf, ibuf, 0, 0, 0, 0, 32767, 32767, rectcpy); */ + IMB_rectop(tbuf, ibuf, 0, 0, 0, 0, 32767, 32767, IMB_rectcpy, 0); + sprintf(fieldname, "%s.jf0", name); + + if (save_vidjpeg(fieldname, tbuf) == 0) { + /* extra argument assumed to be 0 (nzc) */ +/* rectop(tbuf, ibuf, 0, 0, tbuf->x, 0, 32767, 32767, rectcpy); */ + IMB_rectop(tbuf, ibuf, 0, 0, tbuf->x, 0, 32767, 32767, IMB_rectcpy, 0); + sprintf(fieldname, "%s.jf1", name); + save_vidjpeg(fieldname, tbuf); + } + + ibuf->y = oldy; + ibuf->x /= 2; + IMB_freeImBuf(tbuf); + + /* no return value was given, assuming 0 */ + return 0; +} + + +static int save_maxjpeg(char * name, struct ImBuf * ibuf) +{ + FILE * outfile; + struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo; + struct jpeg_error_mgr jerr; + + if ((outfile = fopen(name, "wb")) == NULL) return(-1); + jpeg_default_quality = 100; + + cinfo->err = jpeg_std_error(&jerr); + jerr.error_exit = jpeg_error; + + init_jpeg(outfile, cinfo, ibuf); + + /* scalings factoren goedzetten */ + if (cinfo->in_color_space == JCS_RGB) { + cinfo->comp_info[0].h_samp_factor = 1; + cinfo->comp_info[0].v_samp_factor = 1; + } + + write_jpeg(cinfo, ibuf); + + fclose(outfile); + jpeg_destroy_compress(cinfo); + + if (jpeg_failed) remove(name); + return(jpeg_failed); +} + + +int imb_save_jpeg(char * name, struct ImBuf * ibuf, int flags) +{ + int ret; + + ibuf->flags = flags; + if (IS_stdjpg(ibuf)) ret = save_stdjpeg(name, ibuf); + else if (IS_jstjpg(ibuf)) ret = save_jstjpeg(name, ibuf); + else if (IS_maxjpg(ibuf)) ret = save_maxjpeg(name, ibuf); + else ret = save_vidjpeg(name, ibuf); + return(ret); +} + |