-Replaced tinyjpg for jpgd (public domain), fixes progressive encoded jpgs and speeds up. Closes #2040

-Removed support of loading BitMap as image, now it must be load as a pnm, also closes #2040
This commit is contained in:
Juan Linietsky 2016-01-03 17:14:28 -03:00
parent b988f016fd
commit e8fbf39f88
24 changed files with 3985 additions and 3236 deletions

View file

@ -1636,12 +1636,16 @@ int64_t String::to_int64() const {
return integer*sign;
}
int String::to_int(const char* p_str) {
int String::to_int(const char* p_str,int p_len) {
int to=0;
while(p_str[to]!=0 && p_str[to]!='.')
to++;
if (p_len>=0)
to=p_len;
else {
while(p_str[to]!=0 && p_str[to]!='.')
to++;
}
int integer=0;

View file

@ -144,7 +144,7 @@ public:
int to_int() const;
int64_t to_int64() const;
static int to_int(const char* p_str);
static int to_int(const char* p_str, int p_len=-1);
static double to_double(const char* p_str);
static double to_double(const CharType* p_str, const CharType **r_end=NULL);
static int64_t to_int(const CharType* p_str,int p_len=-1);

View file

@ -12,11 +12,13 @@ SConscript('windows/SCsub');
SConscript('gles2/SCsub');
SConscript('gl_context/SCsub');
SConscript('openssl/SCsub');
SConscript('pnm/SCsub');
if (env["png"]=="yes"):
SConscript("png/SCsub");
if (env["jpg"]=="yes"):
SConscript("jpg/SCsub");
#SConscript("jpg/SCsub");
SConscript("jpegd/SCsub");
if (env["webp"]=="yes"):
SConscript("webp/SCsub");
SConscript("dds/SCsub");

View file

@ -2,9 +2,8 @@ Import('env')
jpg_sources = [
"jpg/tinyjpeg.c",
"jpg/jidctflt.c",
"jpg/image_loader_jpg.cpp"
"jpegd/jpgd.cpp",
"jpegd/image_loader_jpegd.cpp"
]
env.drivers_sources+=jpg_sources

View file

@ -0,0 +1,108 @@
/*************************************************/
/* image_loader_jpg.cpp */
/*************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
#include "image_loader_jpegd.h"
#include "print_string.h"
#include "os/os.h"
#include "jpgd.h"
#include <string.h>
Error ImageLoaderJPG::load_image(Image *p_image,FileAccess *f) {
DVector<uint8_t> src_image;
int src_image_len = f->get_len();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
src_image.resize(src_image_len);
DVector<uint8_t>::Write w = src_image.write();
f->get_buffer(&w[0],src_image_len);
f->close();
jpgd::jpeg_decoder_mem_stream mem_stream(w.ptr(),src_image_len);
jpgd::jpeg_decoder decoder(&mem_stream);
if (decoder.get_error_code() != jpgd::JPGD_SUCCESS) {
return ERR_CANT_OPEN;
}
const int image_width = decoder.get_width();
const int image_height = decoder.get_height();
int comps = decoder.get_num_components();
if (comps==3)
comps=4; //weird
if (decoder.begin_decoding() != jpgd::JPGD_SUCCESS)
return ERR_FILE_CORRUPT;
const int dst_bpl = image_width * comps;
DVector<uint8_t> data;
data.resize(dst_bpl * image_height);
DVector<uint8_t>::Write dw = data.write();
jpgd::uint8 *pImage_data = (jpgd::uint8*)dw.ptr();
for (int y = 0; y < image_height; y++)
{
const jpgd::uint8* pScan_line;
uint scan_line_len;
if (decoder.decode((const void**)&pScan_line, &scan_line_len) != jpgd::JPGD_SUCCESS)
{
return ERR_FILE_CORRUPT;
}
jpgd::uint8 *pDst = pImage_data + y * dst_bpl;
memcpy(pDst, pScan_line, dst_bpl);
}
//all good
Image::Format fmt;
if (comps==1)
fmt=Image::FORMAT_GRAYSCALE;
else
fmt=Image::FORMAT_RGBA;
dw = DVector<uint8_t>::Write();
w = DVector<uint8_t>::Write();
p_image->create(image_width,image_height,0,fmt,data);
return OK;
}
void ImageLoaderJPG::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("jpg");
p_extensions->push_back("jpeg");
}
ImageLoaderJPG::ImageLoaderJPG() {
}

3172
drivers/jpegd/jpgd.cpp Normal file

File diff suppressed because it is too large Load diff

319
drivers/jpegd/jpgd.h Normal file
View file

@ -0,0 +1,319 @@
// jpgd.h - C++ class for JPEG decompression.
// Public domain, Rich Geldreich <richgel99@gmail.com>
#ifndef JPEG_DECODER_H
#define JPEG_DECODER_H
#include <stdlib.h>
#include <stdio.h>
#include <setjmp.h>
#ifdef _MSC_VER
#define JPGD_NORETURN __declspec(noreturn)
#elif defined(__GNUC__)
#define JPGD_NORETURN __attribute__ ((noreturn))
#else
#define JPGD_NORETURN
#endif
namespace jpgd
{
typedef unsigned char uint8;
typedef signed short int16;
typedef unsigned short uint16;
typedef unsigned int uint;
typedef signed int int32;
// Loads a JPEG image from a memory buffer or a file.
// req_comps can be 1 (grayscale), 3 (RGB), or 4 (RGBA).
// On return, width/height will be set to the image's dimensions, and actual_comps will be set to the either 1 (grayscale) or 3 (RGB).
// Notes: For more control over where and how the source data is read, see the decompress_jpeg_image_from_stream() function below, or call the jpeg_decoder class directly.
// Requesting a 8 or 32bpp image is currently a little faster than 24bpp because the jpeg_decoder class itself currently always unpacks to either 8 or 32bpp.
unsigned char *decompress_jpeg_image_from_memory(const unsigned char *pSrc_data, int src_data_size, int *width, int *height, int *actual_comps, int req_comps);
unsigned char *decompress_jpeg_image_from_file(const char *pSrc_filename, int *width, int *height, int *actual_comps, int req_comps);
// Success/failure error codes.
enum jpgd_status
{
JPGD_SUCCESS = 0, JPGD_FAILED = -1, JPGD_DONE = 1,
JPGD_BAD_DHT_COUNTS = -256, JPGD_BAD_DHT_INDEX, JPGD_BAD_DHT_MARKER, JPGD_BAD_DQT_MARKER, JPGD_BAD_DQT_TABLE,
JPGD_BAD_PRECISION, JPGD_BAD_HEIGHT, JPGD_BAD_WIDTH, JPGD_TOO_MANY_COMPONENTS,
JPGD_BAD_SOF_LENGTH, JPGD_BAD_VARIABLE_MARKER, JPGD_BAD_DRI_LENGTH, JPGD_BAD_SOS_LENGTH,
JPGD_BAD_SOS_COMP_ID, JPGD_W_EXTRA_BYTES_BEFORE_MARKER, JPGD_NO_ARITHMITIC_SUPPORT, JPGD_UNEXPECTED_MARKER,
JPGD_NOT_JPEG, JPGD_UNSUPPORTED_MARKER, JPGD_BAD_DQT_LENGTH, JPGD_TOO_MANY_BLOCKS,
JPGD_UNDEFINED_QUANT_TABLE, JPGD_UNDEFINED_HUFF_TABLE, JPGD_NOT_SINGLE_SCAN, JPGD_UNSUPPORTED_COLORSPACE,
JPGD_UNSUPPORTED_SAMP_FACTORS, JPGD_DECODE_ERROR, JPGD_BAD_RESTART_MARKER, JPGD_ASSERTION_ERROR,
JPGD_BAD_SOS_SPECTRAL, JPGD_BAD_SOS_SUCCESSIVE, JPGD_STREAM_READ, JPGD_NOTENOUGHMEM
};
// Input stream interface.
// Derive from this class to read input data from sources other than files or memory. Set m_eof_flag to true when no more data is available.
// The decoder is rather greedy: it will keep on calling this method until its internal input buffer is full, or until the EOF flag is set.
// It the input stream contains data after the JPEG stream's EOI (end of image) marker it will probably be pulled into the internal buffer.
// Call the get_total_bytes_read() method to determine the actual size of the JPEG stream after successful decoding.
class jpeg_decoder_stream
{
public:
jpeg_decoder_stream() { }
virtual ~jpeg_decoder_stream() { }
// The read() method is called when the internal input buffer is empty.
// Parameters:
// pBuf - input buffer
// max_bytes_to_read - maximum bytes that can be written to pBuf
// pEOF_flag - set this to true if at end of stream (no more bytes remaining)
// Returns -1 on error, otherwise return the number of bytes actually written to the buffer (which may be 0).
// Notes: This method will be called in a loop until you set *pEOF_flag to true or the internal buffer is full.
virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag) = 0;
};
// stdio FILE stream class.
class jpeg_decoder_file_stream : public jpeg_decoder_stream
{
jpeg_decoder_file_stream(const jpeg_decoder_file_stream &);
jpeg_decoder_file_stream &operator =(const jpeg_decoder_file_stream &);
FILE *m_pFile;
bool m_eof_flag, m_error_flag;
public:
jpeg_decoder_file_stream();
virtual ~jpeg_decoder_file_stream();
bool open(const char *Pfilename);
void close();
virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag);
};
// Memory stream class.
class jpeg_decoder_mem_stream : public jpeg_decoder_stream
{
const uint8 *m_pSrc_data;
uint m_ofs, m_size;
public:
jpeg_decoder_mem_stream() : m_pSrc_data(NULL), m_ofs(0), m_size(0) { }
jpeg_decoder_mem_stream(const uint8 *pSrc_data, uint size) : m_pSrc_data(pSrc_data), m_ofs(0), m_size(size) { }
virtual ~jpeg_decoder_mem_stream() { }
bool open(const uint8 *pSrc_data, uint size);
void close() { m_pSrc_data = NULL; m_ofs = 0; m_size = 0; }
virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag);
};
// Loads JPEG file from a jpeg_decoder_stream.
unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, int *width, int *height, int *actual_comps, int req_comps);
enum
{
JPGD_IN_BUF_SIZE = 8192, JPGD_MAX_BLOCKS_PER_MCU = 10, JPGD_MAX_HUFF_TABLES = 8, JPGD_MAX_QUANT_TABLES = 4,
JPGD_MAX_COMPONENTS = 4, JPGD_MAX_COMPS_IN_SCAN = 4, JPGD_MAX_BLOCKS_PER_ROW = 8192, JPGD_MAX_HEIGHT = 16384, JPGD_MAX_WIDTH = 16384
};
typedef int16 jpgd_quant_t;
typedef int16 jpgd_block_t;
class jpeg_decoder
{
public:
// Call get_error_code() after constructing to determine if the stream is valid or not. You may call the get_width(), get_height(), etc.
// methods after the constructor is called. You may then either destruct the object, or begin decoding the image by calling begin_decoding(), then decode() on each scanline.
jpeg_decoder(jpeg_decoder_stream *pStream);
~jpeg_decoder();
// Call this method after constructing the object to begin decompression.
// If JPGD_SUCCESS is returned you may then call decode() on each scanline.
int begin_decoding();
// Returns the next scan line.
// For grayscale images, pScan_line will point to a buffer containing 8-bit pixels (get_bytes_per_pixel() will return 1).
// Otherwise, it will always point to a buffer containing 32-bit RGBA pixels (A will always be 255, and get_bytes_per_pixel() will return 4).
// Returns JPGD_SUCCESS if a scan line has been returned.
// Returns JPGD_DONE if all scan lines have been returned.
// Returns JPGD_FAILED if an error occurred. Call get_error_code() for a more info.
int decode(const void** pScan_line, uint* pScan_line_len);
inline jpgd_status get_error_code() const { return m_error_code; }
inline int get_width() const { return m_image_x_size; }
inline int get_height() const { return m_image_y_size; }
inline int get_num_components() const { return m_comps_in_frame; }
inline int get_bytes_per_pixel() const { return m_dest_bytes_per_pixel; }
inline int get_bytes_per_scan_line() const { return m_image_x_size * get_bytes_per_pixel(); }
// Returns the total number of bytes actually consumed by the decoder (which should equal the actual size of the JPEG file).
inline int get_total_bytes_read() const { return m_total_bytes_read; }
private:
jpeg_decoder(const jpeg_decoder &);
jpeg_decoder &operator =(const jpeg_decoder &);
typedef void (*pDecode_block_func)(jpeg_decoder *, int, int, int);
struct huff_tables
{
bool ac_table;
uint look_up[256];
uint look_up2[256];
uint8 code_size[256];
uint tree[512];
};
struct coeff_buf
{
uint8 *pData;
int block_num_x, block_num_y;
int block_len_x, block_len_y;
int block_size;
};
struct mem_block
{
mem_block *m_pNext;
size_t m_used_count;
size_t m_size;
char m_data[1];
};
jmp_buf m_jmp_state;
mem_block *m_pMem_blocks;
int m_image_x_size;
int m_image_y_size;
jpeg_decoder_stream *m_pStream;
int m_progressive_flag;
uint8 m_huff_ac[JPGD_MAX_HUFF_TABLES];
uint8* m_huff_num[JPGD_MAX_HUFF_TABLES]; // pointer to number of Huffman codes per bit size
uint8* m_huff_val[JPGD_MAX_HUFF_TABLES]; // pointer to Huffman codes per bit size
jpgd_quant_t* m_quant[JPGD_MAX_QUANT_TABLES]; // pointer to quantization tables
int m_scan_type; // Gray, Yh1v1, Yh1v2, Yh2v1, Yh2v2 (CMYK111, CMYK4114 no longer supported)
int m_comps_in_frame; // # of components in frame
int m_comp_h_samp[JPGD_MAX_COMPONENTS]; // component's horizontal sampling factor
int m_comp_v_samp[JPGD_MAX_COMPONENTS]; // component's vertical sampling factor
int m_comp_quant[JPGD_MAX_COMPONENTS]; // component's quantization table selector
int m_comp_ident[JPGD_MAX_COMPONENTS]; // component's ID
int m_comp_h_blocks[JPGD_MAX_COMPONENTS];
int m_comp_v_blocks[JPGD_MAX_COMPONENTS];
int m_comps_in_scan; // # of components in scan
int m_comp_list[JPGD_MAX_COMPS_IN_SCAN]; // components in this scan
int m_comp_dc_tab[JPGD_MAX_COMPONENTS]; // component's DC Huffman coding table selector
int m_comp_ac_tab[JPGD_MAX_COMPONENTS]; // component's AC Huffman coding table selector
int m_spectral_start; // spectral selection start
int m_spectral_end; // spectral selection end
int m_successive_low; // successive approximation low
int m_successive_high; // successive approximation high
int m_max_mcu_x_size; // MCU's max. X size in pixels
int m_max_mcu_y_size; // MCU's max. Y size in pixels
int m_blocks_per_mcu;
int m_max_blocks_per_row;
int m_mcus_per_row, m_mcus_per_col;
int m_mcu_org[JPGD_MAX_BLOCKS_PER_MCU];
int m_total_lines_left; // total # lines left in image
int m_mcu_lines_left; // total # lines left in this MCU
int m_real_dest_bytes_per_scan_line;
int m_dest_bytes_per_scan_line; // rounded up
int m_dest_bytes_per_pixel; // 4 (RGB) or 1 (Y)
huff_tables* m_pHuff_tabs[JPGD_MAX_HUFF_TABLES];
coeff_buf* m_dc_coeffs[JPGD_MAX_COMPONENTS];
coeff_buf* m_ac_coeffs[JPGD_MAX_COMPONENTS];
int m_eob_run;
int m_block_y_mcu[JPGD_MAX_COMPONENTS];
uint8* m_pIn_buf_ofs;
int m_in_buf_left;
int m_tem_flag;
bool m_eof_flag;
uint8 m_in_buf_pad_start[128];
uint8 m_in_buf[JPGD_IN_BUF_SIZE + 128];
uint8 m_in_buf_pad_end[128];
int m_bits_left;
uint m_bit_buf;
int m_restart_interval;
int m_restarts_left;
int m_next_restart_num;
int m_max_mcus_per_row;
int m_max_blocks_per_mcu;
int m_expanded_blocks_per_mcu;
int m_expanded_blocks_per_row;
int m_expanded_blocks_per_component;
bool m_freq_domain_chroma_upsample;
int m_max_mcus_per_col;
uint m_last_dc_val[JPGD_MAX_COMPONENTS];
jpgd_block_t* m_pMCU_coefficients;
int m_mcu_block_max_zag[JPGD_MAX_BLOCKS_PER_MCU];
uint8* m_pSample_buf;
int m_crr[256];
int m_cbb[256];
int m_crg[256];
int m_cbg[256];
uint8* m_pScan_line_0;
uint8* m_pScan_line_1;
jpgd_status m_error_code;
bool m_ready_flag;
int m_total_bytes_read;
void free_all_blocks();
JPGD_NORETURN void stop_decoding(jpgd_status status);
void *alloc(size_t n, bool zero = false);
void word_clear(void *p, uint16 c, uint n);
void prep_in_buffer();
void read_dht_marker();
void read_dqt_marker();
void read_sof_marker();
void skip_variable_marker();
void read_dri_marker();
void read_sos_marker();
int next_marker();
int process_markers();
void locate_soi_marker();
void locate_sof_marker();
int locate_sos_marker();
void init(jpeg_decoder_stream * pStream);
void create_look_ups();
void fix_in_buffer();
void transform_mcu(int mcu_row);
void transform_mcu_expand(int mcu_row);
coeff_buf* coeff_buf_open(int block_num_x, int block_num_y, int block_len_x, int block_len_y);
inline jpgd_block_t *coeff_buf_getp(coeff_buf *cb, int block_x, int block_y);
void load_next_row();
void decode_next_row();
void make_huff_table(int index, huff_tables *pH);
void check_quant_tables();
void check_huff_tables();
void calc_mcu_block_order();
int init_scan();
void init_frame();
void process_restart();
void decode_scan(pDecode_block_func decode_block_func);
void init_progressive();
void init_sequential();
void decode_start();
void decode_init(jpeg_decoder_stream * pStream);
void H2V2Convert();
void H2V1Convert();
void H1V2Convert();
void H1V1Convert();
void gray_convert();
void expanded_convert();
void find_eoi();
inline uint get_char();
inline uint get_char(bool *pPadding_flag);
inline void stuff_char(uint8 q);
inline uint8 get_octet();
inline uint get_bits(int num_bits);
inline uint get_bits_no_markers(int numbits);
inline int huff_decode(huff_tables *pH);
inline int huff_decode(huff_tables *pH, int& extrabits);
static inline uint8 clamp(int i);
static void decode_block_dc_first(jpeg_decoder *pD, int component_id, int block_x, int block_y);
static void decode_block_dc_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y);
static void decode_block_ac_first(jpeg_decoder *pD, int component_id, int block_x, int block_y);
static void decode_block_ac_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y);
};
} // namespace jpgd
#endif // JPEG_DECODER_H

View file

@ -1,93 +0,0 @@
/*************************************************/
/* image_loader_jpg.cpp */
/*************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
#include "image_loader_jpg.h"
#include "print_string.h"
#include "os/os.h"
#include "drivers/jpg/tinyjpeg.h"
static void* _tinyjpg_alloc(unsigned int amount) {
return memalloc(amount);
}
static void _tinyjpg_free(void *ptr) {
memfree(ptr);
}
Error ImageLoaderJPG::load_image(Image *p_image,FileAccess *f) {
DVector<uint8_t> src_image;
int src_image_len = f->get_len();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
src_image.resize(src_image_len);
DVector<uint8_t>::Write w = src_image.write();
f->get_buffer(&w[0],src_image_len);
f->close();
jdec_private* jdec=tinyjpeg_init(_tinyjpg_alloc,_tinyjpg_free);
ERR_FAIL_COND_V(!jdec,ERR_UNAVAILABLE);
int ret = tinyjpeg_parse_header(jdec,&w[0],src_image_len);
if (ret!=0) {
tinyjpeg_free(jdec);
}
ERR_FAIL_COND_V(ret!=0,ERR_FILE_CORRUPT);
unsigned int width,height;
tinyjpeg_get_size(jdec,&width,&height);
DVector<uint8_t> imgdata;
imgdata.resize(width*height*3);
DVector<uint8_t>::Write imgdataw = imgdata.write();
unsigned char *components[1]={&imgdataw[0]};
tinyjpeg_set_components(jdec,components,1);
tinyjpeg_decode(jdec,TINYJPEG_FMT_RGB24);
imgdataw = DVector<uint8_t>::Write();
Image dst_image(width,height,0,Image::FORMAT_RGB,imgdata);
tinyjpeg_free(jdec);
*p_image=dst_image;
return OK;
}
void ImageLoaderJPG::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("jpg");
p_extensions->push_back("jpeg");
}
ImageLoaderJPG::ImageLoaderJPG() {
}

View file

@ -1,286 +0,0 @@
/*
* jidctflt.c
*
* Copyright (C) 1994-1998, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
*
* The authors make NO WARRANTY or representation, either express or implied,
* with respect to this software, its quality, accuracy, merchantability, or
* fitness for a particular purpose. This software is provided "AS IS", and you,
* its user, assume the entire risk as to its quality and accuracy.
*
* This software is copyright (C) 1991-1998, Thomas G. Lane.
* All Rights Reserved except as specified below.
*
* Permission is hereby granted to use, copy, modify, and distribute this
* software (or portions thereof) for any purpose, without fee, subject to these
* conditions:
* (1) If any part of the source code for this software is distributed, then this
* README file must be included, with this copyright and no-warranty notice
* unaltered; and any additions, deletions, or changes to the original files
* must be clearly indicated in accompanying documentation.
* (2) If only executable code is distributed, then the accompanying
* documentation must state that "this software is based in part on the work of
* the Independent JPEG Group".
* (3) Permission for use of this software is granted only if the user accepts
* full responsibility for any undesirable consequences; the authors accept
* NO LIABILITY for damages of any kind.
*
* These conditions apply to any software derived from or based on the IJG code,
* not just to the unmodified library. If you use our work, you ought to
* acknowledge us.
*
* Permission is NOT granted for the use of any IJG author's name or company name
* in advertising or publicity relating to this software or products derived from
* it. This software may be referred to only as "the Independent JPEG Group's
* software".
*
* We specifically permit and encourage the use of this software as the basis of
* commercial products, provided that all warranty or liability claims are
* assumed by the product vendor.
*
*
* This file contains a floating-point implementation of the
* inverse DCT (Discrete Cosine Transform). In the IJG code, this routine
* must also perform dequantization of the input coefficients.
*
* This implementation should be more accurate than either of the integer
* IDCT implementations. However, it may not give the same results on all
* machines because of differences in roundoff behavior. Speed will depend
* on the hardware's floating point capacity.
*
* A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
* on each row (or vice versa, but it's more convenient to emit a row at
* a time). Direct algorithms are also available, but they are much more
* complex and seem not to be any faster when reduced to code.
*
* This implementation is based on Arai, Agui, and Nakajima's algorithm for
* scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
* Japanese, but the algorithm is described in the Pennebaker & Mitchell
* JPEG textbook (see REFERENCES section in file README). The following code
* is based directly on figure 4-8 in P&M.
* While an 8-point DCT cannot be done in less than 11 multiplies, it is
* possible to arrange the computation so that many of the multiplies are
* simple scalings of the final outputs. These multiplies can then be
* folded into the multiplications or divisions by the JPEG quantization
* table entries. The AA&N method leaves only 5 multiplies and 29 adds
* to be done in the DCT itself.
* The primary disadvantage of this method is that with a fixed-point
* implementation, accuracy is lost due to imprecise representation of the
* scaled quantization values. However, that problem does not arise if
* we use floating point arithmetic.
*/
#include "tinyjpeg-internal.h"
#define FAST_FLOAT float
#define DCTSIZE 8
#define DCTSIZE2 (DCTSIZE*DCTSIZE)
#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval))
#if 0 && defined(__GNUC__) && (defined(__i686__))
// || defined(__x86_64__))
static inline unsigned char descale_and_clamp(int x, int shift)
{
__asm__ (
"add %3,%1\n"
"\tsar %2,%1\n"
"\tsub $-128,%1\n"
"\tcmovl %5,%1\n" /* Use the sub to compare to 0 */
"\tcmpl %4,%1\n"
"\tcmovg %4,%1\n"
: "=r"(x)
: "0"(x), "Ir"(shift), "ir"(1UL<<(shift-1)), "r" (0xff), "r" (0)
);
return x;
}
#else
static __inline unsigned char descale_and_clamp(int x, int shift)
{
x += (1UL<<(shift-1));
if (x<0)
x = (x >> shift) | ((~(0UL)) << (32-(shift)));
else
x >>= shift;
x += 128;
if (x>255)
return 255;
else if (x<0)
return 0;
else
return x;
}
#endif
/*
* Perform dequantization and inverse DCT on one block of coefficients.
*/
void
tinyjpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride)
{
FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
FAST_FLOAT z5, z10, z11, z12, z13;
int16_t *inptr;
FAST_FLOAT *quantptr;
FAST_FLOAT *wsptr;
uint8_t *outptr;
int ctr;
FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */
/* Pass 1: process columns from input, store into work array. */
inptr = compptr->DCT;
quantptr = compptr->Q_table;
wsptr = workspace;
for (ctr = DCTSIZE; ctr > 0; ctr--) {
/* Due to quantization, we will usually find that many of the input
* coefficients are zero, especially the AC terms. We can exploit this
* by short-circuiting the IDCT calculation for any column in which all
* the AC terms are zero. In that case each output is equal to the
* DC coefficient (with scale factor as needed).
* With typical images and quantization tables, half or more of the
* column DCT calculations can be simplified this way.
*/
if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
inptr[DCTSIZE*7] == 0) {
/* AC terms all zero */
FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
wsptr[DCTSIZE*0] = dcval;
wsptr[DCTSIZE*1] = dcval;
wsptr[DCTSIZE*2] = dcval;
wsptr[DCTSIZE*3] = dcval;
wsptr[DCTSIZE*4] = dcval;
wsptr[DCTSIZE*5] = dcval;
wsptr[DCTSIZE*6] = dcval;
wsptr[DCTSIZE*7] = dcval;
inptr++; /* advance pointers to next column */
quantptr++;
wsptr++;
continue;
}
/* Even part */
tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
tmp10 = tmp0 + tmp2; /* phase 3 */
tmp11 = tmp0 - tmp2;
tmp13 = tmp1 + tmp3; /* phases 5-3 */
tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */
tmp0 = tmp10 + tmp13; /* phase 2 */
tmp3 = tmp10 - tmp13;
tmp1 = tmp11 + tmp12;
tmp2 = tmp11 - tmp12;
/* Odd part */
tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
z13 = tmp6 + tmp5; /* phase 6 */
z10 = tmp6 - tmp5;
z11 = tmp4 + tmp7;
z12 = tmp4 - tmp7;
tmp7 = z11 + z13; /* phase 5 */
tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */
z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */
tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */
tmp6 = tmp12 - tmp7; /* phase 2 */
tmp5 = tmp11 - tmp6;
tmp4 = tmp10 + tmp5;
wsptr[DCTSIZE*0] = tmp0 + tmp7;
wsptr[DCTSIZE*7] = tmp0 - tmp7;
wsptr[DCTSIZE*1] = tmp1 + tmp6;
wsptr[DCTSIZE*6] = tmp1 - tmp6;
wsptr[DCTSIZE*2] = tmp2 + tmp5;
wsptr[DCTSIZE*5] = tmp2 - tmp5;
wsptr[DCTSIZE*4] = tmp3 + tmp4;
wsptr[DCTSIZE*3] = tmp3 - tmp4;
inptr++; /* advance pointers to next column */
quantptr++;
wsptr++;
}
/* Pass 2: process rows from work array, store into output array. */
/* Note that we must descale the results by a factor of 8 == 2**3. */
wsptr = workspace;
outptr = output_buf;
for (ctr = 0; ctr < DCTSIZE; ctr++) {
/* Rows of zeroes can be exploited in the same way as we did with columns.
* However, the column calculation has created many nonzero AC terms, so
* the simplification applies less often (typically 5% to 10% of the time).
* And testing floats for zero is relatively expensive, so we don't bother.
*/
/* Even part */
tmp10 = wsptr[0] + wsptr[4];
tmp11 = wsptr[0] - wsptr[4];
tmp13 = wsptr[2] + wsptr[6];
tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13;
tmp0 = tmp10 + tmp13;
tmp3 = tmp10 - tmp13;
tmp1 = tmp11 + tmp12;
tmp2 = tmp11 - tmp12;
/* Odd part */
z13 = wsptr[5] + wsptr[3];
z10 = wsptr[5] - wsptr[3];
z11 = wsptr[1] + wsptr[7];
z12 = wsptr[1] - wsptr[7];
tmp7 = z11 + z13;
tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562);
z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */
tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */
tmp6 = tmp12 - tmp7;
tmp5 = tmp11 - tmp6;
tmp4 = tmp10 + tmp5;
/* Final output stage: scale down by a factor of 8 and range-limit */
outptr[0] = descale_and_clamp((int)(tmp0 + tmp7), 3);
outptr[7] = descale_and_clamp((int)(tmp0 - tmp7), 3);
outptr[1] = descale_and_clamp((int)(tmp1 + tmp6), 3);
outptr[6] = descale_and_clamp((int)(tmp1 - tmp6), 3);
outptr[2] = descale_and_clamp((int)(tmp2 + tmp5), 3);
outptr[5] = descale_and_clamp((int)(tmp2 - tmp5), 3);
outptr[4] = descale_and_clamp((int)(tmp3 + tmp4), 3);
outptr[3] = descale_and_clamp((int)(tmp3 - tmp4), 3);
wsptr += DCTSIZE; /* advance pointer to next row */
outptr += stride;
}
}

View file

@ -1,341 +0,0 @@
/*
* Small jpeg decoder library - testing application
*
* Copyright (c) 2006, Luc Saillard <luc@saillard.org>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the author nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "tinyjpeg.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define snprintf(buf, size, fmt, ...) sprintf(buf, fmt, __VA_ARGS__)
static void exitmessage(const char *message) __attribute__((noreturn));
static void exitmessage(const char *message)
{
printf("%s\n", message);
exit(0);
}
static int filesize(FILE *fp)
{
long pos;
fseek(fp, 0, SEEK_END);
pos = ftell(fp);
fseek(fp, 0, SEEK_SET);
return pos;
}
/**
* Save a buffer in 24bits Targa format
* (BGR byte order)
*/
static void write_tga(const char *filename, int output_format, int width, int height, unsigned char **components)
{
unsigned char targaheader[18];
FILE *F;
char temp[1024];
unsigned int bufferlen = width * height * 3;
unsigned char *rgb_data = components[0];
sprintf(temp, sizeof(temp), filename);
memset(targaheader,0,sizeof(targaheader));
targaheader[12] = (unsigned char) (width & 0xFF);
targaheader[13] = (unsigned char) (width >> 8);
targaheader[14] = (unsigned char) (height & 0xFF);
targaheader[15] = (unsigned char) (height >> 8);
targaheader[17] = 0x20; /* Top-down, non-interlaced */
targaheader[2] = 2; /* image type = uncompressed RGB */
targaheader[16] = 24;
if (output_format == TINYJPEG_FMT_RGB24)
{
unsigned char *data = rgb_data + bufferlen - 3;
do
{
unsigned char c = data[0];
data[0] = data[2];
data[2] = c;
data-=3;
}
while (data > rgb_data);
}
F = fopen(temp, "wb");
fwrite(targaheader, sizeof(targaheader), 1, F);
fwrite(rgb_data, 1, bufferlen, F);
fclose(F);
}
/**
* Save a buffer in three files (.Y, .U, .V) useable by yuvsplittoppm
*/
static void write_yuv(const char *filename, int width, int height, unsigned char **components)
{
FILE *F;
char temp[1024];
snprintf(temp, 1024, "%s.Y", filename);
F = fopen(temp, "wb");
fwrite(components[0], width, height, F);
fclose(F);
snprintf(temp, 1024, "%s.U", filename);
F = fopen(temp, "wb");
fwrite(components[1], width*height/4, 1, F);
fclose(F);
snprintf(temp, 1024, "%s.V", filename);
F = fopen(temp, "wb");
fwrite(components[2], width*height/4, 1, F);
fclose(F);
}
/**
* Save a buffer in grey image (pgm format)
*/
static void write_pgm(const char *filename, int width, int height, unsigned char **components)
{
FILE *F;
char temp[1024];
snprintf(temp, 1024, "%s", filename);
F = fopen(temp, "wb");
fprintf(F, "P5\n%d %d\n255\n", width, height);
fwrite(components[0], width, height, F);
fclose(F);
}
/**
* Load one jpeg image, and try to decompress 1000 times, and save the result.
* This is mainly used for benchmarking the decoder, or to test if between each
* called of the library the DCT is corrected reset (a bug was found).
*/
int load_multiple_times(const char *filename, const char *outfilename, int output_format)
{
FILE *fp;
int count, length_of_file;
unsigned int width, height;
unsigned char *buf;
struct jdec_private *jdec;
unsigned char *components[4];
jdec = tinyjpeg_init();
count = 0;
/* Load the Jpeg into memory */
fp = fopen(filename, "rb");
if (fp == NULL)
exitmessage("Cannot open filename\n");
length_of_file = filesize(fp);
buf = (unsigned char *)malloc(length_of_file + 4);
fread(buf, length_of_file, 1, fp);
fclose(fp);
while (count<1000)
{
if (tinyjpeg_parse_header(jdec, buf, length_of_file)<0)
exitmessage(tinyjpeg_get_errorstring(jdec));
tinyjpeg_decode(jdec, output_format);
count++;
}
/*
* Get address for each plane (not only max 3 planes is supported), and
* depending of the output mode, only some components will be filled
* RGB: 1 plane, YUV420P: 3 planes, GREY: 1 plane
*/
tinyjpeg_get_components(jdec, components);
tinyjpeg_get_size(jdec, &width, &height);
/* Save it */
switch (output_format)
{
case TINYJPEG_FMT_RGB24:
case TINYJPEG_FMT_BGR24:
write_tga(outfilename, output_format, width, height, components);
break;
case TINYJPEG_FMT_YUV420P:
write_yuv(outfilename, width, height, components);
break;
case TINYJPEG_FMT_GREY:
write_pgm(outfilename, width, height, components);
break;
}
free(buf);
tinyjpeg_free(jdec);
return 0;
}
/**
* Load one jpeg image, and decompress it, and save the result.
*/
int convert_one_image(const char *infilename, const char *outfilename, int output_format)
{
FILE *fp;
unsigned int length_of_file;
unsigned int width, height;
unsigned char *buf;
struct jdec_private *jdec;
unsigned char *components[3];
/* Load the Jpeg into memory */
fp = fopen(infilename, "rb");
if (fp == NULL)
exitmessage("Cannot open filename\n");
length_of_file = filesize(fp);
buf = (unsigned char *)malloc(length_of_file + 4);
if (buf == NULL)
exitmessage("Not enough memory for loading file\n");
fread(buf, length_of_file, 1, fp);
fclose(fp);
/* Decompress it */
jdec = tinyjpeg_init();
if (jdec == NULL)
exitmessage("Not enough memory to alloc the structure need for decompressing\n");
if (tinyjpeg_parse_header(jdec, buf, length_of_file)<0)
exitmessage(tinyjpeg_get_errorstring(jdec));
/* Get the size of the image */
tinyjpeg_get_size(jdec, &width, &height);
printf("Decoding JPEG image...\n");
if (tinyjpeg_decode(jdec, output_format) < 0)
exitmessage(tinyjpeg_get_errorstring(jdec));
/*
* Get address for each plane (not only max 3 planes is supported), and
* depending of the output mode, only some components will be filled
* RGB: 1 plane, YUV420P: 3 planes, GREY: 1 plane
*/
tinyjpeg_get_components(jdec, components);
/* Save it */
switch (output_format)
{
case TINYJPEG_FMT_RGB24:
case TINYJPEG_FMT_BGR24:
write_tga(outfilename, output_format, width, height, components);
break;
case TINYJPEG_FMT_YUV420P:
write_yuv(outfilename, width, height, components);
break;
case TINYJPEG_FMT_GREY:
write_pgm(outfilename, width, height, components);
break;
}
/* Only called this if the buffers were allocated by tinyjpeg_decode() */
tinyjpeg_free(jdec);
/* else called just free(jdec); */
free(buf);
return 0;
}
static void usage(void)
{
fprintf(stderr, "Usage: loadjpeg [options] <input_filename.jpeg> <format> <output_filename>\n");
fprintf(stderr, "options:\n");
fprintf(stderr, " --benchmark - Convert 1000 times the same image\n");
fprintf(stderr, "format:\n");
fprintf(stderr, " yuv420p - output 3 files .Y,.U,.V\n");
fprintf(stderr, " rgb24 - output a .tga image\n");
fprintf(stderr, " bgr24 - output a .tga image\n");
fprintf(stderr, " gray - output a .pgm image\n");
exit(1);
}
/**
* main
*
*/
int main(int argc, char *argv[])
{
int output_format = TINYJPEG_FMT_YUV420P;
char *output_filename, *input_filename;
clock_t start_time, finish_time;
unsigned int duration;
int current_argument;
int benchmark_mode = 0;
if (argc < 3)
usage();
current_argument = 1;
while (1)
{
if (strcmp(argv[current_argument], "--benchmark")==0)
benchmark_mode = 1;
else
break;
current_argument++;
}
if (argc < current_argument+2)
usage();
input_filename = argv[current_argument];
if (strcmp(argv[current_argument+1],"yuv420p")==0)
output_format = TINYJPEG_FMT_YUV420P;
else if (strcmp(argv[current_argument+1],"rgb24")==0)
output_format = TINYJPEG_FMT_RGB24;
else if (strcmp(argv[current_argument+1],"bgr24")==0)
output_format = TINYJPEG_FMT_BGR24;
else if (strcmp(argv[current_argument+1],"grey")==0)
output_format = TINYJPEG_FMT_GREY;
else
exitmessage("Bad format: need to be one of yuv420p, rgb24, bgr24, grey\n");
output_filename = argv[current_argument+2];
start_time = clock();
if (benchmark_mode)
load_multiple_times(input_filename, output_filename, output_format);
else
convert_one_image(input_filename, output_filename, output_format);
finish_time = clock();
duration = finish_time - start_time;
printf("Decoding finished in %u ticks\n", duration);
return 0;
}

View file

@ -1,162 +0,0 @@
/*
* Small jpeg decoder library (Internal header)
*
* Copyright (c) 2006, Luc Saillard <luc@saillard.org>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the author nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __TINYJPEG_INTERNAL_H_
#define __TINYJPEG_INTERNAL_H_
#ifdef _MSC_VER
typedef signed __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef signed __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef signed __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#ifdef NO_STDINT_H
typedef unsigned char uint8_t;
typedef signed char int8_t;
typedef unsigned short uint16_t;
typedef signed short int16_t;
typedef unsigned int uint32_t;
typedef signed int int32_t;
typedef long long int64_t;
typedef unsigned long long int64_t;
#else
#include <stdint.h>
#endif
#endif
#include <setjmp.h>
#define SANITY_CHECK 1
struct jdec_private;
#define HUFFMAN_BITS_SIZE 256
#define HUFFMAN_HASH_NBITS 9
#define HUFFMAN_HASH_SIZE (1UL<<HUFFMAN_HASH_NBITS)
#define HUFFMAN_HASH_MASK (HUFFMAN_HASH_SIZE-1)
#define HUFFMAN_TABLES 4
#define COMPONENTS 3
#define JPEG_MAX_WIDTH 4096
#define JPEG_MAX_HEIGHT 4096
struct huffman_table
{
/* Fast look up table, using HUFFMAN_HASH_NBITS bits we can have directly the symbol,
* if the symbol is <0, then we need to look into the tree table */
short int lookup[HUFFMAN_HASH_SIZE];
/* code size: give the number of bits of a symbol is encoded */
unsigned char code_size[HUFFMAN_HASH_SIZE];
/* some place to store value that is not encoded in the lookup table
* FIXME: Calculate if 256 value is enough to store all values
*/
uint16_t slowtable[16-HUFFMAN_HASH_NBITS][256];
};
struct component
{
unsigned int Hfactor;
unsigned int Vfactor;
float *Q_table; /* Pointer to the quantisation table to use */
struct huffman_table *AC_table;
struct huffman_table *DC_table;
short int previous_DC; /* Previous DC coefficient */
short int DCT[64]; /* DCT coef */
#if SANITY_CHECK
unsigned int cid;
#endif
};
typedef void (*decode_MCU_fct) (struct jdec_private *priv);
typedef void (*convert_colorspace_fct) (struct jdec_private *priv);
struct jdec_private
{
void *(*allocate_mem)(unsigned int amount);
void (*free_mem)(void *mem);
/* Public variables */
uint8_t *components[COMPONENTS];
unsigned int width, height; /* Size of the image */
unsigned int flags;
/* Private variables */
const unsigned char *stream_begin, *stream_end;
unsigned int stream_length;
const unsigned char *stream; /* Pointer to the current stream */
unsigned int reservoir, nbits_in_reservoir;
struct component component_infos[COMPONENTS];
float Q_tables[COMPONENTS][64]; /* quantization tables */
struct huffman_table HTDC[HUFFMAN_TABLES]; /* DC huffman tables */
struct huffman_table HTAC[HUFFMAN_TABLES]; /* AC huffman tables */
int default_huffman_table_initialized;
int restart_interval;
int restarts_to_go; /* MCUs left in this restart interval */
int last_rst_marker_seen; /* Rst marker is incremented each time */
/* Temp space used after the IDCT to store each components */
uint8_t Y[64*4], Cr[64], Cb[64];
jmp_buf jump_state;
/* Internal Pointer use for colorspace conversion, do not modify it !!! */
uint8_t *plane[COMPONENTS];
uint8_t decomp_block[16][16*3];
};
#if defined(__GNUC__) && (__GNUC__ > 3) && defined(__OPTIMIZE__)
#define __likely(x) __builtin_expect(!!(x), 1)
#define __unlikely(x) __builtin_expect(!!(x), 0)
#else
#define __likely(x) (x)
#define __unlikely(x) (x)
#endif
#define IDCT tinyjpeg_idct_float
void tinyjpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,74 +0,0 @@
/*
* Small jpeg decoder library (header file)
*
* Copyright (c) 2006, Luc Saillard <luc@saillard.org>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the author nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __JPEGDEC_H__
#define __JPEGDEC_H__
#ifdef __cplusplus
extern "C" {
#endif
struct jdec_private;
/* Flags that can be set by any applications */
#define TINYJPEG_FLAGS_MJPEG_TABLE (1<<1)
/* Format accepted in outout */
enum tinyjpeg_fmt {
TINYJPEG_FMT_GREY = 1,
TINYJPEG_FMT_BGR24,
TINYJPEG_FMT_RGB24,
TINYJPEG_FMT_YUV420P,
};
struct jdec_private *tinyjpeg_init(void *(*allocate_mem)(unsigned int),void (*free_mem)(void *));
void tinyjpeg_free(struct jdec_private *priv);
int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size);
int tinyjpeg_decode(struct jdec_private *priv, int pixel_format);
const char *tinyjpeg_get_errorstring(struct jdec_private *priv);
void tinyjpeg_get_size(struct jdec_private *priv, unsigned int *width, unsigned int *height);
int tinyjpeg_get_components(struct jdec_private *priv, unsigned char **components);
int tinyjpeg_set_components(struct jdec_private *priv, unsigned char **components, unsigned int ncomponents);
int tinyjpeg_set_flags(struct jdec_private *priv, int flags);
#ifdef __cplusplus
}
#endif
#endif

10
drivers/pnm/SCsub Normal file
View file

@ -0,0 +1,10 @@
Import('env')
pnm_sources = [
"pnm/bitmap_loader_pnm.cpp"
]
env.drivers_sources+=pnm_sources
#env.add_source_files(env.drivers_sources, pnm_sources)

View file

@ -0,0 +1,232 @@
/*************************************************/
/* image_loader_jpg.cpp */
/*************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
#include "bitmap_loader_pnm.h"
#include "os/file_access.h"
#include "scene/resources/bit_mask.h"
static bool _get_token(FileAccessRef& f,uint8_t &saved,DVector<uint8_t>& r_token,bool p_binary=false,bool p_single_chunk=false) {
int token_max = r_token.size();
DVector<uint8_t>::Write w;
if (token_max)
w=r_token.write();
int ofs=0;
bool lf=false;
while(true) {
uint8_t b;
if (saved) {
b=saved;
saved=0;
} else {
b = f->get_8();
}
if (f->eof_reached()) {
if (ofs) {
w=DVector<uint8_t>::Write();
r_token.resize(ofs);
return true;
} else {
return false;
}
}
if (!ofs && !p_binary && b=='#') {
//skip comment
while(b!='\n') {
if (f->eof_reached()) {
return false;
}
b = f->get_8();
}
lf=true;
} else if (b<=32 && !(p_binary && (ofs || lf))) {
if (b=='\n') {
lf=true;
}
if (ofs && !p_single_chunk) {
w=DVector<uint8_t>::Write();
r_token.resize(ofs);
saved=b;
return true;
}
} else {
bool resized=false;
while (ofs>=token_max) {
if (token_max)
token_max<<=1;
else
token_max=1;
resized=true;
}
if (resized) {
w=DVector<uint8_t>::Write();
r_token.resize(token_max);
w=r_token.write();
}
w[ofs++]=b;
}
}
return false;
}
static int _get_number_from_token(DVector<uint8_t>& r_token) {
int len = r_token.size();
DVector<uint8_t>::Read r = r_token.read();
return String::to_int((const char*)r.ptr(),len);
}
RES ResourceFormatPBM::load(const String &p_path,const String& p_original_path,Error *r_error) {
#define _RETURN(m_err)\
{\
if (r_error)\
*r_error=m_err;\
ERR_FAIL_V(RES());\
}
FileAccessRef f=FileAccess::open(p_path,FileAccess::READ);
uint8_t saved=0;
if (!f)
_RETURN(ERR_CANT_OPEN);
DVector<uint8_t> token;
if (!_get_token(f,saved,token)) {
_RETURN(ERR_PARSE_ERROR);
}
if (token.size()!=2) {
_RETURN(ERR_FILE_CORRUPT);
}
if (token[0]!='P') {
_RETURN(ERR_FILE_CORRUPT);
}
if (token[1]!='1' && token[1]!='4') {
_RETURN(ERR_FILE_CORRUPT);
}
bool bits = token[1]=='4';
if (!_get_token(f,saved,token)) {
_RETURN(ERR_PARSE_ERROR);
}
int width = _get_number_from_token(token);
if (width<=0) {
_RETURN(ERR_FILE_CORRUPT);
}
if (!_get_token(f,saved,token)) {
_RETURN(ERR_PARSE_ERROR);
}
int height = _get_number_from_token(token);
if (height<=0) {
_RETURN(ERR_FILE_CORRUPT);
}
Ref<BitMap> bm;
bm.instance();
bm->create(Size2i(width,height));
if (!bits) {
int required_bytes = width*height;
if (!_get_token(f,saved,token,false,true)) {
_RETURN(ERR_PARSE_ERROR);
}
if (token.size()<required_bytes) {
_RETURN(ERR_FILE_CORRUPT);
}
DVector<uint8_t>::Read r=token.read();
for(int i=0;i<height;i++) {
for(int j=0;j<width;j++) {
char num = r[i*width+j];
bm->set_bit(Point2i(j,i),num=='0');
}
}
} else {
//a single, entire token of bits!
if (!_get_token(f,saved,token,true)) {
_RETURN(ERR_PARSE_ERROR);
}
int required_bytes = Math::ceil((width*height)/8.0);
if (token.size()<required_bytes) {
_RETURN(ERR_FILE_CORRUPT);
}
DVector<uint8_t>::Read r=token.read();
for(int i=0;i<height;i++) {
for(int j=0;j<width;j++) {
int ofs = width*i+j;
uint8_t byte = r[ofs/8];
bool bit = (byte>>(7-(ofs%8)))&1;
bm->set_bit(Point2i(j,i),!bit);
}
}
}
return bm;
}
void ResourceFormatPBM::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("pbm");
}
bool ResourceFormatPBM::handles_type(const String& p_type) const {
return p_type=="BitMap";
}
String ResourceFormatPBM::get_resource_type(const String &p_path) const {
if (p_path.extension().to_lower()=="pbm")
return "BitMap";
return "";
}

View file

@ -0,0 +1,33 @@
/*************************************************/
/* image_loader_jpg.h */
/*************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
#ifndef BITMAP_LOADER_PNM_H
#define BITMAP_LOADER_PNM_H
#include "io/resource_loader.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
class ResourceFormatPBM : public ResourceFormatLoader {
public:
virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
};
#endif

View file

@ -14,11 +14,12 @@
#include "png/image_loader_png.h"
#include "webp/image_loader_webp.h"
#include "png/resource_saver_png.h"
#include "jpg/image_loader_jpg.h"
#include "jpegd/image_loader_jpegd.h"
#include "dds/texture_loader_dds.h"
#include "pvr/texture_loader_pvr.h"
#include "etc1/image_etc.h"
#include "chibi/event_stream_chibi.h"
#include "pnm/bitmap_loader_pnm.h"
#ifdef TOOLS_ENABLED
@ -112,6 +113,9 @@ static ResourceFormatLoaderAudioStreamMPC * mpc_stream_loader=NULL;
#include "openssl/register_openssl.h"
#endif
static ResourceFormatPBM * pbm_loader=NULL;
void register_core_driver_types() {
#ifdef PNG_ENABLED
@ -138,6 +142,9 @@ void register_core_driver_types() {
ImageLoader::add_image_format_loader( image_loader_jpg );
#endif
pbm_loader = memnew( ResourceFormatPBM );
ResourceLoader::add_resource_format_loader(pbm_loader);
ObjectTypeDB::register_type<RegEx>();
}
@ -162,6 +169,7 @@ void unregister_core_driver_types() {
memdelete( image_loader_jpg );
#endif
memdelete( pbm_loader );
}

View file

@ -221,7 +221,7 @@
static ResourceFormatLoaderImage *resource_loader_image=NULL;
static ResourceFormatLoaderWAV *resource_loader_wav=NULL;
static ResourceFormatLoaderBitMap *resource_loader_bitmap=NULL;
#ifdef TOOLS_ENABLED
@ -249,8 +249,6 @@ void register_scene_types() {
resource_loader_wav = memnew( ResourceFormatLoaderWAV );
ResourceLoader::add_resource_format_loader( resource_loader_wav );
resource_loader_bitmap = memnew( ResourceFormatLoaderBitMap );
ResourceLoader::add_resource_format_loader( resource_loader_bitmap );
#ifdef TOOLS_ENABLED
@ -631,7 +629,6 @@ void unregister_scene_types() {
memdelete( resource_loader_image );
memdelete( resource_loader_wav );
memdelete( resource_loader_bitmap );
#ifdef TOOLS_ENABLED

View file

@ -204,57 +204,3 @@ BitMap::BitMap() {
//////////////////////////////////////
RES ResourceFormatLoaderBitMap::load(const String &p_path, const String& p_original_path, Error *r_error) {
if (r_error)
*r_error=ERR_FILE_CANT_OPEN;
BitMap* ptr = memnew(BitMap);
Ref<BitMap> bitmap( ptr );
Image image;
Error err = ImageLoader::load_image(p_path,&image);
ERR_EXPLAIN("Failed loading image for BitMap: "+p_path);
ERR_FAIL_COND_V(err, RES());
bitmap->create_from_image_alpha(image);
if (r_error)
*r_error=OK;
return bitmap;
}
bool ResourceFormatLoaderBitMap::handles_type(const String& p_type) const {
return (p_type=="BitMap");
}
void ResourceFormatLoaderBitMap::get_recognized_extensions(List<String> *p_extensions) const {
ImageLoader::get_recognized_extensions(p_extensions);
}
String ResourceFormatLoaderBitMap::get_resource_type(const String &p_path) const {
List<String> extensions;
ImageLoader::get_recognized_extensions(&extensions);
String ext=p_path.extension().to_lower();
for(List<String>::Element *E=extensions.front();E;E=E->next()) {
if (E->get()==ext)
return "BitMap";
}
return "";
}
ResourceFormatLoaderBitMap::ResourceFormatLoaderBitMap() {
}

View file

@ -62,16 +62,5 @@ public:
BitMap();
};
class ResourceFormatLoaderBitMap : public ResourceFormatLoader {
public:
virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
ResourceFormatLoaderBitMap();
};
#endif // BIT_MASK_H

View file

@ -5953,6 +5953,7 @@ EditorNode::EditorNode() {
resource_preview->add_preview_generator( Ref<EditorScriptPreviewPlugin>( memnew(EditorScriptPreviewPlugin )));
resource_preview->add_preview_generator( Ref<EditorSamplePreviewPlugin>( memnew(EditorSamplePreviewPlugin )));
resource_preview->add_preview_generator( Ref<EditorMeshPreviewPlugin>( memnew(EditorMeshPreviewPlugin )));
resource_preview->add_preview_generator( Ref<EditorBitmapPreviewPlugin>( memnew(EditorBitmapPreviewPlugin )));
circle_step_msec=OS::get_singleton()->get_ticks_msec();
circle_step_frame=OS::get_singleton()->get_frames_drawn();

View file

@ -6,6 +6,7 @@
#include "scene/resources/material.h"
#include "scene/resources/sample.h"
#include "scene/resources/mesh.h"
#include "scene/resources/bit_mask.h"
bool EditorTexturePreviewPlugin::handles(const String& p_type) const {
@ -56,6 +57,81 @@ Ref<Texture> EditorTexturePreviewPlugin::generate(const RES& p_from) {
EditorTexturePreviewPlugin::EditorTexturePreviewPlugin() {
}
////////////////////////////////////////////////////////////////////////////
bool EditorBitmapPreviewPlugin::handles(const String& p_type) const {
return ObjectTypeDB::is_type(p_type,"BitMap");
}
Ref<Texture> EditorBitmapPreviewPlugin::generate(const RES& p_from) {
Ref<BitMap> bm =p_from;
if (bm->get_size()==Size2()) {
return Ref<Texture>();
}
DVector<uint8_t> data;
data.resize(bm->get_size().width*bm->get_size().height);
{
DVector<uint8_t>::Write w=data.write();
for(int i=0;i<bm->get_size().width;i++) {
for(int j=0;j<bm->get_size().height;j++) {
if (bm->get_bit(Point2i(i,j))) {
w[j*bm->get_size().width+i]=255;
} else {
w[j*bm->get_size().width+i]=0;
}
}
}
}
Image img(bm->get_size().width,bm->get_size().height,0,Image::FORMAT_GRAYSCALE,data);
int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
if (img.is_compressed()) {
if (img.decompress()!=OK)
return Ref<Texture>();
} else if (img.get_format()!=Image::FORMAT_RGB && img.get_format()!=Image::FORMAT_RGBA) {
img.convert(Image::FORMAT_RGBA);
}
int width,height;
if (img.get_width() > thumbnail_size && img.get_width() >= img.get_height()) {
width=thumbnail_size;
height = img.get_height() * thumbnail_size / img.get_width();
} else if (img.get_height() > thumbnail_size && img.get_height() >= img.get_width()) {
height=thumbnail_size;
width = img.get_width() * thumbnail_size / img.get_height();
} else {
width=img.get_width();
height=img.get_height();
}
img.resize(width,height);
Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture ));
ptex->create_from_image(img,0);
return ptex;
}
EditorBitmapPreviewPlugin::EditorBitmapPreviewPlugin() {
}
///////////////////////////////////////////////////////////////////////////

View file

@ -13,6 +13,17 @@ public:
};
class EditorBitmapPreviewPlugin : public EditorResourcePreviewGenerator {
public:
virtual bool handles(const String& p_type) const;
virtual Ref<Texture> generate(const RES& p_from);
EditorBitmapPreviewPlugin();
};
class EditorPackedScenePreviewPlugin : public EditorResourcePreviewGenerator {
Ref<Texture> _gen_from_imd(Ref<ResourceImportMetadata> p_imd);