/* * epsonds-jpeg.c - Epson ESC/I-2 driver, JPEG support. * * Copyright (C) 2015 Tower Technologies * Author: Alessandro Zummo * * This file is part of the SANE package. * * 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, version 2. */ #define DEBUG_DECLARE_ONLY #include "sane/config.h" #include #include "epsonds.h" #include "epsonds-jpeg.h" #include "epsonds-ops.h" #include struct my_error_mgr { struct jpeg_error_mgr pub; jmp_buf setjmp_buffer; }; typedef struct my_error_mgr * my_error_ptr; METHODDEF(void) my_error_exit (j_common_ptr cinfo) { char buffer[JMSG_LENGTH_MAX]; (*cinfo->err->format_message) (cinfo, buffer); DBG(10,"Jpeg decode error [%s]", buffer); } LOCAL(struct jpeg_error_mgr *) jpeg_custom_error (struct my_error_mgr * err) { struct jpeg_error_mgr* pRet = jpeg_std_error(&(err->pub)); err->pub.error_exit = my_error_exit; return pRet; } typedef struct { struct jpeg_source_mgr pub; JOCTET *buffer; int length; } epsonds_src_mgr; METHODDEF(void) jpeg_init_source(j_decompress_ptr __sane_unused__ cinfo) { } METHODDEF(void) jpeg_term_source(j_decompress_ptr __sane_unused__ cinfo) { } METHODDEF(boolean) jpeg_fill_input_buffer(j_decompress_ptr cinfo) { epsonds_src_mgr *src = (epsonds_src_mgr *)cinfo->src; /* read from scanner if no data? */ src->pub.next_input_byte = src->buffer; src->pub.bytes_in_buffer = src->length; DBG(18, "reading from ring buffer, %d left\n", src->length); return TRUE; } METHODDEF (void) jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes) { epsonds_src_mgr *src = (epsonds_src_mgr *)cinfo->src; if (num_bytes > 0) { while (num_bytes > (long)src->pub.bytes_in_buffer) { num_bytes -= (long)src->pub.bytes_in_buffer; jpeg_fill_input_buffer(cinfo); } src->pub.next_input_byte += (size_t) num_bytes; src->pub.bytes_in_buffer -= (size_t) num_bytes; } } void eds_decode_jpeg(epsonds_scanner*s, SANE_Byte *data, SANE_Int size, ring_buffer* ringBuffer, SANE_Int isBackSide, SANE_Int needToConvertBW) { struct jpeg_decompress_struct jpeg_cinfo; struct my_error_mgr jpeg_err; { epsonds_src_mgr *src; jpeg_cinfo.err = jpeg_custom_error(&jpeg_err); jpeg_create_decompress(&jpeg_cinfo); jpeg_cinfo.src = (struct jpeg_source_mgr *)(*jpeg_cinfo.mem->alloc_small)((j_common_ptr)&jpeg_cinfo, JPOOL_PERMANENT, sizeof(epsonds_src_mgr)); memset(jpeg_cinfo.src, 0x00, sizeof(epsonds_src_mgr)); ; src = (epsonds_src_mgr *)jpeg_cinfo.src; src->pub.init_source = jpeg_init_source; src->pub.fill_input_buffer = jpeg_fill_input_buffer; src->pub.skip_input_data = jpeg_skip_input_data; src->pub.resync_to_restart = jpeg_resync_to_restart; src->pub.term_source = jpeg_term_source; src->pub.bytes_in_buffer = 0; src->pub.next_input_byte = NULL; src->buffer = (JOCTET*)data; src->length = size; } { if (jpeg_read_header(&jpeg_cinfo, TRUE)) { if (jpeg_start_decompress(&jpeg_cinfo)) { DBG(10,"%s: w: %d, h: %d, components: %d\n", __func__, jpeg_cinfo.output_width, jpeg_cinfo.output_height, jpeg_cinfo.output_components); } } } { int sum = 0; int bufSize = jpeg_cinfo.output_width * jpeg_cinfo.output_components; int monoBufSize = (jpeg_cinfo.output_width + 7)/8; JSAMPARRAY scanlines = (jpeg_cinfo.mem->alloc_sarray)((j_common_ptr)&jpeg_cinfo, JPOOL_IMAGE, bufSize, 1); while (jpeg_cinfo.output_scanline < jpeg_cinfo.output_height) { int l = jpeg_read_scanlines(&jpeg_cinfo, scanlines, 1); if (l == 0) { break; } sum += l; if (needToConvertBW) { SANE_Byte* bytes = scanlines[0]; SANE_Int imgPos = 0; for (int i = 0; i < monoBufSize; i++) { SANE_Byte outByte = 0; for(SANE_Int bitIndex = 0; bitIndex < 8 && imgPos < bufSize; bitIndex++) { //DBG(10,"bytes[imgPos] = %d\n", bytes[imgPos]); if(bytes[imgPos] >= 110) { SANE_Byte bit = 7 - (bitIndex % 8); outByte |= (1<< bit); } imgPos += 1; } //DBG(10,"outByte = %d\n", outByte); eds_ring_write(ringBuffer, &outByte, 1); } } else { eds_ring_write(ringBuffer, scanlines[0], bufSize); } // decode until valida data if (isBackSide) { if (sum >= s->height_back) { break; } }else { if (sum >= s->height_front) { break; } } } DBG(10,"decodded lines = %d\n", sum); // abandon unncessary data if ((JDIMENSION)sum < jpeg_cinfo.output_height) { // unncessary data while(1) { int l = jpeg_read_scanlines(&jpeg_cinfo, scanlines, 1); if (l == 0) { break; } } } // if not auto crop mode padding to lines if (s->val[OPT_ADF_CRP].w == 0) { unsigned char* padding = malloc(s->params.bytes_per_line); memset(padding, 255, s->params.bytes_per_line); DBG(10,"padding data lines = %d to %d pa \n", sum, s->params.lines); while(sum < s->params.lines) { eds_ring_write(ringBuffer, padding, bufSize); sum++; } free(padding); padding = NULL; } } { jpeg_finish_decompress(&jpeg_cinfo); jpeg_destroy_decompress(&jpeg_cinfo); } return; }