252 lines
7.0 KiB
C
252 lines
7.0 KiB
C
/*------------------------------------------------------------------------
|
|
* Copyright 2009 (c) Jeff Brown <spadix@users.sourceforge.net>
|
|
*
|
|
* This file is part of the ZBar Bar Code Reader.
|
|
*
|
|
* The ZBar Bar Code Reader is free software; you can redistribute it
|
|
* and/or modify it under the terms of the GNU Lesser Public License as
|
|
* published by the Free Software Foundation; either version 2.1 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* The ZBar Bar Code Reader 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 Lesser Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser Public License
|
|
* along with the ZBar Bar Code Reader; if not, write to the Free
|
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301 USA
|
|
*
|
|
* http://sourceforge.net/projects/zbar
|
|
*------------------------------------------------------------------------*/
|
|
|
|
#include "config.h"
|
|
|
|
#ifdef HAVE_LIBJPEG
|
|
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <assert.h> /* FIXME tmp debug */
|
|
#include <jerror.h>
|
|
#include <jpeglib.h>
|
|
#include <setjmp.h>
|
|
|
|
#undef HAVE_STDLIB_H
|
|
#include <zbar.h>
|
|
#include "image.h"
|
|
#include "video.h"
|
|
|
|
#define HAVE_LONGJMP
|
|
#ifdef HAVE_LONGJMP
|
|
|
|
typedef struct errenv_s {
|
|
struct jpeg_error_mgr err;
|
|
int valid;
|
|
jmp_buf env;
|
|
} errenv_t;
|
|
|
|
void zbar_jpeg_error(j_common_ptr cinfo)
|
|
{
|
|
errenv_t *jerr = (errenv_t *)cinfo->err;
|
|
assert(jerr->valid);
|
|
jerr->valid = 0;
|
|
longjmp(jerr->env, 1);
|
|
assert(0);
|
|
}
|
|
|
|
#endif
|
|
|
|
typedef struct zbar_src_mgr_s {
|
|
struct jpeg_source_mgr src;
|
|
const zbar_image_t *img;
|
|
} zbar_src_mgr_t;
|
|
|
|
static const JOCTET fake_eoi[2] = { 0xff, JPEG_EOI };
|
|
|
|
void init_source(j_decompress_ptr cinfo)
|
|
{
|
|
/* buffer/length refer to compressed data */
|
|
/* FIXME find img */
|
|
const zbar_image_t *img = ((zbar_src_mgr_t *)cinfo->src)->img;
|
|
cinfo->src->next_input_byte = img->data;
|
|
cinfo->src->bytes_in_buffer = img->datalen;
|
|
}
|
|
|
|
boolean fill_input_buffer(j_decompress_ptr cinfo)
|
|
{
|
|
/* buffer underrun error case */
|
|
cinfo->src->next_input_byte = fake_eoi;
|
|
cinfo->src->bytes_in_buffer = 2;
|
|
return (1);
|
|
}
|
|
|
|
void skip_input_data(j_decompress_ptr cinfo, long num_bytes)
|
|
{
|
|
if (num_bytes > 0) {
|
|
if (num_bytes < cinfo->src->bytes_in_buffer) {
|
|
cinfo->src->next_input_byte += num_bytes;
|
|
cinfo->src->bytes_in_buffer -= num_bytes;
|
|
} else {
|
|
fill_input_buffer(cinfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
void term_source(j_decompress_ptr cinfo)
|
|
{
|
|
/* nothing todo */
|
|
}
|
|
|
|
struct jpeg_decompress_struct *_zbar_jpeg_decomp_create(void)
|
|
{
|
|
j_decompress_ptr cinfo = calloc(1, sizeof(struct jpeg_decompress_struct));
|
|
if (!cinfo)
|
|
return (NULL);
|
|
|
|
errenv_t *jerr = calloc(1, sizeof(errenv_t));
|
|
if (!jerr) {
|
|
free(cinfo);
|
|
return (NULL);
|
|
}
|
|
|
|
cinfo->err = jpeg_std_error(&jerr->err);
|
|
jerr->err.error_exit = zbar_jpeg_error;
|
|
|
|
jerr->valid = 1;
|
|
if (setjmp(jerr->env)) {
|
|
jpeg_destroy_decompress(cinfo);
|
|
|
|
/* FIXME TBD save error to errinfo_t */
|
|
(*cinfo->err->output_message)((j_common_ptr)cinfo);
|
|
|
|
free(jerr);
|
|
free(cinfo);
|
|
return (NULL);
|
|
}
|
|
|
|
jpeg_create_decompress(cinfo);
|
|
|
|
jerr->valid = 0;
|
|
return (cinfo);
|
|
}
|
|
|
|
void _zbar_jpeg_decomp_destroy(struct jpeg_decompress_struct *cinfo)
|
|
{
|
|
if (cinfo->err) {
|
|
free(cinfo->err);
|
|
cinfo->err = NULL;
|
|
}
|
|
if (cinfo->src) {
|
|
free(cinfo->src);
|
|
cinfo->src = NULL;
|
|
}
|
|
/* FIXME can this error? */
|
|
jpeg_destroy_decompress(cinfo);
|
|
free(cinfo);
|
|
}
|
|
|
|
/* invoke libjpeg to decompress JPEG format to luminance plane */
|
|
void _zbar_convert_jpeg_to_y(zbar_image_t *dst, const zbar_format_def_t *dstfmt,
|
|
const zbar_image_t *src,
|
|
const zbar_format_def_t *srcfmt)
|
|
{
|
|
/* create decompressor, or use cached video stream decompressor */
|
|
errenv_t *jerr = NULL;
|
|
j_decompress_ptr cinfo;
|
|
if (!src->src)
|
|
cinfo = _zbar_jpeg_decomp_create();
|
|
else {
|
|
cinfo = src->src->jpeg;
|
|
assert(cinfo);
|
|
}
|
|
if (!cinfo)
|
|
goto error;
|
|
|
|
jerr = (errenv_t *)cinfo->err;
|
|
jerr->valid = 1;
|
|
if (setjmp(jerr->env)) {
|
|
/* FIXME TBD save error to src->src->err */
|
|
(*cinfo->err->output_message)((j_common_ptr)cinfo);
|
|
if (dst->data) {
|
|
free((void *)dst->data);
|
|
dst->data = NULL;
|
|
}
|
|
dst->datalen = 0;
|
|
goto error;
|
|
}
|
|
|
|
/* setup input image */
|
|
if (!cinfo->src) {
|
|
cinfo->src = calloc(1, sizeof(zbar_src_mgr_t));
|
|
cinfo->src->init_source = init_source;
|
|
cinfo->src->fill_input_buffer = fill_input_buffer;
|
|
cinfo->src->skip_input_data = skip_input_data;
|
|
cinfo->src->resync_to_restart = jpeg_resync_to_restart;
|
|
cinfo->src->term_source = term_source;
|
|
}
|
|
cinfo->src->next_input_byte = NULL;
|
|
cinfo->src->bytes_in_buffer = 0;
|
|
((zbar_src_mgr_t *)cinfo->src)->img = src;
|
|
|
|
int rc = jpeg_read_header(cinfo, TRUE);
|
|
zprintf(30, "header: %s\n", (rc == 2) ? "tables-only" : "normal");
|
|
|
|
/* supporting color with jpeg became...complicated,
|
|
* so we skip that for now
|
|
*/
|
|
cinfo->out_color_space = JCS_GRAYSCALE;
|
|
|
|
/* FIXME set scaling based on dst->{width,height}
|
|
* then pass bigger buffer...
|
|
*/
|
|
|
|
jpeg_start_decompress(cinfo);
|
|
|
|
/* adjust dst image parameters to match(?) decompressor */
|
|
if (dst->width < cinfo->output_width) {
|
|
dst->width = cinfo->output_width;
|
|
if (dst->crop_x + dst->crop_w > dst->width)
|
|
dst->crop_w = dst->width - dst->crop_x;
|
|
}
|
|
if (dst->height < cinfo->output_height) {
|
|
dst->height = cinfo->output_height;
|
|
if (dst->crop_y + dst->crop_h > dst->height)
|
|
dst->crop_h = dst->height - dst->crop_y;
|
|
}
|
|
unsigned long datalen = (cinfo->output_width * cinfo->output_height *
|
|
cinfo->out_color_components);
|
|
|
|
zprintf(24, "dst=%dx%d %lx src=%dx%d %lx dct=%x\n", dst->width, dst->height,
|
|
dst->datalen, src->width, src->height, src->datalen,
|
|
cinfo->dct_method);
|
|
if (!dst->data) {
|
|
dst->datalen = datalen;
|
|
dst->data = malloc(dst->datalen);
|
|
dst->cleanup = zbar_image_free_data;
|
|
} else
|
|
assert(datalen <= dst->datalen);
|
|
if (!dst->data)
|
|
return;
|
|
|
|
unsigned bpl = dst->width * cinfo->output_components;
|
|
JSAMPROW buf = (void *)dst->data;
|
|
JSAMPARRAY line = &buf;
|
|
for (; cinfo->output_scanline < cinfo->output_height; buf += bpl) {
|
|
jpeg_read_scanlines(cinfo, line, 1);
|
|
/* FIXME pad out to dst->width */
|
|
}
|
|
|
|
/* FIXME always do this? */
|
|
jpeg_finish_decompress(cinfo);
|
|
|
|
error:
|
|
if (jerr)
|
|
jerr->valid = 0;
|
|
if (!src->src && cinfo)
|
|
/* cleanup only if we allocated locally */
|
|
_zbar_jpeg_decomp_destroy(cinfo);
|
|
}
|
|
|
|
#endif
|