mirror of
https://github.com/openharmony/third_party_sane-airscan.git
synced 2026-06-30 21:17:55 -04:00
226 lines
5.9 KiB
C
226 lines
5.9 KiB
C
/* AirScan (a.k.a. eSCL) backend for SANE
|
|
*
|
|
* Copyright (C) 2019 and up by Alexander Pevzner (pzz@apevzner.com)
|
|
* See LICENSE for license terms and conditions
|
|
*
|
|
* JPEG image decoder
|
|
*/
|
|
|
|
#include "airscan.h"
|
|
|
|
#include <jpeglib.h>
|
|
#include <setjmp.h>
|
|
#include <string.h>
|
|
|
|
/* JPEG image decoder
|
|
*/
|
|
typedef struct {
|
|
image_decoder decoder; /* Base class */
|
|
struct jpeg_decompress_struct cinfo; /* libjpeg decoder */
|
|
struct jpeg_error_mgr jerr; /* libjpeg error manager */
|
|
jmp_buf jmpb; /* For longjmp from libjpeg */
|
|
char errbuf[ /* Error buffer */
|
|
JMSG_LENGTH_MAX + 16];
|
|
JDIMENSION num_lines; /* Num of lines left to read */
|
|
} image_decoder_jpeg;
|
|
|
|
/* Free JPEG decoder
|
|
*/
|
|
static void
|
|
image_decoder_jpeg_free (image_decoder *decoder)
|
|
{
|
|
image_decoder_jpeg *jpeg = (image_decoder_jpeg*) decoder;
|
|
|
|
jpeg_destroy_decompress(&jpeg->cinfo);
|
|
mem_free(jpeg);
|
|
}
|
|
|
|
/* Begin JPEG decoding
|
|
*/
|
|
static error
|
|
image_decoder_jpeg_begin (image_decoder *decoder, const void *data,
|
|
size_t size)
|
|
{
|
|
image_decoder_jpeg *jpeg = (image_decoder_jpeg*) decoder;
|
|
int rc;
|
|
|
|
if (!setjmp(jpeg->jmpb)) {
|
|
jpeg_mem_src(&jpeg->cinfo, (unsigned char*) data, size);
|
|
|
|
rc = jpeg_read_header(&jpeg->cinfo, true);
|
|
if (rc != JPEG_HEADER_OK) {
|
|
jpeg_abort((j_common_ptr) &jpeg->cinfo);
|
|
return ERROR("JPEG: invalid header");
|
|
}
|
|
|
|
if (jpeg->cinfo.num_components != 1) {
|
|
jpeg->cinfo.out_color_space = JCS_RGB;
|
|
}
|
|
|
|
jpeg_start_decompress(&jpeg->cinfo);
|
|
jpeg->num_lines = jpeg->cinfo.image_height;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
return ERROR(jpeg->errbuf);
|
|
}
|
|
|
|
/* Reset JPEG decoder
|
|
*/
|
|
static void
|
|
image_decoder_jpeg_reset (image_decoder *decoder)
|
|
{
|
|
image_decoder_jpeg *jpeg = (image_decoder_jpeg*) decoder;
|
|
|
|
jpeg_abort((j_common_ptr) &jpeg->cinfo);
|
|
}
|
|
|
|
/* Get bytes count per pixel
|
|
*/
|
|
static int
|
|
image_decoder_jpeg_get_bytes_per_pixel (image_decoder *decoder)
|
|
{
|
|
image_decoder_jpeg *jpeg = (image_decoder_jpeg*) decoder;
|
|
return jpeg->cinfo.num_components;
|
|
}
|
|
|
|
/* Get image parameters
|
|
*/
|
|
static void
|
|
image_decoder_jpeg_get_params (image_decoder *decoder, SANE_Parameters *params)
|
|
{
|
|
image_decoder_jpeg *jpeg = (image_decoder_jpeg*) decoder;
|
|
|
|
params->last_frame = SANE_TRUE;
|
|
params->pixels_per_line = jpeg->cinfo.image_width;
|
|
params->lines = jpeg->cinfo.image_height;
|
|
params->depth = 8;
|
|
|
|
if (jpeg->cinfo.num_components == 1) {
|
|
params->format = SANE_FRAME_GRAY;
|
|
params->bytes_per_line = params->pixels_per_line;
|
|
} else {
|
|
params->format = SANE_FRAME_RGB;
|
|
params->bytes_per_line = params->pixels_per_line * 3;
|
|
}
|
|
}
|
|
|
|
/* Set clipping window
|
|
*/
|
|
static error
|
|
image_decoder_jpeg_set_window (image_decoder *decoder, image_window *win)
|
|
{
|
|
image_decoder_jpeg *jpeg = (image_decoder_jpeg*) decoder;
|
|
|
|
/* Note, image clipping cannot be supported on rather
|
|
* old libjpeg version (i.e., on Ubuntu 16.04, because
|
|
* jpeg_crop_scanline() and jpeg_skip_scanlines() functions
|
|
* are missed. The safe default is to update window to
|
|
* match the entire image dimensions.
|
|
*/
|
|
|
|
#if 1
|
|
win->x_off = win->y_off = 0;
|
|
win->wid = jpeg->cinfo.image_width;
|
|
win->hei = jpeg->cinfo.image_height;
|
|
return NULL;
|
|
#else
|
|
JDIMENSION x_off = win->x_off;
|
|
JDIMENSION wid = win->wid;
|
|
|
|
if (!setjmp(jpeg->jmpb)) {
|
|
jpeg_crop_scanline(&jpeg->cinfo, &x_off, &wid);
|
|
if (win->y_off > 0) {
|
|
jpeg_skip_scanlines(&jpeg->cinfo, win->y_off);
|
|
}
|
|
|
|
jpeg->num_lines = win->hei;
|
|
|
|
win->x_off = x_off;
|
|
win->wid = wid;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
return ERROR(jpeg->errbuf);
|
|
#endif
|
|
}
|
|
|
|
/* Read next line of image
|
|
*/
|
|
static error
|
|
image_decoder_jpeg_read_line (image_decoder *decoder, void *buffer)
|
|
{
|
|
image_decoder_jpeg *jpeg = (image_decoder_jpeg*) decoder;
|
|
JSAMPROW lines[1] = {buffer};
|
|
|
|
if (!jpeg->num_lines) {
|
|
return ERROR("JPEG: end of file");
|
|
}
|
|
|
|
if (!setjmp(jpeg->jmpb)) {
|
|
if (jpeg_read_scanlines(&jpeg->cinfo, lines, 1) == 0) {
|
|
return ERROR(jpeg->errbuf);
|
|
}
|
|
|
|
jpeg->num_lines --;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
return ERROR(jpeg->errbuf);
|
|
}
|
|
|
|
/* "Output error message" callback for JPEG decoder
|
|
*/
|
|
static void
|
|
image_decoder_jpeg_output_message (j_common_ptr cinfo)
|
|
{
|
|
image_decoder_jpeg *jpeg = OUTER_STRUCT(cinfo, image_decoder_jpeg, cinfo);
|
|
|
|
memcpy(jpeg->errbuf, "JPEG: ", 6);
|
|
(*cinfo->err->format_message)(cinfo, jpeg->errbuf + 6);
|
|
}
|
|
|
|
/* error_exit callback for JPEG decoder. The default callback
|
|
* terminates a program, which is not good for us
|
|
*/
|
|
static void
|
|
image_decoder_jpeg_error_exit (j_common_ptr cinfo)
|
|
{
|
|
image_decoder_jpeg *jpeg = OUTER_STRUCT(cinfo, image_decoder_jpeg, cinfo);
|
|
|
|
image_decoder_jpeg_output_message(cinfo);
|
|
|
|
jpeg_abort(cinfo);
|
|
longjmp(jpeg->jmpb, 1);
|
|
}
|
|
|
|
/* Create JPEG image decoder
|
|
*/
|
|
image_decoder*
|
|
image_decoder_jpeg_new (void)
|
|
{
|
|
image_decoder_jpeg *jpeg = mem_new(image_decoder_jpeg, 1);
|
|
|
|
jpeg->decoder.content_type = "image/jpeg";
|
|
jpeg->decoder.free = image_decoder_jpeg_free;
|
|
jpeg->decoder.begin = image_decoder_jpeg_begin;
|
|
jpeg->decoder.reset = image_decoder_jpeg_reset;
|
|
jpeg->decoder.get_bytes_per_pixel = image_decoder_jpeg_get_bytes_per_pixel;
|
|
jpeg->decoder.get_params = image_decoder_jpeg_get_params;
|
|
jpeg->decoder.set_window = image_decoder_jpeg_set_window;
|
|
jpeg->decoder.read_line = image_decoder_jpeg_read_line;
|
|
|
|
jpeg->cinfo.err = jpeg_std_error(&jpeg->jerr);
|
|
jpeg->jerr.output_message = image_decoder_jpeg_output_message;
|
|
jpeg->jerr.error_exit = image_decoder_jpeg_error_exit;
|
|
jpeg_create_decompress(&jpeg->cinfo);
|
|
|
|
return &jpeg->decoder;
|
|
}
|
|
|
|
/* vim:ts=8:sw=4:et
|
|
*/
|