This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/imbuf/intern/jpeg.c

758 lines
19 KiB
C
Raw Normal View History

/*
* ***** BEGIN GPL LICENSE BLOCK *****
2002-10-12 11:37:38 +00:00
*
* 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.
2002-10-12 11:37:38 +00:00
*
* 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,
2010-02-12 13:34:04 +00:00
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2002-10-12 11:37:38 +00:00
*
* 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 LICENSE BLOCK *****
2002-10-12 11:37:38 +00:00
*/
2011-02-27 20:23:21 +00:00
/** \file blender/imbuf/intern/jpeg.c
* \ingroup imbuf
*/
2002-10-12 11:37:38 +00:00
/* This little block needed for linking to Blender... */
#include <stdio.h>
#include <setjmp.h>
#include "MEM_guardedalloc.h"
2002-10-12 11:37:38 +00:00
#include "BLI_blenlib.h"
#include "imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "IMB_metadata.h"
#include "IMB_filetype.h"
2002-10-12 11:37:38 +00:00
#include "jpeglib.h"
#include "jerror.h"
2002-10-12 11:37:38 +00:00
2012-05-16 07:38:23 +00:00
#define IS_jpg(x) (x->ftype & JPG)
#define IS_stdjpg(x) ((x->ftype & JPG_MSK) == JPG_STD)
#define IS_vidjpg(x) ((x->ftype & JPG_MSK) == JPG_VID)
#define IS_jstjpg(x) ((x->ftype & JPG_MSK) == JPG_JST)
#define IS_maxjpg(x) ((x->ftype & JPG_MSK) == JPG_MAX)
2002-10-12 11:37:38 +00:00
/* the types are from the jpeg lib */
2012-05-16 07:38:23 +00:00
static void jpeg_error(j_common_ptr cinfo);
2002-10-12 11:37:38 +00:00
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, size_t size);
2012-05-16 07:38:23 +00:00
static boolean handle_app1(j_decompress_ptr cinfo);
static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int flags);
2002-10-12 11:37:38 +00:00
/*
2003-04-27 09:59:36 +00:00
* In principle there are 4 jpeg formats.
2012-02-27 10:35:39 +00:00
*
2003-04-27 09:59:36 +00:00
* 1. jpeg - standard printing, u & v at quarter of resulution
* 2. jvid - standaard video, u & v half resolution, frame not interlaced
2012-03-09 18:28:30 +00:00
*
* type 3 is unsupported as of jul 05 2000 Frank.
*
* 3. jstr - as 2, but written in 2 separate fields
2012-03-09 18:28:30 +00:00
*
2003-04-27 09:59:36 +00:00
* 4. jmax - no scaling in the components
2002-10-12 11:37:38 +00:00
*/
static int jpeg_default_quality;
static int ibuf_ftype;
int imb_is_a_jpeg(unsigned char *mem)
{
2012-05-16 07:38:23 +00:00
if ((mem[0] == 0xFF) && (mem[1] == 0xD8)) return 1;
return 0;
}
//----------------------------------------------------------
// JPG ERROR HANDLING
//----------------------------------------------------------
typedef struct my_error_mgr {
2012-05-16 07:38:23 +00:00
struct jpeg_error_mgr pub; /* "public" fields */
2012-05-16 07:38:23 +00:00
jmp_buf setjmp_buffer; /* for return to caller */
} my_error_mgr;
2012-05-16 07:38:23 +00:00
typedef my_error_mgr *my_error_ptr;
2012-05-16 07:38:23 +00:00
static void jpeg_error(j_common_ptr cinfo)
2002-10-12 11:37:38 +00:00
{
my_error_ptr err = (my_error_ptr)cinfo->err;
2002-10-12 11:37:38 +00:00
/* Always display the message */
2012-05-16 07:38:23 +00:00
(*cinfo->err->output_message)(cinfo);
2002-10-12 11:37:38 +00:00
/* Let the memory manager delete any temp files before we die */
jpeg_destroy(cinfo);
/* return control to the setjmp point */
longjmp(err->setjmp_buffer, 1);
2002-10-12 11:37:38 +00:00
}
//----------------------------------------------------------
// INPUT HANDLER FROM MEMORY
2002-10-12 11:37:38 +00:00
//----------------------------------------------------------
typedef struct {
2012-05-16 07:38:23 +00:00
unsigned char *buffer;
int filled;
2002-10-12 11:37:38 +00:00
} buffer_struct;
typedef struct {
2012-05-16 07:38:23 +00:00
struct jpeg_source_mgr pub; /* public fields */
2002-10-12 11:37:38 +00:00
2012-05-16 07:38:23 +00:00
unsigned char *buffer;
int size;
JOCTET terminal[2];
2002-10-12 11:37:38 +00:00
} my_source_mgr;
2012-05-16 07:38:23 +00:00
typedef my_source_mgr *my_src_ptr;
2002-10-12 11:37:38 +00:00
static void init_source(j_decompress_ptr cinfo)
{
(void)cinfo; /* unused */
2002-10-12 11:37:38 +00:00
}
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
2012-03-09 18:28:30 +00:00
* we simply fake an end of file
*/
2002-10-12 11:37:38 +00:00
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;
if (num_bytes > 0) {
// prevent skipping over file end
size_t skip_size = (size_t)num_bytes <= src->pub.bytes_in_buffer ? num_bytes : src->pub.bytes_in_buffer;
src->pub.next_input_byte = src->pub.next_input_byte + skip_size;
src->pub.bytes_in_buffer = src->pub.bytes_in_buffer - skip_size;
}
2002-10-12 11:37:38 +00:00
}
static void term_source(j_decompress_ptr cinfo)
{
(void)cinfo; /* unused */
2002-10-12 11:37:38 +00:00
}
static void memory_source(j_decompress_ptr cinfo, unsigned char *buffer, size_t size)
2002-10-12 11:37:38 +00:00
{
my_src_ptr src;
if (cinfo->src == NULL) { /* first time for this JPEG object? */
2002-10-12 11:37:38 +00:00
cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small)
2012-05-16 07:38:23 +00:00
((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_source_mgr));
2002-10-12 11:37:38 +00:00
}
src = (my_src_ptr) cinfo->src;
2012-05-16 07:38:23 +00:00
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;
2002-10-12 11:37:38 +00:00
2012-05-16 07:38:23 +00:00
src->pub.bytes_in_buffer = size;
src->pub.next_input_byte = buffer;
2002-10-12 11:37:38 +00:00
src->buffer = buffer;
src->size = size;
}
2012-05-16 07:38:23 +00:00
#define MAKESTMT(stuff) do { stuff } while (0)
2002-10-12 11:37:38 +00:00
#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); \
2012-05-27 20:13:59 +00:00
} (void)0
2002-10-12 11:37:38 +00:00
/* Read a byte into variable V.
* If must suspend, take the specified action (typically "return FALSE").
*/
2012-05-16 07:38:23 +00:00
#define INPUT_BYTE(cinfo, V, action) \
MAKESTMT(MAKE_BYTE_AVAIL(cinfo,action); \
bytes_in_buffer--; \
2002-10-12 11:37:38 +00:00
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.
*/
2012-05-16 07:38:23 +00:00
#define INPUT_2BYTES(cinfo, V, action) \
MAKESTMT(MAKE_BYTE_AVAIL(cinfo,action); \
bytes_in_buffer--; \
2002-10-12 11:37:38 +00:00
V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \
2012-05-16 07:38:23 +00:00
MAKE_BYTE_AVAIL(cinfo, action); \
bytes_in_buffer--; \
2002-10-12 11:37:38 +00:00
V += GETJOCTET(*next_input_byte++); )
static boolean
2012-05-16 07:38:23 +00:00
handle_app1(j_decompress_ptr cinfo)
2002-10-12 11:37:38 +00:00
{
INT32 length; /* initialized by the macro */
INT32 i;
2002-10-12 11:37:38 +00:00
char neogeo[128];
INPUT_VARS(cinfo);
2002-10-12 11:37:38 +00:00
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);
}
2012-05-16 07:38:23 +00:00
INPUT_SYNC(cinfo); /* do before skip_input_data */
if (length > 0) (*cinfo->src->skip_input_data)(cinfo, length);
2002-10-12 11:37:38 +00:00
return TRUE;
}
2012-05-16 07:38:23 +00:00
static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int flags)
2002-10-12 11:37:38 +00:00
{
JSAMPARRAY row_pointer;
2012-05-16 07:38:23 +00:00
JSAMPLE *buffer = NULL;
2002-10-12 11:37:38 +00:00
int row_stride;
int x, y, depth, r, g, b, k;
2012-05-16 07:38:23 +00:00
struct ImBuf *ibuf = NULL;
uchar *rect;
jpeg_saved_marker_ptr marker;
char *str, *key, *value;
2002-10-12 11:37:38 +00:00
2003-04-27 09:59:36 +00:00
/* install own app1 handler */
2002-10-12 11:37:38 +00:00
ibuf_ftype = 0;
jpeg_set_marker_processor(cinfo, 0xe1, handle_app1);
cinfo->dct_method = JDCT_FLOAT;
jpeg_save_markers(cinfo, JPEG_COM, 0xffff);
2002-10-12 11:37:38 +00:00
if (jpeg_read_header(cinfo, FALSE) == JPEG_HEADER_OK) {
x = cinfo->image_width;
y = cinfo->image_height;
depth = cinfo->num_components;
2002-10-12 11:37:38 +00:00
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);
}
else if ((ibuf = IMB_allocImBuf(x, y, 8 * depth, IB_rect)) == NULL) {
jpeg_abort_decompress(cinfo);
}
else {
2002-10-12 11:37:38 +00:00
row_stride = cinfo->output_width * depth;
2012-05-16 07:38:23 +00:00
row_pointer = (*cinfo->mem->alloc_sarray)((j_common_ptr) cinfo, JPOOL_IMAGE, row_stride, 1);
2002-10-12 11:37:38 +00:00
for (y = ibuf->y - 1; y >= 0; y--) {
jpeg_read_scanlines(cinfo, row_pointer, 1);
rect = (uchar *) (ibuf->rect + y * ibuf->x);
2002-10-12 11:37:38 +00:00
buffer = row_pointer[0];
switch (depth) {
case 1:
2012-05-16 07:38:23 +00:00
for (x = ibuf->x; x > 0; x--) {
2002-10-12 11:37:38 +00:00
rect[3] = 255;
rect[0] = rect[1] = rect[2] = *buffer++;
rect += 4;
}
2012-02-27 10:35:39 +00:00
break;
case 3:
2012-05-16 07:38:23 +00:00
for (x = ibuf->x; x > 0; x--) {
2002-10-12 11:37:38 +00:00
rect[3] = 255;
rect[0] = *buffer++;
rect[1] = *buffer++;
rect[2] = *buffer++;
rect += 4;
}
2012-02-27 10:35:39 +00:00
break;
case 4:
2012-05-16 07:38:23 +00:00
for (x = ibuf->x; x > 0; x--) {
2002-10-12 11:37:38 +00:00
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;
2012-02-27 10:35:39 +00:00
}
2002-10-12 11:37:38 +00:00
rect[3] = 255 - k;
rect[2] = b;
rect[1] = g;
rect[0] = r;
rect += 4;
}
2002-10-12 11:37:38 +00:00
}
}
2012-05-16 07:38:23 +00:00
marker = cinfo->marker_list;
while (marker) {
if (marker->marker != JPEG_COM)
goto next_stamp_marker;
/*
* Because JPEG format don't support the
* pair "key/value" like PNG, we store the
* stampinfo in a single "encode" string:
* "Blender:key:value"
*
* That is why we need split it to the
* common key/value here.
*/
if (strncmp((char *) marker->data, "Blender", 7)) {
/*
* Maybe the file have text that
* we don't know "what it's", in that
* case we keep the text (with a
* key "None").
* This is only for don't "lose"
* the information when we write
* it back to disk.
*/
IMB_metadata_add_field(ibuf, "None", (char *) marker->data);
ibuf->flags |= IB_metadata;
goto next_stamp_marker;
}
2012-05-16 07:38:23 +00:00
str = BLI_strdup((char *) marker->data);
key = strchr(str, ':');
/*
* A little paranoid, but the file maybe
* is broken... and a "extra" check is better
* then segfault ;)
*/
if (!key) {
MEM_freeN(str);
goto next_stamp_marker;
}
key++;
2012-05-16 07:38:23 +00:00
value = strchr(key, ':');
if (!value) {
MEM_freeN(str);
goto next_stamp_marker;
}
*value = '\0'; /* need finish the key string */
value++;
IMB_metadata_add_field(ibuf, key, value);
ibuf->flags |= IB_metadata;
MEM_freeN(str);
next_stamp_marker:
2012-05-16 07:38:23 +00:00
marker = marker->next;
}
2002-10-12 11:37:38 +00:00
jpeg_finish_decompress(cinfo);
}
jpeg_destroy((j_common_ptr) cinfo);
if (ibuf) {
ibuf->ftype = ibuf_ftype;
ibuf->profile = IB_PROFILE_SRGB;
}
}
2002-10-12 11:37:38 +00:00
return(ibuf);
}
2002-10-12 11:37:38 +00:00
2012-05-16 07:38:23 +00:00
ImBuf *imb_load_jpeg(unsigned char *buffer, size_t size, int flags)
2002-10-12 11:37:38 +00:00
{
struct jpeg_decompress_struct _cinfo, *cinfo = &_cinfo;
struct my_error_mgr jerr;
2012-05-16 07:38:23 +00:00
ImBuf *ibuf;
if (!imb_is_a_jpeg(buffer)) return NULL;
2002-10-12 11:37:38 +00:00
cinfo->err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = jpeg_error;
/* Establish the setjmp return context for my_error_exit to use. */
if (setjmp(jerr.setjmp_buffer)) {
/* If we get here, the JPEG code has signaled an error.
* We need to clean up the JPEG object, close the input file, and return.
*/
jpeg_destroy_decompress(cinfo);
return NULL;
}
2002-10-12 11:37:38 +00:00
jpeg_create_decompress(cinfo);
memory_source(cinfo, buffer, size);
ibuf = ibJpegImageFromCinfo(cinfo, flags);
return(ibuf);
}
2012-05-16 07:38:23 +00:00
static void write_jpeg(struct jpeg_compress_struct *cinfo, struct ImBuf *ibuf)
2002-10-12 11:37:38 +00:00
{
2012-05-16 07:38:23 +00:00
JSAMPLE *buffer = NULL;
2002-10-12 11:37:38 +00:00
JSAMPROW row_pointer[1];
2012-05-16 07:38:23 +00:00
uchar *rect;
2002-10-12 11:37:38 +00:00
int x, y;
char neogeo[128];
ImMetaData *iptr;
char *text;
2002-10-12 11:37:38 +00:00
jpeg_start_compress(cinfo, TRUE);
strcpy(neogeo, "NeoGeo");
ibuf_ftype = BIG_LONG(ibuf->ftype);
memcpy(neogeo + 6, &ibuf_ftype, 4);
2012-05-16 07:38:23 +00:00
jpeg_write_marker(cinfo, 0xe1, (JOCTET *) neogeo, 10);
2002-10-12 11:37:38 +00:00
if (ibuf->metadata) {
/* key + max value + "Blender" */
2012-05-16 07:38:23 +00:00
text = MEM_mallocN(530, "stamp info read");
iptr = ibuf->metadata;
while (iptr) {
2012-05-16 07:38:23 +00:00
if (!strcmp(iptr->key, "None")) {
jpeg_write_marker(cinfo, JPEG_COM, (JOCTET *) iptr->value, strlen(iptr->value) + 1);
goto next_stamp_info;
}
/*
* The JPEG format don't support a pair "key/value"
* like PNG, so we "encode" the stamp in a
* single string:
* "Blender:key:value"
*
* The first "Blender" is a simple identify to help
* in the read process.
*/
2012-05-16 07:38:23 +00:00
sprintf(text, "Blender:%s:%s", iptr->key, iptr->value);
jpeg_write_marker(cinfo, JPEG_COM, (JOCTET *) text, strlen(text) + 1);
next_stamp_info:
iptr = iptr->next;
}
MEM_freeN(text);
}
2002-10-12 11:37:38 +00:00
row_pointer[0] =
2012-05-16 07:38:23 +00:00
MEM_mallocN(sizeof(JSAMPLE) *
cinfo->input_components *
cinfo->image_width, "jpeg row_pointer");
2002-10-12 11:37:38 +00:00
for (y = ibuf->y - 1; y >= 0; y--) {
2002-10-12 11:37:38 +00:00
rect = (uchar *) (ibuf->rect + y * ibuf->x);
buffer = row_pointer[0];
switch (cinfo->in_color_space) {
2012-02-27 10:35:39 +00:00
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;
2012-05-16 07:38:23 +00:00
/* default was missing... intentional ? */
2012-02-27 10:35:39 +00:00
default:
; /* do nothing */
2002-10-12 11:37:38 +00:00
}
jpeg_write_scanlines(cinfo, row_pointer, 1);
}
jpeg_finish_compress(cinfo);
MEM_freeN(row_pointer[0]);
2002-10-12 11:37:38 +00:00
}
2012-05-16 07:38:23 +00:00
static int init_jpeg(FILE *outfile, struct jpeg_compress_struct *cinfo, struct ImBuf *ibuf)
2002-10-12 11:37:38 +00:00
{
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->planes == 8) cinfo->in_color_space = JCS_GRAYSCALE;
#if 0
/* just write RGBA as RGB,
* unsupported feature only confuses other s/w */
if (ibuf->planes == 32) cinfo->in_color_space = JCS_UNKNOWN;
#endif
switch (cinfo->in_color_space) {
2012-02-27 10:35:39 +00:00
case JCS_RGB:
cinfo->input_components = 3;
break;
case JCS_GRAYSCALE:
cinfo->input_components = 1;
break;
case JCS_UNKNOWN:
cinfo->input_components = 4;
break;
2012-05-16 07:38:23 +00:00
/* default was missing... intentional ? */
2012-02-27 10:35:39 +00:00
default:
; /* do nothing */
2002-10-12 11:37:38 +00:00
}
jpeg_set_defaults(cinfo);
2003-04-27 09:59:36 +00:00
/* own settings */
2002-10-12 11:37:38 +00:00
cinfo->dct_method = JDCT_FLOAT;
jpeg_set_quality(cinfo, quality, TRUE);
return(0);
}
static int save_stdjpeg(const char *name, struct ImBuf *ibuf)
2002-10-12 11:37:38 +00:00
{
2012-05-16 07:38:23 +00:00
FILE *outfile;
2002-10-12 11:37:38 +00:00
struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo;
struct my_error_mgr jerr;
2002-10-12 11:37:38 +00:00
if ((outfile = BLI_fopen(name, "wb")) == NULL) return 0;
2002-10-12 11:37:38 +00:00
jpeg_default_quality = 75;
cinfo->err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = jpeg_error;
/* Establish the setjmp return context for jpeg_error to use. */
if (setjmp(jerr.setjmp_buffer)) {
/* If we get here, the JPEG code has signaled an error.
* We need to clean up the JPEG object, close the input file, and return.
*/
jpeg_destroy_compress(cinfo);
fclose(outfile);
remove(name);
return 0;
}
2002-10-12 11:37:38 +00:00
init_jpeg(outfile, cinfo, ibuf);
write_jpeg(cinfo, ibuf);
fclose(outfile);
jpeg_destroy_compress(cinfo);
return 1;
2002-10-12 11:37:38 +00:00
}
static int save_vidjpeg(const char *name, struct ImBuf *ibuf)
2002-10-12 11:37:38 +00:00
{
2012-05-16 07:38:23 +00:00
FILE *outfile;
2002-10-12 11:37:38 +00:00
struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo;
struct my_error_mgr jerr;
2002-10-12 11:37:38 +00:00
if ((outfile = BLI_fopen(name, "wb")) == NULL) return 0;
2002-10-12 11:37:38 +00:00
jpeg_default_quality = 90;
cinfo->err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = jpeg_error;
/* Establish the setjmp return context for jpeg_error to use. */
if (setjmp(jerr.setjmp_buffer)) {
/* If we get here, the JPEG code has signaled an error.
* We need to clean up the JPEG object, close the input file, and return.
*/
jpeg_destroy_compress(cinfo);
fclose(outfile);
remove(name);
return 0;
}
2002-10-12 11:37:38 +00:00
init_jpeg(outfile, cinfo, ibuf);
2003-04-27 09:59:36 +00:00
/* adjust scaling factors */
2002-10-12 11:37:38 +00:00
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);
return 1;
2002-10-12 11:37:38 +00:00
}
static int save_jstjpeg(const char *name, struct ImBuf *ibuf)
2002-10-12 11:37:38 +00:00
{
char fieldname[1024];
2012-05-16 07:38:23 +00:00
struct ImBuf *tbuf;
int oldy, returnval;
2002-10-12 11:37:38 +00:00
tbuf = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 24, IB_rect);
2002-10-12 11:37:38 +00:00
tbuf->ftype = ibuf->ftype;
tbuf->flags = ibuf->flags;
oldy = ibuf->y;
ibuf->x *= 2;
ibuf->y /= 2;
IMB_rectcpy(tbuf, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
2002-10-12 11:37:38 +00:00
sprintf(fieldname, "%s.jf0", name);
2012-02-27 10:35:39 +00:00
returnval = save_vidjpeg(fieldname, tbuf);
if (returnval == 1) {
IMB_rectcpy(tbuf, ibuf, 0, 0, tbuf->x, 0, ibuf->x, ibuf->y);
2002-10-12 11:37:38 +00:00
sprintf(fieldname, "%s.jf1", name);
returnval = save_vidjpeg(fieldname, tbuf);
2002-10-12 11:37:38 +00:00
}
ibuf->y = oldy;
ibuf->x /= 2;
IMB_freeImBuf(tbuf);
return returnval;
2002-10-12 11:37:38 +00:00
}
static int save_maxjpeg(const char *name, struct ImBuf *ibuf)
2002-10-12 11:37:38 +00:00
{
2012-05-16 07:38:23 +00:00
FILE *outfile;
2002-10-12 11:37:38 +00:00
struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo;
struct my_error_mgr jerr;
2002-10-12 11:37:38 +00:00
if ((outfile = BLI_fopen(name, "wb")) == NULL) return 0;
2002-10-12 11:37:38 +00:00
jpeg_default_quality = 100;
cinfo->err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = jpeg_error;
/* Establish the setjmp return context for jpeg_error to use. */
if (setjmp(jerr.setjmp_buffer)) {
/* If we get here, the JPEG code has signaled an error.
* We need to clean up the JPEG object, close the input file, and return.
*/
jpeg_destroy_compress(cinfo);
fclose(outfile);
remove(name);
return 0;
}
2002-10-12 11:37:38 +00:00
init_jpeg(outfile, cinfo, ibuf);
2003-04-27 09:59:36 +00:00
/* adjust scaling factors */
2002-10-12 11:37:38 +00:00
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);
return 1;
2002-10-12 11:37:38 +00:00
}
int imb_savejpeg(struct ImBuf *ibuf, const char *name, int flags)
2002-10-12 11:37:38 +00:00
{
ibuf->flags = flags;
if (IS_stdjpg(ibuf)) return save_stdjpeg(name, ibuf);
if (IS_jstjpg(ibuf)) return save_jstjpeg(name, ibuf);
if (IS_maxjpg(ibuf)) return save_maxjpeg(name, ibuf);
return save_vidjpeg(name, ibuf);
2002-10-12 11:37:38 +00:00
}