root/software/libpackjpg/lib_src/packjpg.cpp @ fea928c1
| 525a7e92 | David Sorber | /*
|
|
packJPG v2.5k (01/22/2016)
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
packJPG is a compression program specially designed for further
|
|||
compression of JPEG images without causing any further loss. Typically
|
|||
it reduces the file size of a JPEG file by 20%.
|
|||
LGPL v3 license and special permissions
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
All programs in this package are free software; you can redistribute
|
|||
them and/or modify them under the terms of the GNU Lesser General Public
|
|||
License as published by the Free Software Foundation; either version 3
|
|||
of the License, or (at your option) any later version.
|
|||
The package 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
|
|||
General Public License for more details at
|
|||
http://www.gnu.org/copyleft/lgpl.html.
|
|||
If the LGPL v3 license is not compatible with your software project you
|
|||
might contact us and ask for a special permission to use the packJPG
|
|||
library under different conditions. In any case, usage of the packJPG
|
|||
algorithm under the LGPL v3 or above is highly advised and special
|
|||
permissions will only be given where necessary on a case by case basis.
|
|||
This offer is aimed mainly at closed source freeware developers seeking
|
|||
to add PJG support to their software projects.
|
|||
Copyright 2006...2014 by HTW Aalen University and Matthias Stirner.
|
|||
Usage of packJPG
|
|||
~~~~~~~~~~~~~~~~
|
|||
JPEG files are compressed and PJG files are decompressed using this
|
|||
command:
|
|||
"packJPG [file(s)]"
|
|||
packJPG recognizes file types on its own and decides whether to compress
|
|||
(JPG) or decompress (PJG). For unrecognized file types no action is
|
|||
taken. Files are recognized by content, not by extension.
|
|||
packJPG supports wildcards like "*.*" and drag and drop of multiple
|
|||
files. Filenames for output files are created automatically. In default
|
|||
mode, files are never overwritten. If a filename is already in use,
|
|||
packJPG creates a new filename by adding underscores.
|
|||
If "-" is used as a filename input from stdin is assumed and output is
|
|||
written to stdout. This can be useful for example if jpegtran is to be
|
|||
used as a preprocessor.
|
|||
Usage examples:
|
|||
"packJPG *.pjg"
|
|||
"packJPG lena.jpg"
|
|||
"packJPG kodim??.jpg"
|
|||
"packJPG - < sail.pjg > sail.jpg"
|
|||
Command line switches
|
|||
~~~~~~~~~~~~~~~~~~~~~
|
|||
-ver verify files after processing
|
|||
-v? level of verbosity; 0,1 or 2 is allowed (default 0)
|
|||
-np no pause after processing files
|
|||
-o overwrite existing files
|
|||
-p proceed on warnings
|
|||
-d discard meta-info
|
|||
By default, compression is cancelled on warnings. If warnings are
|
|||
skipped by using "-p", most files with warnings can also be compressed,
|
|||
but JPEG files reconstructed from PJG files might not be bitwise
|
|||
identical with the original JPEG files. There won't be any loss to
|
|||
image data or quality however.
|
|||
Unnecessary meta information can be discarded using "-d". This reduces
|
|||
compressed files' sizes. Be warned though, reconstructed files won't be
|
|||
bitwise identical with the original files and meta information will be
|
|||
lost forever. As with "-p" there won't be any loss to image data or
|
|||
quality.
|
|||
There is no known case in which a file compressed by packJPG (without
|
|||
the "-p" option, see above) couldn't be reconstructed to exactly the
|
|||
state it was before. If you want an additional layer of safety you can
|
|||
also use the verify option "-ver". In this mode, files are compressed,
|
|||
then decompressed and the decompressed file compared to the original
|
|||
file. If this test doesn't pass there will be an error message and the
|
|||
compressed file won't be written to the drive.
|
|||
Please note that the "-ver" option should never be used in conjunction
|
|||
with the "-d" and/or "-p" options. As stated above, the "-p" and "-d"
|
|||
options will most likely lead to reconstructed JPG files not being
|
|||
bitwise identical to the original JPG files. In turn, the verification
|
|||
process may fail on various files although nothing actually went wrong.
|
|||
Usage examples:
|
|||
"packJPG -v1 -o baboon.pjg"
|
|||
"packJPG -ver lena.jpg"
|
|||
"packJPG -d tiffany.jpg"
|
|||
"packJPG -p *.jpg"
|
|||
Known Limitations
|
|||
~~~~~~~~~~~~~~~~~
|
|||
packJPG is a compression program specially for JPEG files, so it doesn't
|
|||
compress other file types.
|
|||
packJPG has low error tolerance. JPEG files might not work with packJPG
|
|||
even if they work perfectly with other image processing software. The
|
|||
command line switch "-p" can be used to increase error tolerance and
|
|||
compatibility.
|
|||
If you try to drag and drop to many files at once, there might be a
|
|||
windowed error message about missing privileges. In that case you can
|
|||
try it again with less files or consider using the command prompt.
|
|||
packJPG has been tested to work perfectly with thousands of files from
|
|||
the command line. This issue also happens with drag and drop in other
|
|||
applications, so it might not be a limitation of packJPG but a
|
|||
limitation of Windows.
|
|||
Compressed PJG files are not compatible between different packJPG
|
|||
versions. You will get an error message if you try to decompress PJG
|
|||
files with a different version than the one used for compression. You
|
|||
may download older versions of packJPG from:
|
|||
http://www.elektronik.htw-aalen.de/packJPG/binaries/old/
|
|||
Open source release / developer info
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
The packJPG source codes is found inside the "source" subdirectory.
|
|||
Additional documents aimed to developers, containing detailed
|
|||
instructions on compiling the source code and using special
|
|||
functionality, are included in the "packJPG" subdirectory.
|
|||
History
|
|||
~~~~~~~
|
|||
v1.9a (04/20/2007) (non public)
|
|||
- first released version
|
|||
- only for testing purposes
|
|||
v2.0 (05/28/2007) (public)
|
|||
- first public version of packJPG
|
|||
- minor improvements to overall compression
|
|||
- minor bugfixes
|
|||
v2.2 (08/05/2007) (public)
|
|||
- around 40% faster compression & decompression
|
|||
- major improvements to overall compression (around 2% on average)
|
|||
- reading from stdin, writing to stdout
|
|||
- smaller executable
|
|||
- minor bugfixes
|
|||
- various minor improvements
|
|||
v2.3 (09/18/2007) (public)
|
|||
- compatibility with JPEG progressive mode
|
|||
- compatibility with JPEG extended sequential mode
|
|||
- compatibility with the CMYK color space
|
|||
- compatibility with older CPUs
|
|||
- around 15% faster compression & decompression
|
|||
- new switch: [-d] (discard meta-info)
|
|||
- various bugfixes
|
|||
v2.3a (11/21/2007) (public)
|
|||
- crash issue with certain images fixed
|
|||
- compatibility with packJPG v2.3 maintained
|
|||
v2.3b (12/20/2007) (public)
|
|||
- some minor errors in the packJPG library fixed
|
|||
- compatibility with packJPG v2.3 maintained
|
|||
v2.4 (03/24/2010) (public)
|
|||
- major improvements (1%...2%) to overall compression
|
|||
- around 10% faster compression & decompression
|
|||
- major improvements to JPG compatibility
|
|||
- size of executable reduced to ~33%
|
|||
- new switch: [-ver] (verify file after processing)
|
|||
- new switch: [-np] (no pause after processing)
|
|||
- new progress bar output mode
|
|||
- arithmetic coding routines rewritten from scratch
|
|||
- various smaller improvements to numerous to list here
|
|||
- new SFX (self extracting) archive format
|
|||
v2.5 (11/11/2011) (public)
|
|||
- improvements (~0.5%) to overall compression
|
|||
- several minor bugfixes
|
|||
- major code cleanup
|
|||
- removed packJPX from the package
|
|||
- added packARC to the package
|
|||
- packJPG is now open source!
|
|||
v2.5a (11/21/11) (public)
|
|||
- source code compatibility improvements (Gerhard Seelmann)
|
|||
- avoid some compiler warnings (Gerhard Seelmann)
|
|||
- source code clean up (Gerhard Seelmann)
|
|||
v2.5b (01/27/12) (public)
|
|||
- further removal of redundant code
|
|||
- some fixes for the packJPG static library
|
|||
- compiler fix for Mac OS (thanks to Sergio Lopez)
|
|||
- improved compression ratio calculation
|
|||
- eliminated the need for temp files
|
|||
v2.5c (04/13/12) (public)
|
|||
- various source code optimizations
|
|||
v2.5d (07/03/12) (public)
|
|||
- fixed a rare bug with progressive JPEG
|
|||
v2.5e (07/03/12) (public)
|
|||
- some minor source code optimizations
|
|||
- changed packJPG licensing to LGPL
|
|||
- moved packARC to a separate package
|
|||
v2.5f (02/24/13) (public)
|
|||
- fixed a minor bug in the JPG parser (thanks to Stephan Busch)
|
|||
v2.5g (09/14/13) (public)
|
|||
- fixed a rare crash bug with manipulated JPEG files
|
|||
v2.5h (12/07/13) (public)
|
|||
- added a warning for inefficient huffman coding (thanks to Moinak Ghosh)
|
|||
v2.5i (12/26/13) (public)
|
|||
- fixed possible crash with malformed JPEG (thanks to Moinak Ghosh)
|
|||
v2.5j (01/15/14) (public)
|
|||
- various source code optimizations (using cppcheck)
|
|||
v2.5k (01/22/16) (public)
|
|||
- Updated contact info
|
|||
- fixed a minor bug
|
|||
Acknowledgements
|
|||
~~~~~~~~~~~~~~~~
|
|||
packJPG is the result of countless hours of research and development. It
|
|||
is part of my final year project for Hochschule Aalen.
|
|||
Prof. Dr. Gerhard Seelmann from Hochschule Aalen supported my
|
|||
development of packJPG with his extensive knowledge in the field of data
|
|||
compression. Without his advice, packJPG would not be possible.
|
|||
The official developer blog for packJPG is hosted by encode.ru.
|
|||
packJPG logo and icon are designed by Michael Kaufmann.
|
|||
Contact
|
|||
~~~~~~~
|
|||
The official developer blog for packJPG:
|
|||
http://packjpg.encode.ru/
|
|||
For questions and bug reports:
|
|||
packjpg (at) matthiasstirner.com
|
|||
____________________________________
|
|||
packJPG by Matthias Stirner, 01/2016
|
|||
*/
|
|||
#include <cstdio>
|
|||
#include <cstdlib>
|
|||
#include <cstring>
|
|||
#include <string>
|
|||
#include <cmath>
|
|||
#include <ctime>
|
|||
#include <memory>
|
|||
#include <stdexcept>
|
|||
#include <vector>
|
|||
#include "packjpg.h"
|
|||
#define INIT_MODEL_S(a, b, c) new model_s(a, b, c, 255)
|
|||
#define INIT_MODEL_B(a, b) new model_b(a, b, 255)
|
|||
// #define USE_PLOCOI // uncomment to use loco-i predictor instead of 1DDCT predictor
|
|||
// #define DEV_BUILD // uncomment to include developer functions
|
|||
// #define DEV_INFOS // uncomment to include developer information
|
|||
#define QUANT(cm, bp) (cmpnfo[cm].qtable[bp])
|
|||
#define MAX_V(cm, bp) (( QUANT(cm,bp) > 0 ) ? ( ( freqmax[bp] + QUANT(cm,bp) - 1 ) / QUANT(cm,bp) ) : 0)
|
|||
// #define QUN_V(v,cm,bp) ( ( QUANT(cm,bp) > 0 ) ? ( ( v > 0 ) ? ( v + (QUANT(cm,bp)/2) ) / QUANT(cm,bp) : ( v - (QUANT(cm,bp)/2) ) / QUANT(cm,bp) ) : 0 )
|
|||
#define ENVLI(s, v) (( v > 0 ) ? v : ( v - 1 ) + ( 1 << s ))
|
|||
#define DEVLI(s, n) (( n >= ( 1 << (s - 1) ) ) ? n : n + 1 - ( 1 << s ))
|
|||
#define E_ENVLI(s, v) (v - ( 1 << s ))
|
|||
#define E_DEVLI(s, n) (n + ( 1 << s ))
|
|||
#define ABS(v1) ((v1 < 0) ? -v1 : v1)
|
|||
#define ABSDIFF(v1,v2) ((v1 > v2) ? (v1 - v2) : (v2 - v1))
|
|||
#define IPOS(w,v,h) (( v * w ) + h )
|
|||
#define NPOS(n1,n2,p) (( ( p / n1 ) * n2 ) + ( p % n1 ))
|
|||
#define ROUND_F(v1) ((v1 < 0) ? (int) (v1 - 0.5) : (int) (v1 + 0.5))
|
|||
#define DIV_INT(v1,v2) ((v1 < 0) ? (v1 - (v2 >> 1)) / v2 : (v1 + (v2 >> 1)) / v2)
|
|||
#define B_SHORT(v1,v2) (( ((int) v1) << 8 ) + ((int) v2))
|
|||
#define BITLEN1024P(v) (pbitlen_0_1024[v])
|
|||
#define BITLEN2048N(v) ((pbitlen_n2048_2047 + 2048)[v])
|
|||
#define CLAMPED(l,h,v) (( v < l ) ? l : ( v > h ) ? h : v)
|
|||
// special realloc with guaranteed free() of previous memory
|
|||
static inline void* frealloc(void* ptr, size_t size)
|
|||
{
|
|||
void* n_ptr = realloc(ptr, (size) ? size : 1);
|
|||
if (n_ptr == nullptr)
|
|||
{
|
|||
free(ptr);
|
|||
}
|
|||
return n_ptr;
|
|||
}
|
|||
// Initialize static members
|
|||
const unsigned char packJPG::appversion = 25;
|
|||
const char* packJPG::subversion = "k";
|
|||
const char* packJPG::apptitle = "packJPG";
|
|||
const char* packJPG::appname = "packjpg";
|
|||
const char* packJPG::versiondate = "01/22/2016";
|
|||
const char* packJPG::author = "Matthias Stirner / Se";
|
|||
const char packJPG::pjg_magic[] = { 'J', 'S' };
|
|||
packJPG::packJPG()
|
|||
: lib_in_type(-1),
|
|||
lib_out_type(-1),
|
|||
grbgdata(nullptr),
|
|||
hdrdata(nullptr),
|
|||
huffdata(nullptr),
|
|||
hufs(0),
|
|||
hdrs(0),
|
|||
grbs(0),
|
|||
rstp(nullptr),
|
|||
scnp(nullptr),
|
|||
rstc(0),
|
|||
scnc(0),
|
|||
rsti(0),
|
|||
padbit(-1),
|
|||
rst_err(nullptr),
|
|||
zdstdata(),
|
|||
eobxhigh(),
|
|||
eobyhigh(),
|
|||
zdstxlow(),
|
|||
zdstylow(),
|
|||
colldata(),
|
|||
freqscan(),
|
|||
zsrtscan(),
|
|||
adpt_idct_8x8(),
|
|||
adpt_idct_1x8(),
|
|||
adpt_idct_8x1(),
|
|||
cmpnfo(),
|
|||
cmpc(0),
|
|||
imgwidth(0),
|
|||
imgheight(0),
|
|||
sfhm(0),
|
|||
sfvm(0),
|
|||
mcuv(0),
|
|||
mcuh(0),
|
|||
mcuc(0),
|
|||
cs_cmpc(0),
|
|||
cs_cmp(),
|
|||
cs_from(0),
|
|||
cs_to(0),
|
|||
cs_sah(0),
|
|||
cs_sal(0),
|
|||
jpgfilename(nullptr),
|
|||
pjgfilename(nullptr),
|
|||
jpgfilesize(0),
|
|||
pjgfilesize(0),
|
|||
jpegtype(0),
|
|||
filetype(0),
|
|||
//~ str_in, // input stream
|
|||
//~ str_out, // output stream
|
|||
errormessage(),
|
|||
errorfunction(nullptr),
|
|||
errorlevel(0),
|
|||
err_tol(1),
|
|||
disc_meta(false),
|
|||
auto_set(true),
|
|||
action(A_COMPRESS),
|
|||
nois_trs{6, 6, 6, 6},
|
|||
segm_cnt{10, 10, 10, 10}
|
|||
{
|
|||
}
|
|||
packJPG::~packJPG()
|
|||
{
|
|||
}
|
|||
const char* packJPG::pjglib_version_info(void)
|
|||
{
|
|||
static char v_info[256];
|
|||
// copy version info to string
|
|||
sprintf(v_info, "--> %s library v%i.%i%s (%s) by %s <--",
|
|||
apptitle, appversion / 10, appversion % 10, subversion,
|
|||
versiondate, author);
|
|||
return (const char*) v_info;
|
|||
}
|
|||
const char* packJPG::pjglib_short_name(void)
|
|||
{
|
|||
static char v_name[256];
|
|||
// copy version info to string
|
|||
sprintf(v_name, "%s v%i.%i%s",
|
|||
apptitle, appversion / 10, appversion % 10, subversion);
|
|||
return (const char*) v_name;
|
|||
}
|
|||
/* ------------------- Begin of library only functions --------------------- */
|
|||
/* -----------------------------------------------
|
|||
DLL export converter function
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjglib_convert_stream2stream(char* msg)
|
|||
{
|
|||
// process in main function
|
|||
return pjglib_convert_stream2mem(nullptr, nullptr, msg);
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
DLL export converter function
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjglib_convert_file2file(char* in, char* out, char* msg)
|
|||
{
|
|||
// init streams
|
|||
pjglib_init_streams((void*) in, 0, 0, (void*) out, 0);
|
|||
// process in main function
|
|||
return pjglib_convert_stream2mem(nullptr, nullptr, msg);
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
DLL export converter function
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjglib_convert_stream2mem(
|
|||
unsigned char** out_file,
|
|||
unsigned int* out_size,
|
|||
char* msg)
|
|||
{
|
|||
clock_t begin, end;
|
|||
int total;
|
|||
float cr;
|
|||
// use automatic settings
|
|||
auto_set = true;
|
|||
// (re)set buffers
|
|||
reset_buffers();
|
|||
action = A_COMPRESS;
|
|||
// main compression / decompression routines
|
|||
begin = clock();
|
|||
// process one file
|
|||
process_file();
|
|||
// fetch pointer and size of output (only for memory output)
|
|||
if ((errorlevel < err_tol) && (lib_out_type == 1) &&
|
|||
(out_file != nullptr) && (out_size != nullptr))
|
|||
{
|
|||
*out_size = str_out->num_bytes_written();
|
|||
*out_file = str_out->get_c_data();
|
|||
}
|
|||
// close iostreams
|
|||
str_in.reset(nullptr);
|
|||
str_out.reset(nullptr);
|
|||
end = clock();
|
|||
// copy errormessage / remove files if error (and output is file)
|
|||
if (errorlevel >= err_tol)
|
|||
{
|
|||
if (lib_out_type == 0)
|
|||
{
|
|||
if (filetype == F_JPG)
|
|||
{
|
|||
if (file_exists(pjgfilename))
|
|||
{
|
|||
remove(pjgfilename);
|
|||
}
|
|||
}
|
|||
else if (filetype == F_PJG)
|
|||
{
|
|||
if (file_exists(jpgfilename))
|
|||
{
|
|||
remove(jpgfilename);
|
|||
}
|
|||
}
|
|||
}
|
|||
if (msg != nullptr)
|
|||
{
|
|||
strcpy(msg, errormessage);
|
|||
}
|
|||
return false;
|
|||
}
|
|||
// get compression info
|
|||
total = (int)((double)((end - begin) * 1000) / CLOCKS_PER_SEC);
|
|||
cr = (jpgfilesize > 0) ? (100.0 * pjgfilesize / jpgfilesize) : 0;
|
|||
// write success message else
|
|||
if (msg != nullptr)
|
|||
{
|
|||
switch (filetype)
|
|||
{
|
|||
case F_JPG:
|
|||
sprintf(msg, "Compressed to %s (%.2f%%) in %ims",
|
|||
pjgfilename, cr, (total >= 0) ? total : -1);
|
|||
break;
|
|||
case F_PJG:
|
|||
sprintf(msg, "Decompressed to %s (%.2f%%) in %ims",
|
|||
jpgfilename, cr, (total >= 0) ? total : -1);
|
|||
break;
|
|||
case F_UNK:
|
|||
sprintf(msg, "Unknown filetype");
|
|||
break;
|
|||
}
|
|||
}
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
DLL export init input (file/mem)
|
|||
----------------------------------------------- */
|
|||
void packJPG::pjglib_init_streams(
|
|||
void* in_src,
|
|||
int in_type,
|
|||
int in_size,
|
|||
void* out_dest,
|
|||
int out_type)
|
|||
{
|
|||
/* a short reminder about input/output stream types:
|
|||
if input is file
|
|||
----------------
|
|||
in_scr -> name of input file
|
|||
in_type -> 0
|
|||
in_size -> ignore
|
|||
if input is memory
|
|||
------------------
|
|||
in_scr -> array containg data
|
|||
in_type -> 1
|
|||
in_size -> size of data array
|
|||
if input is *FILE (f.e. stdin)
|
|||
------------------------------
|
|||
in_src -> stream pointer
|
|||
in_type -> 2
|
|||
in_size -> ignore
|
|||
vice versa for output streams! */
|
|||
unsigned char buffer[2];
|
|||
// (re)set errorlevel
|
|||
errorfunction = nullptr;
|
|||
errorlevel = 0;
|
|||
jpgfilesize = 0;
|
|||
pjgfilesize = 0;
|
|||
switch (in_type)
|
|||
{
|
|||
case 0:
|
|||
try
|
|||
{
|
|||
str_in = std::make_unique<FileReader>((char*)in_src);
|
|||
}
|
|||
catch (const std::runtime_error&)
|
|||
{
|
|||
sprintf(errormessage, "error opening input file %s", (char*)in_src);
|
|||
errorlevel = 2;
|
|||
return;
|
|||
}
|
|||
break;
|
|||
case 1:
|
|||
str_in = std::make_unique<MemoryReader>((unsigned char*)in_src, in_size);
|
|||
break;
|
|||
case 2:
|
|||
try
|
|||
{
|
|||
str_in = std::make_unique<StreamReader>();
|
|||
}
|
|||
catch (const std::runtime_error& e)
|
|||
{
|
|||
sprintf(errormessage, e.what());
|
|||
errorlevel = 2;
|
|||
return;
|
|||
}
|
|||
break;
|
|||
default:
|
|||
sprintf(errormessage, "Invalid input type: %i", in_type);
|
|||
errorlevel = 2;
|
|||
return;
|
|||
}
|
|||
switch (out_type)
|
|||
{
|
|||
case 0:
|
|||
try
|
|||
{
|
|||
str_out = std::make_unique<FileWriter>((char*)out_dest);
|
|||
}
|
|||
catch (const std::runtime_error&)
|
|||
{
|
|||
sprintf(errormessage, "error opening output file %s", (char*)out_dest);
|
|||
errorlevel = 2;
|
|||
return;
|
|||
}
|
|||
break;
|
|||
case 1:
|
|||
str_out = std::make_unique<MemoryWriter>();
|
|||
break;
|
|||
case 2:
|
|||
try
|
|||
{
|
|||
str_out = std::make_unique<StreamWriter>();
|
|||
}
|
|||
catch (const std::runtime_error& e)
|
|||
{
|
|||
sprintf(errormessage, e.what());
|
|||
errorlevel = 2;
|
|||
return;
|
|||
}
|
|||
break;
|
|||
default:
|
|||
sprintf(errormessage, "Invalid output type: %i", out_type);
|
|||
errorlevel = 2;
|
|||
return;
|
|||
}
|
|||
// free memory from filenames if needed
|
|||
if (jpgfilename != nullptr)
|
|||
{
|
|||
free(jpgfilename);
|
|||
jpgfilename = nullptr;
|
|||
}
|
|||
if (pjgfilename != nullptr)
|
|||
{
|
|||
free(pjgfilename);
|
|||
pjgfilename = nullptr;
|
|||
}
|
|||
// check input stream
|
|||
str_in->read(buffer, 2);
|
|||
if ((buffer[0] == 0xFF) && (buffer[1] == 0xD8))
|
|||
{
|
|||
// file is JPEG
|
|||
filetype = F_JPG;
|
|||
// copy filenames
|
|||
jpgfilename = (char*) calloc((in_type == 0) ? strlen((char*) in_src) + 1 : 32, sizeof(char));
|
|||
pjgfilename = (char*) calloc((out_type == 0) ? strlen((char*) out_dest) + 1 : 32, sizeof(char));
|
|||
strcpy(jpgfilename, (in_type == 0) ? (char*) in_src : "JPG in memory");
|
|||
strcpy(pjgfilename, (out_type == 0) ? (char*) out_dest : "PJG in memory");
|
|||
}
|
|||
else if ((buffer[0] == pjg_magic[0]) && (buffer[1] == pjg_magic[1]))
|
|||
{
|
|||
// file is PJG
|
|||
filetype = F_PJG;
|
|||
// copy filenames
|
|||
pjgfilename = (char*) calloc((in_type == 0) ? strlen((char*) in_src) + 1 : 32, sizeof(char));
|
|||
jpgfilename = (char*) calloc((out_type == 0) ? strlen((char*) out_dest) + 1 : 32, sizeof(char));
|
|||
strcpy(pjgfilename, (in_type == 0) ? (char*) in_src : "PJG in memory");
|
|||
strcpy(jpgfilename, (out_type == 0) ? (char*) out_dest : "JPG in memory");
|
|||
}
|
|||
else
|
|||
{
|
|||
// file is neither
|
|||
filetype = F_UNK;
|
|||
sprintf(errormessage, "filetype of input stream is unknown");
|
|||
errorlevel = 2;
|
|||
return;
|
|||
}
|
|||
// store types of in-/output
|
|||
lib_in_type = in_type;
|
|||
lib_out_type = out_type;
|
|||
}
|
|||
/* -------------------- End of libary only functions ----------------------- */
|
|||
/* ----------------- Begin of main interface functions --------------------- */
|
|||
/* -----------------------------------------------
|
|||
processes one file
|
|||
----------------------------------------------- */
|
|||
void packJPG::process_file(void)
|
|||
{
|
|||
if (filetype == F_JPG)
|
|||
{
|
|||
switch (action)
|
|||
{
|
|||
case A_COMPRESS:
|
|||
read_jpeg();
|
|||
decode_jpeg();
|
|||
check_value_range();
|
|||
adapt_icos();
|
|||
predict_dc();
|
|||
calc_zdst_lists();
|
|||
pack_pjg();
|
|||
break;
|
|||
default:
|
|||
break;
|
|||
}
|
|||
}
|
|||
else if (filetype == F_PJG)
|
|||
{
|
|||
switch (action)
|
|||
{
|
|||
case A_COMPRESS:
|
|||
unpack_pjg();
|
|||
adapt_icos();
|
|||
unpredict_dc();
|
|||
recode_jpeg();
|
|||
merge_jpeg();
|
|||
break;
|
|||
default:
|
|||
break;
|
|||
}
|
|||
}
|
|||
// reset buffers
|
|||
reset_buffers();
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
main-function execution routine
|
|||
----------------------------------------------- */
|
|||
void packJPG::execute(bool (*function)())
|
|||
{
|
|||
if (errorlevel < err_tol)
|
|||
{
|
|||
// call function
|
|||
(*function)();
|
|||
// store errorfunction if needed
|
|||
if ((errorlevel > 0) && (errorfunction == nullptr))
|
|||
{
|
|||
errorfunction = function;
|
|||
}
|
|||
}
|
|||
}
|
|||
/* ----------------------- End of main interface functions ----------------- */
|
|||
/* ----------------------- Begin of main functions ------------------------- */
|
|||
/* -----------------------------------------------
|
|||
set each variable to its initial value
|
|||
----------------------------------------------- */
|
|||
bool packJPG::reset_buffers(void)
|
|||
{
|
|||
int cmp, bpos;
|
|||
int i;
|
|||
// -- free buffers --
|
|||
// free buffers & set pointers nullptr
|
|||
if (hdrdata != nullptr)
|
|||
{
|
|||
free(hdrdata);
|
|||
}
|
|||
if (huffdata != nullptr)
|
|||
{
|
|||
free(huffdata);
|
|||
}
|
|||
if (grbgdata != nullptr)
|
|||
{
|
|||
free(grbgdata);
|
|||
}
|
|||
if (rst_err != nullptr)
|
|||
{
|
|||
free(rst_err);
|
|||
}
|
|||
if (rstp != nullptr)
|
|||
{
|
|||
free(rstp);
|
|||
}
|
|||
if (scnp != nullptr)
|
|||
{
|
|||
free(scnp);
|
|||
}
|
|||
hdrdata = nullptr;
|
|||
huffdata = nullptr;
|
|||
grbgdata = nullptr;
|
|||
rst_err = nullptr;
|
|||
rstp = nullptr;
|
|||
scnp = nullptr;
|
|||
// free image arrays
|
|||
for (cmp = 0; cmp < 4; cmp++)
|
|||
{
|
|||
if (zdstdata[cmp] != nullptr)
|
|||
{
|
|||
free(zdstdata[cmp]);
|
|||
}
|
|||
if (eobxhigh[cmp] != nullptr)
|
|||
{
|
|||
free(eobxhigh[cmp]);
|
|||
}
|
|||
if (eobyhigh[cmp] != nullptr)
|
|||
{
|
|||
free(eobyhigh[cmp]);
|
|||
}
|
|||
if (zdstxlow[cmp] != nullptr)
|
|||
{
|
|||
free(zdstxlow[cmp]);
|
|||
}
|
|||
if (zdstylow[cmp] != nullptr)
|
|||
{
|
|||
free(zdstylow[cmp]);
|
|||
}
|
|||
zdstdata[cmp] = nullptr;
|
|||
eobxhigh[cmp] = nullptr;
|
|||
eobyhigh[cmp] = nullptr;
|
|||
zdstxlow[cmp] = nullptr;
|
|||
zdstylow[cmp] = nullptr;
|
|||
freqscan[cmp] = (unsigned char*) stdscan;
|
|||
for (bpos = 0; bpos < 64; bpos++)
|
|||
{
|
|||
if (colldata[cmp][bpos] != nullptr)
|
|||
{
|
|||
free(colldata[cmp][bpos]);
|
|||
}
|
|||
colldata[cmp][bpos] = nullptr;
|
|||
}
|
|||
}
|
|||
// -- set variables --
|
|||
// preset componentinfo
|
|||
for (cmp = 0; cmp < 4; cmp++)
|
|||
{
|
|||
cmpnfo[cmp].sfv = -1;
|
|||
cmpnfo[cmp].sfh = -1;
|
|||
cmpnfo[cmp].mbs = -1;
|
|||
cmpnfo[cmp].bcv = -1;
|
|||
cmpnfo[cmp].bch = -1;
|
|||
cmpnfo[cmp].bc = -1;
|
|||
cmpnfo[cmp].ncv = -1;
|
|||
cmpnfo[cmp].nch = -1;
|
|||
cmpnfo[cmp].nc = -1;
|
|||
cmpnfo[cmp].sid = -1;
|
|||
cmpnfo[cmp].jid = -1;
|
|||
cmpnfo[cmp].qtable = nullptr;
|
|||
cmpnfo[cmp].huffdc = -1;
|
|||
cmpnfo[cmp].huffac = -1;
|
|||
}
|
|||
// preset imgwidth / imgheight / component count
|
|||
imgwidth = 0;
|
|||
imgheight = 0;
|
|||
cmpc = 0;
|
|||
// preset mcu info variables / restart interval
|
|||
sfhm = 0;
|
|||
sfvm = 0;
|
|||
mcuc = 0;
|
|||
mcuh = 0;
|
|||
mcuv = 0;
|
|||
rsti = 0;
|
|||
// reset quantization / huffman tables
|
|||
for (i = 0; i < 4; i++)
|
|||
{
|
|||
htset[0][i] = 0;
|
|||
htset[1][i] = 0;
|
|||
for (bpos = 0; bpos < 64; bpos++)
|
|||
{
|
|||
qtables[i][bpos] = 0;
|
|||
}
|
|||
}
|
|||
// preset jpegtype
|
|||
jpegtype = 0;
|
|||
// reset padbit
|
|||
padbit = -1;
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
Read in header & image data
|
|||
----------------------------------------------- */
|
|||
bool packJPG::read_jpeg(void)
|
|||
{
|
|||
unsigned char* segment = nullptr; // storage for current segment
|
|||
unsigned int ssize = 1024; // current size of segment array
|
|||
unsigned char type = 0x00; // type of current marker segment
|
|||
unsigned int len = 0; // length of current marker segment
|
|||
unsigned int crst = 0; // current rst marker counter
|
|||
unsigned int cpos = 0; // rst marker counter
|
|||
unsigned char tmp;
|
|||
MemoryWriter* huffw;
|
|||
MemoryWriter* hdrw;
|
|||
MemoryWriter* grbgw;
|
|||
// preset count of scans
|
|||
scnc = 0;
|
|||
// start headerwriter
|
|||
hdrw = new MemoryWriter();
|
|||
hdrs = 0; // size of header data, start with 0
|
|||
// start huffman writer
|
|||
huffw = new MemoryWriter();
|
|||
hufs = 0; // size of image data, start with 0
|
|||
// alloc memory for segment data first
|
|||
segment = (unsigned char*) calloc(ssize, sizeof(char));
|
|||
if (segment == nullptr)
|
|||
{
|
|||
sprintf(errormessage, MEM_ERRMSG);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
// JPEG reader loop
|
|||
while (true)
|
|||
{
|
|||
if (type == 0xDA) // if last marker was sos
|
|||
{
|
|||
// switch to huffman data reading mode
|
|||
cpos = 0;
|
|||
crst = 0;
|
|||
while (true)
|
|||
{
|
|||
// read byte from imagedata
|
|||
if (str_in->read_byte(&tmp) == 0)
|
|||
{
|
|||
break;
|
|||
}
|
|||
// non-0xFF loop
|
|||
if (tmp != 0xFF)
|
|||
{
|
|||
crst = 0;
|
|||
while (tmp != 0xFF)
|
|||
{
|
|||
huffw->write_byte(tmp);
|
|||
if (str_in->read_byte(&tmp) == 0)
|
|||
{
|
|||
break;
|
|||
}
|
|||
}
|
|||
}
|
|||
// treatment of 0xFF
|
|||
if (tmp == 0xFF)
|
|||
{
|
|||
if (str_in->read_byte(&tmp) == 0)
|
|||
{
|
|||
break; // read next byte & check
|
|||
}
|
|||
if (tmp == 0x00)
|
|||
{
|
|||
crst = 0;
|
|||
// no zeroes needed -> ignore 0x00. write 0xFF
|
|||
huffw->write_byte(0xFF);
|
|||
}
|
|||
else if (tmp == 0xD0 + (cpos % 8)) // restart marker
|
|||
{
|
|||
// increment rst counters
|
|||
cpos++;
|
|||
crst++;
|
|||
}
|
|||
else // in all other cases leave it to the header parser routines
|
|||
{
|
|||
// store number of wrongly set rst markers
|
|||
if (crst > 0)
|
|||
{
|
|||
if (rst_err == nullptr)
|
|||
{
|
|||
rst_err = (unsigned char*) calloc(scnc + 1, sizeof(char));
|
|||
if (rst_err == nullptr)
|
|||
{
|
|||
sprintf(errormessage, MEM_ERRMSG);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
}
|
|||
}
|
|||
if (rst_err != nullptr)
|
|||
{
|
|||
// realloc and set only if needed
|
|||
rst_err = (unsigned char*) frealloc(rst_err, (scnc + 1) * sizeof(char));
|
|||
if (rst_err == nullptr)
|
|||
{
|
|||
sprintf(errormessage, MEM_ERRMSG);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
if (crst > 255)
|
|||
{
|
|||
sprintf(errormessage, "Severe false use of RST markers (%i)", (int) crst);
|
|||
errorlevel = 1;
|
|||
crst = 255;
|
|||
}
|
|||
rst_err[scnc] = crst;
|
|||
}
|
|||
// end of current scan
|
|||
scnc++;
|
|||
// on with the header parser routines
|
|||
segment[0] = 0xFF;
|
|||
segment[1] = tmp;
|
|||
break;
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
// otherwise this means end-of-file, so break out
|
|||
break;
|
|||
}
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
// read in next marker
|
|||
if (str_in->read(segment, 2) != 2)
|
|||
{
|
|||
break;
|
|||
}
|
|||
if (segment[0] != 0xFF)
|
|||
{
|
|||
// ugly fix for incorrect marker segment sizes
|
|||
sprintf(errormessage, "size mismatch in marker segment FF %2X", type);
|
|||
errorlevel = 2;
|
|||
if (type == 0xFE) // if last marker was COM try again
|
|||
{
|
|||
if (str_in->read(segment, 2) != 2)
|
|||
{
|
|||
break;
|
|||
}
|
|||
if (segment[0] == 0xFF)
|
|||
{
|
|||
errorlevel = 1;
|
|||
}
|
|||
}
|
|||
if (errorlevel == 2)
|
|||
{
|
|||
delete (hdrw);
|
|||
delete (huffw);
|
|||
free(segment);
|
|||
return false;
|
|||
}
|
|||
}
|
|||
}
|
|||
// read segment type
|
|||
type = segment[1];
|
|||
// if EOI is encountered make a quick exit
|
|||
if (type == 0xD9)
|
|||
{
|
|||
// get pointer for header data & size
|
|||
hdrdata = hdrw->get_c_data();
|
|||
hdrs = hdrw->num_bytes_written();
|
|||
// get pointer for huffman data & size
|
|||
huffdata = huffw->get_c_data();
|
|||
hufs = huffw->num_bytes_written();
|
|||
// everything is done here now
|
|||
break;
|
|||
}
|
|||
// read in next segments' length and check it
|
|||
if (str_in->read(segment + 2, 2) != 2)
|
|||
{
|
|||
break;
|
|||
}
|
|||
len = 2 + B_SHORT(segment[2], segment[3]);
|
|||
if (len < 4)
|
|||
{
|
|||
break;
|
|||
}
|
|||
// realloc segment data if needed
|
|||
if (ssize < len)
|
|||
{
|
|||
segment = (unsigned char*) frealloc(segment, len);
|
|||
if (segment == nullptr)
|
|||
{
|
|||
sprintf(errormessage, MEM_ERRMSG);
|
|||
errorlevel = 2;
|
|||
delete (hdrw);
|
|||
delete (huffw);
|
|||
return false;
|
|||
}
|
|||
ssize = len;
|
|||
}
|
|||
// read rest of segment, store back in header writer
|
|||
if (str_in->read((segment + 4), (len - 4)) !=
|
|||
(unsigned short)(len - 4))
|
|||
{
|
|||
break;
|
|||
}
|
|||
hdrw->write(segment, len);
|
|||
}
|
|||
// JPEG reader loop end
|
|||
// free writers
|
|||
delete hdrw;
|
|||
delete huffw;
|
|||
// check if everything went OK
|
|||
if ((hdrs == 0) || (hufs == 0))
|
|||
{
|
|||
sprintf(errormessage, "unexpected end of data encountered");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
// store garbage after EOI if needed
|
|||
grbs = str_in->read_byte(&tmp);
|
|||
if (grbs > 0)
|
|||
{
|
|||
grbgw = new MemoryWriter();
|
|||
grbgw->write_byte(tmp);
|
|||
while (true)
|
|||
{
|
|||
len = str_in->read(segment, ssize);
|
|||
if (len == 0)
|
|||
{
|
|||
break;
|
|||
}
|
|||
grbgw->write(segment, len);
|
|||
}
|
|||
grbgdata = grbgw->get_c_data();
|
|||
grbs = grbgw->num_bytes_written();
|
|||
delete grbgw;
|
|||
}
|
|||
// free segment
|
|||
free(segment);
|
|||
// get filesize
|
|||
jpgfilesize = str_in->get_size();
|
|||
// parse header for image info
|
|||
if (!jpg_setup_imginfo())
|
|||
{
|
|||
return false;
|
|||
}
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
Merges header & image data to jpeg
|
|||
----------------------------------------------- */
|
|||
bool packJPG::merge_jpeg(void)
|
|||
{
|
|||
unsigned char SOI[2] = {0xFF, 0xD8}; // SOI segment
|
|||
unsigned char EOI[2] = {0xFF, 0xD9}; // EOI segment
|
|||
unsigned char mrk = 0xFF; // marker start
|
|||
unsigned char stv = 0x00; // 0xFF stuff value
|
|||
unsigned char rst = 0xD0; // restart marker
|
|||
unsigned char type = 0x00; // type of current marker segment
|
|||
unsigned int len = 0; // length of current marker segment
|
|||
unsigned int hpos = 0; // current position in header
|
|||
unsigned int ipos = 0; // current position in imagedata
|
|||
unsigned int rpos = 0; // current restart marker position
|
|||
unsigned int cpos = 0; // in scan corrected rst marker position
|
|||
unsigned int scan = 1; // number of current scan
|
|||
unsigned int tmp; // temporary storage variable
|
|||
// write SOI
|
|||
str_out->write(SOI, 2);
|
|||
// JPEG writing loop
|
|||
while (true)
|
|||
{
|
|||
// store current header position
|
|||
tmp = hpos;
|
|||
// seek till start-of-scan
|
|||
for (type = 0x00; type != 0xDA;)
|
|||
{
|
|||
if ((int) hpos >= hdrs)
|
|||
{
|
|||
break;
|
|||
}
|
|||
type = hdrdata[hpos + 1];
|
|||
len = 2 + B_SHORT(hdrdata[hpos + 2], hdrdata[hpos + 3]);
|
|||
hpos += len;
|
|||
}
|
|||
// write header data to file
|
|||
str_out->write(hdrdata + tmp, (hpos - tmp));
|
|||
// get out if last marker segment type was not SOS
|
|||
if (type != 0xDA)
|
|||
{
|
|||
break;
|
|||
}
|
|||
// (re)set corrected rst pos
|
|||
cpos = 0;
|
|||
// write & expand huffman coded image data
|
|||
for (ipos = scnp[scan - 1]; ipos < scnp[scan]; ipos++)
|
|||
{
|
|||
// write current byte
|
|||
str_out->write_byte(huffdata[ipos]);
|
|||
// check current byte, stuff if needed
|
|||
if (huffdata[ipos] == 0xFF)
|
|||
{
|
|||
str_out->write_byte(stv);
|
|||
}
|
|||
// insert restart markers if needed
|
|||
if (rstp != nullptr)
|
|||
{
|
|||
if (ipos == rstp[rpos])
|
|||
{
|
|||
rst = 0xD0 + (cpos % 8);
|
|||
str_out->write_byte(mrk);
|
|||
str_out->write_byte(rst);
|
|||
rpos++;
|
|||
cpos++;
|
|||
}
|
|||
}
|
|||
}
|
|||
// insert false rst markers at end if needed
|
|||
if (rst_err != nullptr)
|
|||
{
|
|||
while (rst_err[scan - 1] > 0)
|
|||
{
|
|||
rst = 0xD0 + (cpos % 8);
|
|||
str_out->write_byte(mrk);
|
|||
str_out->write_byte(rst);
|
|||
cpos++;
|
|||
rst_err[scan - 1]--;
|
|||
}
|
|||
}
|
|||
// proceed with next scan
|
|||
scan++;
|
|||
}
|
|||
// write EOI
|
|||
str_out->write(EOI, 2);
|
|||
// write garbage if needed
|
|||
if (grbs > 0)
|
|||
{
|
|||
str_out->write(grbgdata, grbs);
|
|||
}
|
|||
// errormessage if write error
|
|||
if (str_out->error())
|
|||
{
|
|||
sprintf(errormessage, "write error, possibly drive is full");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
// get filesize
|
|||
jpgfilesize = str_out->num_bytes_written();
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
JPEG decoding routine
|
|||
----------------------------------------------- */
|
|||
bool packJPG::decode_jpeg(void)
|
|||
{
|
|||
BitReader* huffr; // bitwise reader for image data
|
|||
unsigned char type = 0x00; // type of current marker segment
|
|||
unsigned int len = 0; // length of current marker segment
|
|||
unsigned int hpos = 0; // current position in header
|
|||
int lastdc[4]; // last dc for each component
|
|||
short block[64]; // store block for coeffs
|
|||
int peobrun; // previous eobrun
|
|||
int eobrun; // run of eobs
|
|||
int rstw; // restart wait counter
|
|||
int cmp, bpos, dpos;
|
|||
int mcu, sub, csc;
|
|||
int eob, sta;
|
|||
// open huffman coded image data for input in BitReader
|
|||
huffr = new BitReader(huffdata, hufs);
|
|||
// preset count of scans
|
|||
scnc = 0;
|
|||
// JPEG decompression loop
|
|||
while (true)
|
|||
{
|
|||
// seek till start-of-scan, parse only DHT, DRI and SOS
|
|||
for (type = 0x00; type != 0xDA;)
|
|||
{
|
|||
if ((int) hpos >= hdrs)
|
|||
{
|
|||
break;
|
|||
}
|
|||
type = hdrdata[hpos + 1];
|
|||
len = 2 + B_SHORT(hdrdata[hpos + 2], hdrdata[hpos + 3]);
|
|||
if ((type == 0xC4) || (type == 0xDA) || (type == 0xDD))
|
|||
{
|
|||
if (!jpg_parse_jfif(type, len, &(hdrdata[hpos])))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
}
|
|||
hpos += len;
|
|||
}
|
|||
// get out if last marker segment type was not SOS
|
|||
if (type != 0xDA)
|
|||
{
|
|||
break;
|
|||
}
|
|||
// check if huffman tables are available
|
|||
for (csc = 0; csc < cs_cmpc; csc++)
|
|||
{
|
|||
cmp = cs_cmp[csc];
|
|||
if (((cs_sal == 0) && (htset[0][cmpnfo[cmp].huffdc] == 0)) ||
|
|||
((cs_sah > 0) && (htset[1][cmpnfo[cmp].huffac] == 0)))
|
|||
{
|
|||
sprintf(errormessage, "huffman table missing in scan%i", scnc);
|
|||
delete huffr;
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
}
|
|||
// intial variables set for decoding
|
|||
cmp = cs_cmp[0];
|
|||
csc = 0;
|
|||
mcu = 0;
|
|||
sub = 0;
|
|||
dpos = 0;
|
|||
// JPEG imagedata decoding routines
|
|||
while (true)
|
|||
{
|
|||
// (re)set last DCs for diff coding
|
|||
lastdc[0] = 0;
|
|||
lastdc[1] = 0;
|
|||
lastdc[2] = 0;
|
|||
lastdc[3] = 0;
|
|||
// (re)set status
|
|||
eob = 0;
|
|||
sta = 0;
|
|||
// (re)set eobrun
|
|||
eobrun = 0;
|
|||
peobrun = 0;
|
|||
// (re)set rst wait counter
|
|||
rstw = rsti;
|
|||
// decoding for interleaved data
|
|||
if (cs_cmpc > 1)
|
|||
{
|
|||
if (jpegtype == 1)
|
|||
{
|
|||
// ---> sequential interleaved decoding <---
|
|||
while (sta == 0)
|
|||
{
|
|||
// decode block
|
|||
eob = jpg_decode_block_seq(huffr,
|
|||
&(htrees[0][cmpnfo[cmp].huffdc]),
|
|||
&(htrees[1][cmpnfo[cmp].huffdc]),
|
|||
block);
|
|||
// check for non optimal coding
|
|||
if ((eob > 1) && (block[eob - 1] == 0))
|
|||
{
|
|||
sprintf(errormessage, "reconstruction of inefficient coding not supported");
|
|||
errorlevel = 1;
|
|||
}
|
|||
// fix dc
|
|||
block[0] += lastdc[cmp];
|
|||
lastdc[cmp] = block[0];
|
|||
// copy to colldata
|
|||
for (bpos = 0; bpos < eob; bpos++)
|
|||
{
|
|||
colldata[cmp][bpos][dpos] = block[bpos];
|
|||
}
|
|||
// check for errors, proceed if no error encountered
|
|||
if (eob < 0)
|
|||
{
|
|||
sta = -1;
|
|||
}
|
|||
else
|
|||
{
|
|||
sta = jpg_next_mcupos(&mcu, &cmp, &csc, &sub, &dpos, &rstw);
|
|||
}
|
|||
}
|
|||
}
|
|||
else if (cs_sah == 0)
|
|||
{
|
|||
// ---> progressive interleaved DC decoding <---
|
|||
// ---> succesive approximation first stage <---
|
|||
while (sta == 0)
|
|||
{
|
|||
sta = jpg_decode_dc_prg_fs(huffr,
|
|||
&(htrees[0][cmpnfo[cmp].huffdc]),
|
|||
block);
|
|||
// fix dc for diff coding
|
|||
colldata[cmp][0][dpos] = block[0] + lastdc[cmp];
|
|||
lastdc[cmp] = colldata[cmp][0][dpos];
|
|||
// bitshift for succesive approximation
|
|||
colldata[cmp][0][dpos] <<= cs_sal;
|
|||
// next mcupos if no error happened
|
|||
if (sta != -1)
|
|||
{
|
|||
sta = jpg_next_mcupos(&mcu, &cmp, &csc, &sub, &dpos, &rstw);
|
|||
}
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
// ---> progressive interleaved DC decoding <---
|
|||
// ---> succesive approximation later stage <---
|
|||
while (sta == 0)
|
|||
{
|
|||
// decode next bit
|
|||
sta = jpg_decode_dc_prg_sa(huffr, block);
|
|||
// shift in next bit
|
|||
colldata[cmp][0][dpos] += block[0] << cs_sal;
|
|||
// next mcupos if no error happened
|
|||
if (sta != -1)
|
|||
{
|
|||
sta = jpg_next_mcupos(&mcu, &cmp, &csc, &sub, &dpos, &rstw);
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
else // decoding for non interleaved data
|
|||
{
|
|||
if (jpegtype == 1)
|
|||
{
|
|||
// ---> sequential non interleaved decoding <---
|
|||
while (sta == 0)
|
|||
{
|
|||
// decode block
|
|||
eob = jpg_decode_block_seq(huffr,
|
|||
&(htrees[0][cmpnfo[cmp].huffdc]),
|
|||
&(htrees[1][cmpnfo[cmp].huffdc]),
|
|||
block);
|
|||
// check for non optimal coding
|
|||
if ((eob > 1) && (block[eob - 1] == 0))
|
|||
{
|
|||
sprintf(errormessage, "reconstruction of inefficient coding not supported");
|
|||
errorlevel = 1;
|
|||
}
|
|||
// fix dc
|
|||
block[0] += lastdc[cmp];
|
|||
lastdc[cmp] = block[0];
|
|||
// copy to colldata
|
|||
for (bpos = 0; bpos < eob; bpos++)
|
|||
{
|
|||
colldata[cmp][bpos][dpos] = block[bpos];
|
|||
}
|
|||
// check for errors, proceed if no error encountered
|
|||
if (eob < 0)
|
|||
{
|
|||
sta = -1;
|
|||
}
|
|||
else
|
|||
{
|
|||
sta = jpg_next_mcuposn(&cmp, &dpos, &rstw);
|
|||
}
|
|||
}
|
|||
}
|
|||
else if (cs_to == 0)
|
|||
{
|
|||
if (cs_sah == 0)
|
|||
{
|
|||
// ---> progressive non interleaved DC decoding <---
|
|||
// ---> succesive approximation first stage <---
|
|||
while (sta == 0)
|
|||
{
|
|||
sta = jpg_decode_dc_prg_fs(huffr,
|
|||
&(htrees[0][cmpnfo[cmp].huffdc]),
|
|||
block);
|
|||
// fix dc for diff coding
|
|||
colldata[cmp][0][dpos] = block[0] + lastdc[cmp];
|
|||
lastdc[cmp] = colldata[cmp][0][dpos];
|
|||
// bitshift for succesive approximation
|
|||
colldata[cmp][0][dpos] <<= cs_sal;
|
|||
// check for errors, increment dpos otherwise
|
|||
if (sta != -1)
|
|||
{
|
|||
sta = jpg_next_mcuposn(&cmp, &dpos, &rstw);
|
|||
}
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
// ---> progressive non interleaved DC decoding <---
|
|||
// ---> succesive approximation later stage <---
|
|||
while (sta == 0)
|
|||
{
|
|||
// decode next bit
|
|||
sta = jpg_decode_dc_prg_sa(huffr, block);
|
|||
// shift in next bit
|
|||
colldata[cmp][0][dpos] += block[0] << cs_sal;
|
|||
// check for errors, increment dpos otherwise
|
|||
if (sta != -1)
|
|||
{
|
|||
sta = jpg_next_mcuposn(&cmp, &dpos, &rstw);
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
if (cs_sah == 0)
|
|||
{
|
|||
// ---> progressive non interleaved AC decoding <---
|
|||
// ---> succesive approximation first stage <---
|
|||
while (sta == 0)
|
|||
{
|
|||
if (eobrun == 0)
|
|||
{
|
|||
// decode block
|
|||
eob = jpg_decode_ac_prg_fs(huffr,
|
|||
&(htrees[1][cmpnfo[cmp].huffac]),
|
|||
block, &eobrun, cs_from, cs_to);
|
|||
if (eobrun > 0)
|
|||
{
|
|||
// check for non optimal coding
|
|||
if ((eob == cs_from) && (peobrun > 0) &&
|
|||
(peobrun < hcodes[1][cmpnfo[cmp].huffac].max_eobrun - 1))
|
|||
{
|
|||
sprintf(errormessage,
|
|||
"reconstruction of inefficient coding not supported");
|
|||
errorlevel = 1;
|
|||
}
|
|||
peobrun = eobrun;
|
|||
eobrun--;
|
|||
}
|
|||
else
|
|||
{
|
|||
peobrun = 0;
|
|||
}
|
|||
// copy to colldata
|
|||
for (bpos = cs_from; bpos < eob; bpos++)
|
|||
{
|
|||
colldata[cmp][bpos][dpos] = block[bpos] << cs_sal;
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
eobrun--;
|
|||
}
|
|||
// check for errors
|
|||
if (eob < 0)
|
|||
{
|
|||
sta = -1;
|
|||
}
|
|||
else
|
|||
{
|
|||
sta = jpg_skip_eobrun(&cmp, &dpos, &rstw, &eobrun);
|
|||
}
|
|||
// proceed only if no error encountered
|
|||
if (sta == 0)
|
|||
{
|
|||
sta = jpg_next_mcuposn(&cmp, &dpos, &rstw);
|
|||
}
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
// ---> progressive non interleaved AC decoding <---
|
|||
// ---> succesive approximation later stage <---
|
|||
while (sta == 0)
|
|||
{
|
|||
// copy from colldata
|
|||
for (bpos = cs_from; bpos <= cs_to; bpos++)
|
|||
{
|
|||
block[bpos] = colldata[cmp][bpos][dpos];
|
|||
}
|
|||
if (eobrun == 0)
|
|||
{
|
|||
// decode block (long routine)
|
|||
eob = jpg_decode_ac_prg_sa(huffr,
|
|||
&(htrees[1][cmpnfo[cmp].huffac]),
|
|||
block, &eobrun, cs_from, cs_to);
|
|||
if (eobrun > 0)
|
|||
{
|
|||
// check for non optimal coding
|
|||
if ((eob == cs_from) && (peobrun > 0) &&
|
|||
(peobrun < hcodes[1][cmpnfo[cmp].huffac].max_eobrun - 1))
|
|||
{
|
|||
sprintf(errormessage,
|
|||
"reconstruction of inefficient coding not supported");
|
|||
errorlevel = 1;
|
|||
}
|
|||
// store eobrun
|
|||
peobrun = eobrun;
|
|||
eobrun--;
|
|||
}
|
|||
else
|
|||
{
|
|||
peobrun = 0;
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
// decode block (short routine)
|
|||
eob = jpg_decode_eobrun_sa(huffr,
|
|||
block, &eobrun, cs_from, cs_to);
|
|||
eobrun--;
|
|||
}
|
|||
// copy back to colldata
|
|||
for (bpos = cs_from; bpos <= cs_to; bpos++)
|
|||
{
|
|||
colldata[cmp][bpos][dpos] += block[bpos] << cs_sal;
|
|||
}
|
|||
// proceed only if no error encountered
|
|||
if (eob < 0)
|
|||
{
|
|||
sta = -1;
|
|||
}
|
|||
else
|
|||
{
|
|||
sta = jpg_next_mcuposn(&cmp, &dpos, &rstw);
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
// unpad huffman reader / check padbit
|
|||
if (padbit != -1)
|
|||
{
|
|||
if (padbit != huffr->unpad(padbit))
|
|||
{
|
|||
sprintf(errormessage, "inconsistent use of padbits");
|
|||
padbit = 1;
|
|||
errorlevel = 1;
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
padbit = huffr->unpad(padbit);
|
|||
}
|
|||
// evaluate status
|
|||
if (sta == -1) // status -1 means error
|
|||
{
|
|||
sprintf(errormessage, "decode error in scan%i / mcu%i",
|
|||
scnc, (cs_cmpc > 1) ? mcu : dpos);
|
|||
delete huffr;
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
else if (sta == 2) // status 2/3 means done
|
|||
{
|
|||
scnc++; // increment scan counter
|
|||
break; // leave decoding loop, everything is done here
|
|||
}
|
|||
// else if ( sta == 1 ); // status 1 means restart - so stay in the loop
|
|||
}
|
|||
}
|
|||
// check for missing data
|
|||
if (huffr->peof() > 0)
|
|||
{
|
|||
sprintf(errormessage, "coded image data truncated / too short");
|
|||
errorlevel = 1;
|
|||
}
|
|||
// check for surplus data
|
|||
if (!huffr->eof())
|
|||
{
|
|||
sprintf(errormessage, "surplus data found after coded image data");
|
|||
errorlevel = 1;
|
|||
}
|
|||
// clean up
|
|||
delete huffr;
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
JPEG encoding routine
|
|||
----------------------------------------------- */
|
|||
bool packJPG::recode_jpeg(void)
|
|||
{
|
|||
BitWriter* huffw; // bitwise writer for image data
|
|||
unsigned char type = 0x00; // type of current marker segment
|
|||
unsigned int len = 0; // length of current marker segment
|
|||
unsigned int hpos = 0; // current position in header
|
|||
int lastdc[4]; // last dc for each component0
|
|||
short block[64]; // store block for coeffs
|
|||
int eobrun; // run of eobs
|
|||
int rstw; // restart wait counter
|
|||
int cmp, bpos, dpos;
|
|||
int mcu, sub, csc;
|
|||
int eob, sta;
|
|||
int tmp;
|
|||
// open huffman coded image data in BitWriter
|
|||
huffw = new BitWriter(padbit);
|
|||
// init storage writer
|
|||
std::vector<std::uint8_t> storw; // Storage for correction bits.
|
|||
// preset count of scans and restarts
|
|||
scnc = 0;
|
|||
rstc = 0;
|
|||
// JPEG decompression loop
|
|||
while (true)
|
|||
{
|
|||
// seek till start-of-scan, parse only DHT, DRI and SOS
|
|||
for (type = 0x00; type != 0xDA;)
|
|||
{
|
|||
if ((int) hpos >= hdrs)
|
|||
{
|
|||
break;
|
|||
}
|
|||
type = hdrdata[hpos + 1];
|
|||
len = 2 + B_SHORT(hdrdata[hpos + 2], hdrdata[hpos + 3]);
|
|||
if ((type == 0xC4) || (type == 0xDA) || (type == 0xDD))
|
|||
{
|
|||
if (!jpg_parse_jfif(type, len, &(hdrdata[hpos])))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
hpos += len;
|
|||
}
|
|||
else
|
|||
{
|
|||
hpos += len;
|
|||
continue;
|
|||
}
|
|||
}
|
|||
// get out if last marker segment type was not SOS
|
|||
if (type != 0xDA)
|
|||
{
|
|||
break;
|
|||
}
|
|||
// (re)alloc scan positons array
|
|||
if (scnp == nullptr)
|
|||
{
|
|||
scnp = (unsigned int*) calloc(scnc + 2, sizeof(int));
|
|||
}
|
|||
else
|
|||
{
|
|||
scnp = (unsigned int*) frealloc(scnp, (scnc + 2) * sizeof(int));
|
|||
}
|
|||
if (scnp == nullptr)
|
|||
{
|
|||
sprintf(errormessage, MEM_ERRMSG);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
// (re)alloc restart marker positons array if needed
|
|||
if (rsti > 0)
|
|||
{
|
|||
tmp = rstc + ((cs_cmpc > 1) ?
|
|||
(mcuc / rsti) : (cmpnfo[cs_cmp[0]].bc / rsti));
|
|||
if (rstp == nullptr)
|
|||
{
|
|||
rstp = (unsigned int*) calloc(tmp + 1, sizeof(int));
|
|||
}
|
|||
else
|
|||
{
|
|||
rstp = (unsigned int*) frealloc(rstp, (tmp + 1) * sizeof(int));
|
|||
}
|
|||
if (rstp == nullptr)
|
|||
{
|
|||
sprintf(errormessage, MEM_ERRMSG);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
}
|
|||
// intial variables set for encoding
|
|||
cmp = cs_cmp[0];
|
|||
csc = 0;
|
|||
mcu = 0;
|
|||
sub = 0;
|
|||
dpos = 0;
|
|||
// store scan position
|
|||
scnp[scnc] = huffw->num_bytes_written();
|
|||
// JPEG imagedata encoding routines
|
|||
while (true)
|
|||
{
|
|||
// (re)set last DCs for diff coding
|
|||
lastdc[0] = 0;
|
|||
lastdc[1] = 0;
|
|||
lastdc[2] = 0;
|
|||
lastdc[3] = 0;
|
|||
// (re)set status
|
|||
sta = 0;
|
|||
// (re)set eobrun
|
|||
eobrun = 0;
|
|||
// (re)set rst wait counter
|
|||
rstw = rsti;
|
|||
// encoding for interleaved data
|
|||
if (cs_cmpc > 1)
|
|||
{
|
|||
if (jpegtype == 1)
|
|||
{
|
|||
// ---> sequential interleaved encoding <---
|
|||
while (sta == 0)
|
|||
{
|
|||
// copy from colldata
|
|||
for (bpos = 0; bpos < 64; bpos++)
|
|||
{
|
|||
block[bpos] = colldata[cmp][bpos][dpos];
|
|||
}
|
|||
// diff coding for dc
|
|||
block[0] -= lastdc[cmp];
|
|||
lastdc[cmp] = colldata[cmp][0][dpos];
|
|||
// encode block
|
|||
eob = jpg_encode_block_seq(huffw,
|
|||
&(hcodes[0][cmpnfo[cmp].huffdc]),
|
|||
&(hcodes[1][cmpnfo[cmp].huffac]),
|
|||
block);
|
|||
// check for errors, proceed if no error encountered
|
|||
if (eob < 0)
|
|||
{
|
|||
sta = -1;
|
|||
}
|
|||
else
|
|||
{
|
|||
sta = jpg_next_mcupos(&mcu, &cmp, &csc, &sub, &dpos, &rstw);
|
|||
}
|
|||
}
|
|||
}
|
|||
else if (cs_sah == 0)
|
|||
{
|
|||
// ---> progressive interleaved DC encoding <---
|
|||
// ---> succesive approximation first stage <---
|
|||
while (sta == 0)
|
|||
{
|
|||
// diff coding & bitshifting for dc
|
|||
tmp = colldata[cmp][0][dpos] >> cs_sal;
|
|||
block[0] = tmp - lastdc[cmp];
|
|||
lastdc[cmp] = tmp;
|
|||
// encode dc
|
|||
sta = jpg_encode_dc_prg_fs(huffw,
|
|||
&(hcodes[0][cmpnfo[cmp].huffdc]),
|
|||
block);
|
|||
// next mcupos if no error happened
|
|||
if (sta != -1)
|
|||
{
|
|||
sta = jpg_next_mcupos(&mcu, &cmp, &csc, &sub, &dpos, &rstw);
|
|||
}
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
// ---> progressive interleaved DC encoding <---
|
|||
// ---> succesive approximation later stage <---
|
|||
while (sta == 0)
|
|||
{
|
|||
// fetch bit from current bitplane
|
|||
block[0] = BITN(colldata[cmp][0][dpos], cs_sal);
|
|||
// encode dc correction bit
|
|||
sta = jpg_encode_dc_prg_sa(huffw, block);
|
|||
// next mcupos if no error happened
|
|||
if (sta != -1)
|
|||
{
|
|||
sta = jpg_next_mcupos(&mcu, &cmp, &csc, &sub, &dpos, &rstw);
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
else // encoding for non interleaved data
|
|||
{
|
|||
if (jpegtype == 1)
|
|||
{
|
|||
// ---> sequential non interleaved encoding <---
|
|||
while (sta == 0)
|
|||
{
|
|||
// copy from colldata
|
|||
for (bpos = 0; bpos < 64; bpos++)
|
|||
{
|
|||
block[bpos] = colldata[cmp][bpos][dpos];
|
|||
}
|
|||
// diff coding for dc
|
|||
block[0] -= lastdc[cmp];
|
|||
lastdc[cmp] = colldata[cmp][0][dpos];
|
|||
// encode block
|
|||
eob = jpg_encode_block_seq(huffw,
|
|||
&(hcodes[0][cmpnfo[cmp].huffdc]),
|
|||
&(hcodes[1][cmpnfo[cmp].huffac]),
|
|||
block);
|
|||
// check for errors, proceed if no error encountered
|
|||
if (eob < 0)
|
|||
{
|
|||
sta = -1;
|
|||
}
|
|||
else
|
|||
{
|
|||
sta = jpg_next_mcuposn(&cmp, &dpos, &rstw);
|
|||
}
|
|||
}
|
|||
}
|
|||
else if (cs_to == 0)
|
|||
{
|
|||
if (cs_sah == 0)
|
|||
{
|
|||
// ---> progressive non interleaved DC encoding <---
|
|||
// ---> succesive approximation first stage <---
|
|||
while (sta == 0)
|
|||
{
|
|||
// diff coding & bitshifting for dc
|
|||
tmp = colldata[cmp][0][dpos] >> cs_sal;
|
|||
block[0] = tmp - lastdc[cmp];
|
|||
lastdc[cmp] = tmp;
|
|||
// encode dc
|
|||
sta = jpg_encode_dc_prg_fs(huffw,
|
|||
&(hcodes[0][cmpnfo[cmp].huffdc]),
|
|||
block);
|
|||
// check for errors, increment dpos otherwise
|
|||
if (sta != -1)
|
|||
{
|
|||
sta = jpg_next_mcuposn(&cmp, &dpos, &rstw);
|
|||
}
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
// ---> progressive non interleaved DC encoding <---
|
|||
// ---> succesive approximation later stage <---
|
|||
while (sta == 0)
|
|||
{
|
|||
// fetch bit from current bitplane
|
|||
block[0] = BITN(colldata[cmp][0][dpos], cs_sal);
|
|||
// encode dc correction bit
|
|||
sta = jpg_encode_dc_prg_sa(huffw, block);
|
|||
// next mcupos if no error happened
|
|||
if (sta != -1)
|
|||
{
|
|||
sta = jpg_next_mcuposn(&cmp, &dpos, &rstw);
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
if (cs_sah == 0)
|
|||
{
|
|||
// ---> progressive non interleaved AC encoding <---
|
|||
// ---> succesive approximation first stage <---
|
|||
while (sta == 0)
|
|||
{
|
|||
// copy from colldata
|
|||
for (bpos = cs_from; bpos <= cs_to; bpos++)
|
|||
block[bpos] =
|
|||
FDIV2(colldata[cmp][bpos][dpos], cs_sal);
|
|||
// encode block
|
|||
eob = jpg_encode_ac_prg_fs(huffw,
|
|||
&(hcodes[1][cmpnfo[cmp].huffac]),
|
|||
block, &eobrun, cs_from, cs_to);
|
|||
// check for errors, proceed if no error encountered
|
|||
if (eob < 0)
|
|||
{
|
|||
sta = -1;
|
|||
}
|
|||
else
|
|||
{
|
|||
sta = jpg_next_mcuposn(&cmp, &dpos, &rstw);
|
|||
}
|
|||
}
|
|||
// encode remaining eobrun
|
|||
jpg_encode_eobrun(huffw,
|
|||
&(hcodes[1][cmpnfo[cmp].huffac]),
|
|||
&eobrun);
|
|||
}
|
|||
else
|
|||
{
|
|||
// ---> progressive non interleaved AC encoding <---
|
|||
// ---> succesive approximation later stage <---
|
|||
while (sta == 0)
|
|||
{
|
|||
// copy from colldata
|
|||
for (bpos = cs_from; bpos <= cs_to; bpos++)
|
|||
block[bpos] =
|
|||
FDIV2(colldata[cmp][bpos][dpos], cs_sal);
|
|||
// encode block
|
|||
eob = jpg_encode_ac_prg_sa(huffw, storw,
|
|||
&(hcodes[1][cmpnfo[cmp].huffac]),
|
|||
block, &eobrun, cs_from, cs_to);
|
|||
// check for errors, proceed if no error encountered
|
|||
if (eob < 0)
|
|||
{
|
|||
sta = -1;
|
|||
}
|
|||
else
|
|||
{
|
|||
sta = jpg_next_mcuposn(&cmp, &dpos, &rstw);
|
|||
}
|
|||
}
|
|||
// encode remaining eobrun
|
|||
jpg_encode_eobrun(huffw,
|
|||
&(hcodes[1][cmpnfo[cmp].huffac]),
|
|||
&eobrun);
|
|||
// encode remaining correction bits
|
|||
jpg_encode_crbits(huffw, storw);
|
|||
}
|
|||
}
|
|||
}
|
|||
// pad huffman writer
|
|||
huffw->pad();
|
|||
// evaluate status
|
|||
if (sta == -1) // status -1 means error
|
|||
{
|
|||
sprintf(errormessage, "encode error in scan%i / mcu%i",
|
|||
scnc, (cs_cmpc > 1) ? mcu : dpos);
|
|||
delete huffw;
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
else if (sta == 2) // status 2 means done
|
|||
{
|
|||
scnc++; // increment scan counter
|
|||
break; // leave decoding loop, everything is done here
|
|||
}
|
|||
else if (sta == 1) // status 1 means restart
|
|||
{
|
|||
if (rsti > 0) // store rstp & stay in the loop
|
|||
{
|
|||
rstp[rstc++] = huffw->num_bytes_written() - 1;
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
// get data into huffdata
|
|||
huffdata = huffw->get_c_bytes();
|
|||
hufs = huffw->num_bytes_written();
|
|||
delete huffw;
|
|||
// store last scan & restart positions
|
|||
scnp[scnc] = hufs;
|
|||
if (rstp != nullptr)
|
|||
{
|
|||
rstp[rstc] = hufs;
|
|||
}
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
adapt ICOS tables for quantizer tables
|
|||
----------------------------------------------- */
|
|||
bool packJPG::adapt_icos(void)
|
|||
{
|
|||
unsigned short quant[64]; // local copy of quantization
|
|||
int ipos;
|
|||
int cmp;
|
|||
for (cmp = 0; cmp < cmpc; cmp++)
|
|||
{
|
|||
// make a local copy of the quantization values, check
|
|||
for (ipos = 0; ipos < 64; ipos++)
|
|||
{
|
|||
quant[ipos] = QUANT(cmp, zigzag[ipos]);
|
|||
if (quant[ipos] >= 2048) // if this is true, it can be safely assumed (for 8 bit JPEG), that all coefficients are zero
|
|||
{
|
|||
quant[ipos] = 0;
|
|||
}
|
|||
}
|
|||
// adapt idct 8x8 table
|
|||
for (ipos = 0; ipos < 64 * 64; ipos++)
|
|||
{
|
|||
adpt_idct_8x8[cmp][ipos] = icos_idct_8x8[ipos] * quant[ipos % 64];
|
|||
}
|
|||
// adapt idct 1x8 table
|
|||
for (ipos = 0; ipos < 8 * 8; ipos++)
|
|||
{
|
|||
adpt_idct_1x8[cmp][ipos] = icos_idct_1x8[ipos] * quant[(ipos % 8) * 8];
|
|||
}
|
|||
// adapt idct 8x1 table
|
|||
for (ipos = 0; ipos < 8 * 8; ipos++)
|
|||
{
|
|||
adpt_idct_8x1[cmp][ipos] = icos_idct_1x8[ipos] * quant[ipos % 8];
|
|||
}
|
|||
}
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
filter DC coefficients
|
|||
----------------------------------------------- */
|
|||
bool packJPG::predict_dc(void)
|
|||
{
|
|||
signed short* coef;
|
|||
int absmaxp;
|
|||
int absmaxn;
|
|||
int corr_f;
|
|||
int cmp, dpos;
|
|||
// apply prediction, store prediction error instead of DC
|
|||
for (cmp = 0; cmp < cmpc; cmp++)
|
|||
{
|
|||
absmaxp = MAX_V(cmp, 0);
|
|||
absmaxn = -absmaxp;
|
|||
corr_f = ((2 * absmaxp) + 1);
|
|||
for (dpos = cmpnfo[cmp].bc - 1; dpos > 0; dpos--)
|
|||
{
|
|||
coef = &(colldata[cmp][0][dpos]);
|
|||
#if defined(USE_PLOCOI)
|
|||
(*coef) -= dc_coll_predictor(cmp, dpos); // loco-i predictor
|
|||
#else
|
|||
(*coef) -= dc_1ddct_predictor(cmp, dpos); // 1d dct
|
|||
#endif
|
|||
// fix range
|
|||
if ((*coef) > absmaxp)
|
|||
{
|
|||
(*coef) -= corr_f;
|
|||
}
|
|||
else if ((*coef) < absmaxn)
|
|||
{
|
|||
(*coef) += corr_f;
|
|||
}
|
|||
}
|
|||
}
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
unpredict DC coefficients
|
|||
----------------------------------------------- */
|
|||
bool packJPG::unpredict_dc(void)
|
|||
{
|
|||
signed short* coef;
|
|||
int absmaxp;
|
|||
int absmaxn;
|
|||
int corr_f;
|
|||
int cmp, dpos;
|
|||
// remove prediction, store DC instead of prediction error
|
|||
for (cmp = 0; cmp < cmpc; cmp++)
|
|||
{
|
|||
absmaxp = MAX_V(cmp, 0);
|
|||
absmaxn = -absmaxp;
|
|||
corr_f = ((2 * absmaxp) + 1);
|
|||
for (dpos = 1; dpos < cmpnfo[cmp].bc; dpos++)
|
|||
{
|
|||
coef = &(colldata[cmp][0][dpos]);
|
|||
#if defined( USE_PLOCOI )
|
|||
(*coef) += dc_coll_predictor(cmp, dpos); // loco-i predictor
|
|||
#else
|
|||
(*coef) += dc_1ddct_predictor(cmp, dpos); // 1d dct predictor
|
|||
#endif
|
|||
// fix range
|
|||
if ((*coef) > absmaxp)
|
|||
{
|
|||
(*coef) -= corr_f;
|
|||
}
|
|||
else if ((*coef) < absmaxn)
|
|||
{
|
|||
(*coef) += corr_f;
|
|||
}
|
|||
}
|
|||
}
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
checks range of values, error if out of bounds
|
|||
----------------------------------------------- */
|
|||
bool packJPG::check_value_range(void)
|
|||
{
|
|||
int absmax;
|
|||
int cmp, bpos, dpos;
|
|||
// out of range should never happen with unmodified JPEGs
|
|||
for (cmp = 0; cmp < cmpc; cmp++)
|
|||
for (bpos = 0; bpos < 64; bpos++)
|
|||
{
|
|||
absmax = MAX_V(cmp, bpos);
|
|||
for (dpos = 0; dpos < cmpnfo[cmp].bc; dpos++)
|
|||
if ((colldata[cmp][bpos][dpos] > absmax) ||
|
|||
(colldata[cmp][bpos][dpos] < -absmax))
|
|||
{
|
|||
sprintf(errormessage, "value out of range error: cmp%i, frq%i, val %i, max %i",
|
|||
cmp, bpos, colldata[cmp][bpos][dpos], absmax);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
}
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
calculate zero distribution lists
|
|||
----------------------------------------------- */
|
|||
bool packJPG::calc_zdst_lists(void)
|
|||
{
|
|||
int cmp, bpos, dpos;
|
|||
int b_x, b_y;
|
|||
// this functions counts, for each DCT block, the number of non-zero coefficients
|
|||
for (cmp = 0; cmp < cmpc; cmp++)
|
|||
{
|
|||
// preset zdstlist
|
|||
memset(zdstdata[cmp], 0, cmpnfo[cmp].bc * sizeof(char));
|
|||
// calculate # on non-zeroes per block (separately for lower 7x7 block & first row/collumn)
|
|||
for (bpos = 1; bpos < 64; bpos++)
|
|||
{
|
|||
b_x = unzigzag[bpos] % 8;
|
|||
b_y = unzigzag[bpos] / 8;
|
|||
if (b_x == 0)
|
|||
{
|
|||
for (dpos = 0; dpos < cmpnfo[cmp].bc; dpos++)
|
|||
if (colldata[cmp][bpos][dpos] != 0)
|
|||
{
|
|||
zdstylow[cmp][dpos]++;
|
|||
}
|
|||
}
|
|||
else if (b_y == 0)
|
|||
{
|
|||
for (dpos = 0; dpos < cmpnfo[cmp].bc; dpos++)
|
|||
if (colldata[cmp][bpos][dpos] != 0)
|
|||
{
|
|||
zdstxlow[cmp][dpos]++;
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
for (dpos = 0; dpos < cmpnfo[cmp].bc; dpos++)
|
|||
if (colldata[cmp][bpos][dpos] != 0)
|
|||
{
|
|||
zdstdata[cmp][dpos]++;
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
packs all parts to compressed pjg
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pack_pjg(void)
|
|||
{
|
|||
unsigned char hcode;
|
|||
int cmp;
|
|||
#if defined(DEV_INFOS)
|
|||
int dev_size = 0;
|
|||
#endif
|
|||
// PJG-Header
|
|||
str_out->write(reinterpret_cast<const unsigned char*>(pjg_magic), 2);
|
|||
// store settings if not auto
|
|||
if (!auto_set)
|
|||
{
|
|||
hcode = 0x00;
|
|||
str_out->write_byte(hcode);
|
|||
str_out->write(nois_trs, 4);
|
|||
str_out->write(segm_cnt, 4);
|
|||
}
|
|||
// store version number
|
|||
hcode = appversion;
|
|||
str_out->write_byte(hcode);
|
|||
// init arithmetic compression
|
|||
auto encoder = new ArithmeticEncoder(*str_out);
|
|||
// discard meta information from header if option set
|
|||
if (disc_meta)
|
|||
if (!jpg_rebuild_header())
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// optimize header for compression
|
|||
if (!pjg_optimize_header())
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// set padbit to 1 if previously unset
|
|||
if (padbit == -1)
|
|||
{
|
|||
padbit = 1;
|
|||
}
|
|||
// encode JPG header
|
|||
#if !defined(DEV_INFOS)
|
|||
if (!pjg_encode_generic(encoder, hdrdata, hdrs))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
#else
|
|||
dev_size = str_out->getpos();
|
|||
if (!pjg_encode_generic(encoder, hdrdata, hdrs))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
dev_size_hdr += str_out->getpos() - dev_size;
|
|||
#endif
|
|||
// store padbit (padbit can't be retrieved from the header)
|
|||
if (!pjg_encode_bit(encoder, padbit))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// also encode one bit to signal false/correct use of RST markers
|
|||
if (!pjg_encode_bit(encoder, (rst_err == nullptr) ? 0 : 1))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// encode # of false set RST markers per scan
|
|||
if (rst_err != nullptr)
|
|||
if (!pjg_encode_generic(encoder, rst_err, scnc))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// encode actual components data
|
|||
for (cmp = 0; cmp < cmpc; cmp++)
|
|||
{
|
|||
#if !defined(DEV_INFOS)
|
|||
// encode frequency scan ('zero-sort-scan')
|
|||
if (!pjg_encode_zstscan(encoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// encode zero-distribution-lists for higher (7x7) ACs
|
|||
if (!pjg_encode_zdst_high(encoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// encode coefficients for higher (7x7) ACs
|
|||
if (!pjg_encode_ac_high(encoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// encode zero-distribution-lists for lower ACs
|
|||
if (!pjg_encode_zdst_low(encoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// encode coefficients for first row / collumn ACs
|
|||
if (!pjg_encode_ac_low(encoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// encode coefficients for DC
|
|||
if (!pjg_encode_dc(encoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
#else
|
|||
dev_size = str_out->getpos();
|
|||
// encode frequency scan ('zero-sort-scan')
|
|||
if (!pjg_encode_zstscan(encoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
dev_size_zsr[cmp] += str_out->getpos() - dev_size;
|
|||
dev_size = str_out->getpos();
|
|||
// encode zero-distribution-lists for higher (7x7) ACs
|
|||
if (!pjg_encode_zdst_high(encoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
dev_size_zdh[cmp] += str_out->getpos() - dev_size;
|
|||
dev_size = str_out->getpos();
|
|||
// encode coefficients for higher (7x7) ACs
|
|||
if (!pjg_encode_ac_high(encoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
dev_size_ach[cmp] += str_out->getpos() - dev_size;
|
|||
dev_size = str_out->getpos();
|
|||
// encode zero-distribution-lists for lower ACs
|
|||
if (!pjg_encode_zdst_low(encoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
dev_size_zdl[cmp] += str_out->getpos() - dev_size;
|
|||
dev_size = str_out->getpos();
|
|||
// encode coefficients for first row / collumn ACs
|
|||
if (!pjg_encode_ac_low(encoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
dev_size_acl[cmp] += str_out->getpos() - dev_size;
|
|||
dev_size = str_out->getpos();
|
|||
// encode coefficients for DC
|
|||
if (!pjg_encode_dc(encoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
dev_size_dc[cmp] += str_out->getpos() - dev_size;
|
|||
dev_size_cmp[cmp] =
|
|||
dev_size_zsr[cmp] + dev_size_zdh[cmp] + dev_size_zdl[cmp] +
|
|||
dev_size_ach[cmp] + dev_size_acl[cmp] + dev_size_dc[cmp];
|
|||
#endif
|
|||
}
|
|||
// encode checkbit for garbage (0 if no garbage, 1 if garbage has to be coded)
|
|||
if (!pjg_encode_bit(encoder, (grbs > 0) ? 1 : 0))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// encode garbage data only if needed
|
|||
if (grbs > 0)
|
|||
if (!pjg_encode_generic(encoder, grbgdata, grbs))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// finalize arithmetic compression
|
|||
delete encoder;
|
|||
// errormessage if write error
|
|||
if (str_out->error())
|
|||
{
|
|||
sprintf(errormessage, "write error, possibly drive is full");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
// get filesize
|
|||
pjgfilesize = str_out->num_bytes_written();
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
unpacks compressed pjg to colldata
|
|||
----------------------------------------------- */
|
|||
bool packJPG::unpack_pjg(void)
|
|||
{
|
|||
unsigned char hcode;
|
|||
unsigned char cb;
|
|||
int cmp;
|
|||
// check header codes ( maybe position in other function ? )
|
|||
while (true)
|
|||
{
|
|||
str_in->read_byte(&hcode);
|
|||
if (hcode == 0x00)
|
|||
{
|
|||
// retrieve compression settings from file
|
|||
str_in->read(nois_trs, 4);
|
|||
str_in->read(segm_cnt, 4);
|
|||
auto_set = false;
|
|||
}
|
|||
else if (hcode >= 0x14)
|
|||
{
|
|||
// compare version number
|
|||
if (hcode != appversion)
|
|||
{
|
|||
sprintf(errormessage, "incompatible file, use %s v%i.%i",
|
|||
appname, hcode / 10, hcode % 10);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
else
|
|||
{
|
|||
break;
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
sprintf(errormessage, "unknown header code, use newer version of %s", appname);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
}
|
|||
// init arithmetic compression
|
|||
auto decoder = new ArithmeticDecoder(*str_in);
|
|||
// decode JPG header
|
|||
if (!pjg_decode_generic(decoder, &hdrdata, &hdrs))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// retrieve padbit from stream
|
|||
if (!pjg_decode_bit(decoder, &cb))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
padbit = cb;
|
|||
// decode one bit that signals false /correct use of RST markers
|
|||
if (!pjg_decode_bit(decoder, &cb))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// decode # of false set RST markers per scan only if available
|
|||
if (cb == 1)
|
|||
if (!pjg_decode_generic(decoder, &rst_err, nullptr))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// undo header optimizations
|
|||
if (!pjg_unoptimize_header())
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// discard meta information from header if option set
|
|||
if (disc_meta)
|
|||
if (!jpg_rebuild_header())
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// parse header for image-info
|
|||
if (!jpg_setup_imginfo())
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// decode actual components data
|
|||
for (cmp = 0; cmp < cmpc; cmp++)
|
|||
{
|
|||
// decode frequency scan ('zero-sort-scan')
|
|||
if (!pjg_decode_zstscan(decoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// decode zero-distribution-lists for higher (7x7) ACs
|
|||
if (!pjg_decode_zdst_high(decoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// decode coefficients for higher (7x7) ACs
|
|||
if (!pjg_decode_ac_high(decoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// decode zero-distribution-lists for lower ACs
|
|||
if (!pjg_decode_zdst_low(decoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// decode coefficients for first row / collumn ACs
|
|||
if (!pjg_decode_ac_low(decoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// decode coefficients for DC
|
|||
if (!pjg_decode_dc(decoder, cmp))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
}
|
|||
// retrieve checkbit for garbage (0 if no garbage, 1 if garbage has to be coded)
|
|||
if (!pjg_decode_bit(decoder, &cb))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// decode garbage data only if available
|
|||
if (cb == 0)
|
|||
{
|
|||
grbs = 0;
|
|||
}
|
|||
else if (!pjg_decode_generic(decoder, &grbgdata, &grbs))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
// finalize arithmetic compression
|
|||
delete decoder;
|
|||
// get filesize
|
|||
pjgfilesize = str_in->get_size();
|
|||
return true;
|
|||
}
|
|||
/* ------------------------ End of main functions -------------------------- */
|
|||
/* ----------------------- Begin of JPEG specific functions ---------------- */
|
|||
/* -----------------------------------------------
|
|||
Parses header for imageinfo
|
|||
----------------------------------------------- */
|
|||
bool packJPG::jpg_setup_imginfo(void)
|
|||
{
|
|||
unsigned char type = 0x00; // type of current marker segment
|
|||
unsigned int len = 0; // length of current marker segment
|
|||
unsigned int hpos = 0; // position in header
|
|||
int cmp, bpos;
|
|||
int i;
|
|||
// header parser loop
|
|||
while ((int) hpos < hdrs)
|
|||
{
|
|||
type = hdrdata[hpos + 1];
|
|||
len = 2 + B_SHORT(hdrdata[hpos + 2], hdrdata[hpos + 3]);
|
|||
// do not parse DHT & DRI
|
|||
if ((type != 0xDA) && (type != 0xC4) && (type != 0xDD))
|
|||
{
|
|||
if (!jpg_parse_jfif(type, len, &(hdrdata[hpos])))
|
|||
{
|
|||
return false;
|
|||
}
|
|||
}
|
|||
hpos += len;
|
|||
}
|
|||
// check if information is complete
|
|||
if (cmpc == 0)
|
|||
{
|
|||
sprintf(errormessage, "header contains incomplete information");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
for (cmp = 0; cmp < cmpc; cmp++)
|
|||
{
|
|||
if ((cmpnfo[cmp].sfv == 0) ||
|
|||
(cmpnfo[cmp].sfh == 0) ||
|
|||
(cmpnfo[cmp].qtable == nullptr) ||
|
|||
(cmpnfo[cmp].qtable[0] == 0) ||
|
|||
(jpegtype == 0))
|
|||
{
|
|||
sprintf(errormessage, "header information is incomplete");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
}
|
|||
// do all remaining component info calculations
|
|||
for (cmp = 0; cmp < cmpc; cmp++)
|
|||
{
|
|||
if (cmpnfo[cmp].sfh > sfhm)
|
|||
{
|
|||
sfhm = cmpnfo[cmp].sfh;
|
|||
}
|
|||
if (cmpnfo[cmp].sfv > sfvm)
|
|||
{
|
|||
sfvm = cmpnfo[cmp].sfv;
|
|||
}
|
|||
}
|
|||
mcuv = (int) ceil((float) imgheight / (float)(8 * sfhm));
|
|||
mcuh = (int) ceil((float) imgwidth / (float)(8 * sfvm));
|
|||
mcuc = mcuv * mcuh;
|
|||
for (cmp = 0; cmp < cmpc; cmp++)
|
|||
{
|
|||
cmpnfo[cmp].mbs = cmpnfo[cmp].sfv * cmpnfo[cmp].sfh;
|
|||
cmpnfo[cmp].bcv = mcuv * cmpnfo[cmp].sfh;
|
|||
cmpnfo[cmp].bch = mcuh * cmpnfo[cmp].sfv;
|
|||
cmpnfo[cmp].bc = cmpnfo[cmp].bcv * cmpnfo[cmp].bch;
|
|||
cmpnfo[cmp].ncv = (int) ceil((float) imgheight *
|
|||
((float) cmpnfo[cmp].sfh / (8.0 * sfhm)));
|
|||
cmpnfo[cmp].nch = (int) ceil((float) imgwidth *
|
|||
((float) cmpnfo[cmp].sfv / (8.0 * sfvm)));
|
|||
cmpnfo[cmp].nc = cmpnfo[cmp].ncv * cmpnfo[cmp].nch;
|
|||
}
|
|||
// decide components' statistical ids
|
|||
if (cmpc <= 3)
|
|||
{
|
|||
for (cmp = 0; cmp < cmpc; cmp++)
|
|||
{
|
|||
cmpnfo[cmp].sid = cmp;
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
for (cmp = 0; cmp < cmpc; cmp++)
|
|||
{
|
|||
cmpnfo[cmp].sid = 0;
|
|||
}
|
|||
}
|
|||
// alloc memory for further operations
|
|||
for (cmp = 0; cmp < cmpc; cmp++)
|
|||
{
|
|||
// alloc memory for colls
|
|||
for (bpos = 0; bpos < 64; bpos++)
|
|||
{
|
|||
colldata[cmp][bpos] = (short int*) calloc(cmpnfo[cmp].bc, sizeof(short));
|
|||
if (colldata[cmp][bpos] == nullptr)
|
|||
{
|
|||
sprintf(errormessage, MEM_ERRMSG);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
}
|
|||
// alloc memory for zdstlist / eob x / eob y
|
|||
zdstdata[cmp] = (unsigned char*) calloc(cmpnfo[cmp].bc, sizeof(char));
|
|||
eobxhigh[cmp] = (unsigned char*) calloc(cmpnfo[cmp].bc, sizeof(char));
|
|||
eobyhigh[cmp] = (unsigned char*) calloc(cmpnfo[cmp].bc, sizeof(char));
|
|||
zdstxlow[cmp] = (unsigned char*) calloc(cmpnfo[cmp].bc, sizeof(char));
|
|||
zdstylow[cmp] = (unsigned char*) calloc(cmpnfo[cmp].bc, sizeof(char));
|
|||
if ((zdstdata[cmp] == nullptr) ||
|
|||
(eobxhigh[cmp] == nullptr) || (eobyhigh[cmp] == nullptr) ||
|
|||
(zdstxlow[cmp] == nullptr) || (zdstylow[cmp] == nullptr))
|
|||
{
|
|||
sprintf(errormessage, MEM_ERRMSG);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
}
|
|||
// also decide automatic settings here
|
|||
if (auto_set)
|
|||
{
|
|||
for (cmp = 0; cmp < cmpc; cmp++)
|
|||
{
|
|||
for (i = 0;
|
|||
conf_sets[i][cmpnfo[cmp].sid] > (unsigned int) cmpnfo[cmp].bc;
|
|||
i++);
|
|||
segm_cnt[cmp] = conf_segm[i][cmpnfo[cmp].sid];
|
|||
nois_trs[cmp] = conf_ntrs[i][cmpnfo[cmp].sid];
|
|||
}
|
|||
}
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
Parse routines for JFIF segments
|
|||
----------------------------------------------- */
|
|||
bool packJPG::jpg_parse_jfif(
|
|||
unsigned char type,
|
|||
unsigned int len,
|
|||
unsigned char* segment)
|
|||
{
|
|||
unsigned int hpos = 4; // current position in segment, start after segment header
|
|||
int lval, rval; // temporary variables
|
|||
int skip;
|
|||
int cmp;
|
|||
int i;
|
|||
switch (type)
|
|||
{
|
|||
case 0xC4: // DHT segment
|
|||
// build huffman trees & codes
|
|||
while (hpos < len)
|
|||
{
|
|||
lval = LBITS(segment[hpos], 4);
|
|||
rval = RBITS(segment[hpos], 4);
|
|||
if (((lval < 0) || (lval >= 2)) || ((rval < 0) || (rval >= 4)))
|
|||
{
|
|||
break;
|
|||
}
|
|||
hpos++;
|
|||
// build huffman codes & trees
|
|||
jpg_build_huffcodes(&(segment[hpos + 0]), &(segment[hpos + 16]),
|
|||
&(hcodes[lval][rval]), &(htrees[lval][rval]));
|
|||
htset[lval][rval] = 1;
|
|||
skip = 16;
|
|||
for (i = 0; i < 16; i++)
|
|||
{
|
|||
skip += (int) segment[hpos + i];
|
|||
}
|
|||
hpos += skip;
|
|||
}
|
|||
if (hpos != len)
|
|||
{
|
|||
// if we get here, something went wrong
|
|||
sprintf(errormessage, "size mismatch in dht marker");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
return true;
|
|||
case 0xDB: // DQT segment
|
|||
// copy quantization tables to internal memory
|
|||
while (hpos < len)
|
|||
{
|
|||
lval = LBITS(segment[hpos], 4);
|
|||
rval = RBITS(segment[hpos], 4);
|
|||
if ((lval < 0) || (lval >= 2))
|
|||
{
|
|||
break;
|
|||
}
|
|||
if ((rval < 0) || (rval >= 4))
|
|||
{
|
|||
break;
|
|||
}
|
|||
hpos++;
|
|||
if (lval == 0) // 8 bit precision
|
|||
{
|
|||
for (i = 0; i < 64; i++)
|
|||
{
|
|||
qtables[rval][i] = (unsigned short) segment[hpos + i];
|
|||
if (qtables[rval][i] == 0)
|
|||
{
|
|||
break;
|
|||
}
|
|||
}
|
|||
hpos += 64;
|
|||
}
|
|||
else // 16 bit precision
|
|||
{
|
|||
for (i = 0; i < 64; i++)
|
|||
{
|
|||
qtables[rval][i] =
|
|||
B_SHORT(segment[hpos + (2*i)], segment[hpos + (2*i) + 1]);
|
|||
if (qtables[rval][i] == 0)
|
|||
{
|
|||
break;
|
|||
}
|
|||
}
|
|||
hpos += 128;
|
|||
}
|
|||
}
|
|||
if (hpos != len)
|
|||
{
|
|||
// if we get here, something went wrong
|
|||
sprintf(errormessage, "size mismatch in dqt marker");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
return true;
|
|||
case 0xDD: // DRI segment
|
|||
// define restart interval
|
|||
rsti = B_SHORT(segment[hpos], segment[hpos + 1]);
|
|||
return true;
|
|||
case 0xDA: // SOS segment
|
|||
// prepare next scan
|
|||
cs_cmpc = segment[hpos];
|
|||
if (cs_cmpc > cmpc)
|
|||
{
|
|||
sprintf(errormessage, "%i components in scan, only %i are allowed",
|
|||
cs_cmpc, cmpc);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
hpos++;
|
|||
for (i = 0; i < cs_cmpc; i++)
|
|||
{
|
|||
for (cmp = 0; (segment[hpos] != cmpnfo[cmp].jid) && (cmp < cmpc); cmp++);
|
|||
if (cmp == cmpc)
|
|||
{
|
|||
sprintf(errormessage, "component id mismatch in start-of-scan");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
cs_cmp[i] = cmp;
|
|||
cmpnfo[cmp].huffdc = LBITS(segment[hpos + 1], 4);
|
|||
cmpnfo[cmp].huffac = RBITS(segment[hpos + 1], 4);
|
|||
if ((cmpnfo[cmp].huffdc < 0) || (cmpnfo[cmp].huffdc >= 4) ||
|
|||
(cmpnfo[cmp].huffac < 0) || (cmpnfo[cmp].huffac >= 4))
|
|||
{
|
|||
sprintf(errormessage, "huffman table number mismatch");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
hpos += 2;
|
|||
}
|
|||
cs_from = segment[hpos + 0];
|
|||
cs_to = segment[hpos + 1];
|
|||
cs_sah = LBITS(segment[hpos + 2], 4);
|
|||
cs_sal = RBITS(segment[hpos + 2], 4);
|
|||
// check for errors
|
|||
if ((cs_from > cs_to) || (cs_from > 63) || (cs_to > 63))
|
|||
{
|
|||
sprintf(errormessage, "spectral selection parameter out of range");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
if ((cs_sah >= 12) || (cs_sal >= 12))
|
|||
{
|
|||
sprintf(errormessage, "successive approximation parameter out of range");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
return true;
|
|||
case 0xC0: // SOF0 segment
|
|||
// coding process: baseline DCT
|
|||
case 0xC1: // SOF1 segment
|
|||
// coding process: extended sequential DCT
|
|||
case 0xC2: // SOF2 segment
|
|||
// coding process: progressive DCT
|
|||
// set JPEG coding type
|
|||
if (type == 0xC2)
|
|||
{
|
|||
jpegtype = 2;
|
|||
}
|
|||
else
|
|||
{
|
|||
jpegtype = 1;
|
|||
}
|
|||
// check data precision, only 8 bit is allowed
|
|||
lval = segment[hpos];
|
|||
if (lval != 8)
|
|||
{
|
|||
sprintf(errormessage, "%i bit data precision is not supported", lval);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
// image size, height & component count
|
|||
imgheight = B_SHORT(segment[hpos + 1], segment[hpos + 2]);
|
|||
imgwidth = B_SHORT(segment[hpos + 3], segment[hpos + 4]);
|
|||
cmpc = segment[hpos + 5];
|
|||
if ((imgwidth == 0) || (imgheight == 0))
|
|||
{
|
|||
sprintf(errormessage, "resolution is %ix%i, possible malformed JPEG", imgwidth, imgheight);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
if (cmpc > 4)
|
|||
{
|
|||
sprintf(errormessage, "image has %i components, max 4 are supported", cmpc);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
hpos += 6;
|
|||
// components contained in image
|
|||
for (cmp = 0; cmp < cmpc; cmp++)
|
|||
{
|
|||
cmpnfo[cmp].jid = segment[hpos];
|
|||
cmpnfo[cmp].sfv = LBITS(segment[hpos + 1], 4);
|
|||
cmpnfo[cmp].sfh = RBITS(segment[hpos + 1], 4);
|
|||
cmpnfo[cmp].qtable = qtables[segment[hpos + 2]];
|
|||
hpos += 3;
|
|||
}
|
|||
return true;
|
|||
case 0xC3: // SOF3 segment
|
|||
// coding process: lossless sequential
|
|||
sprintf(errormessage, "sof3 marker found, image is coded lossless");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
case 0xC5: // SOF5 segment
|
|||
// coding process: differential sequential DCT
|
|||
sprintf(errormessage, "sof5 marker found, image is coded diff. sequential");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
case 0xC6: // SOF6 segment
|
|||
// coding process: differential progressive DCT
|
|||
sprintf(errormessage, "sof6 marker found, image is coded diff. progressive");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
case 0xC7: // SOF7 segment
|
|||
// coding process: differential lossless
|
|||
sprintf(errormessage, "sof7 marker found, image is coded diff. lossless");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
case 0xC9: // SOF9 segment
|
|||
// coding process: arithmetic extended sequential DCT
|
|||
sprintf(errormessage, "sof9 marker found, image is coded arithm. sequential");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
case 0xCA: // SOF10 segment
|
|||
// coding process: arithmetic extended sequential DCT
|
|||
sprintf(errormessage, "sof10 marker found, image is coded arithm. progressive");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
case 0xCB: // SOF11 segment
|
|||
// coding process: arithmetic extended sequential DCT
|
|||
sprintf(errormessage, "sof11 marker found, image is coded arithm. lossless");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
case 0xCD: // SOF13 segment
|
|||
// coding process: arithmetic differntial sequential DCT
|
|||
sprintf(errormessage, "sof13 marker found, image is coded arithm. diff. sequential");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
case 0xCE: // SOF14 segment
|
|||
// coding process: arithmetic differential progressive DCT
|
|||
sprintf(errormessage, "sof14 marker found, image is coded arithm. diff. progressive");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
case 0xCF: // SOF15 segment
|
|||
// coding process: arithmetic differntial lossless
|
|||
sprintf(errormessage, "sof15 marker found, image is coded arithm. diff. lossless");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
case 0xE0: // APP0 segment
|
|||
case 0xE1: // APP1 segment
|
|||
case 0xE2: // APP2 segment
|
|||
case 0xE3: // APP3 segment
|
|||
case 0xE4: // APP4 segment
|
|||
case 0xE5: // APP5 segment
|
|||
case 0xE6: // APP6 segment
|
|||
case 0xE7: // APP7 segment
|
|||
case 0xE8: // APP8 segment
|
|||
case 0xE9: // APP9 segment
|
|||
case 0xEA: // APP10 segment
|
|||
case 0xEB: // APP11 segment
|
|||
case 0xEC: // APP12 segment
|
|||
case 0xED: // APP13 segment
|
|||
case 0xEE: // APP14 segment
|
|||
case 0xEF: // APP15 segment
|
|||
case 0xFE: // COM segment
|
|||
// do nothing - return true
|
|||
return true;
|
|||
case 0xD0: // RST0 segment
|
|||
case 0xD1: // RST1 segment
|
|||
case 0xD2: // RST2 segment
|
|||
case 0xD3: // RST3 segment
|
|||
case 0xD4: // RST4 segment
|
|||
case 0xD5: // RST5 segment
|
|||
case 0xD6: // RST6 segment
|
|||
case 0xD7: // RST7 segment
|
|||
// return errormessage - RST is out of place here
|
|||
sprintf(errormessage, "rst marker found out of place");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
case 0xD8: // SOI segment
|
|||
// return errormessage - start-of-image is out of place here
|
|||
sprintf(errormessage, "soi marker found out of place");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
case 0xD9: // EOI segment
|
|||
// return errormessage - end-of-image is out of place here
|
|||
sprintf(errormessage, "eoi marker found out of place");
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
default: // unknown marker segment
|
|||
// return warning
|
|||
sprintf(errormessage, "unknown marker found: FF %2X", type);
|
|||
errorlevel = 1;
|
|||
return true;
|
|||
}
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
JFIF header rebuilding routine
|
|||
----------------------------------------------- */
|
|||
bool packJPG::jpg_rebuild_header(void)
|
|||
{
|
|||
unsigned char type = 0x00; // type of current marker segment
|
|||
unsigned int len = 0; // length of current marker segment
|
|||
unsigned int hpos = 0; // position in header
|
|||
// start headerwriter
|
|||
MemoryWriter* hdrw = new MemoryWriter(); // new header writer
|
|||
// header parser loop
|
|||
while ((int) hpos < hdrs)
|
|||
{
|
|||
type = hdrdata[hpos + 1];
|
|||
len = 2 + B_SHORT(hdrdata[hpos + 2], hdrdata[hpos + 3]);
|
|||
// discard any unneeded meta info
|
|||
if ((type == 0xDA) || (type == 0xC4) || (type == 0xDB) ||
|
|||
(type == 0xC0) || (type == 0xC1) || (type == 0xC2) ||
|
|||
(type == 0xDD))
|
|||
{
|
|||
hdrw->write(&(hdrdata[hpos]), len);
|
|||
}
|
|||
hpos += len;
|
|||
}
|
|||
// replace current header with the new one
|
|||
free(hdrdata);
|
|||
hdrdata = hdrw->get_c_data();
|
|||
hdrs = hdrw->num_bytes_written();
|
|||
delete hdrw;
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
sequential block decoding routine
|
|||
----------------------------------------------- */
|
|||
int packJPG::jpg_decode_block_seq(
|
|||
BitReader* huffr,
|
|||
huffTree* dctree,
|
|||
huffTree* actree,
|
|||
short* block)
|
|||
{
|
|||
unsigned short n;
|
|||
unsigned char s;
|
|||
unsigned char z;
|
|||
int eob = 64;
|
|||
int bpos;
|
|||
int hc;
|
|||
// decode dc
|
|||
hc = jpg_next_huffcode(huffr, dctree);
|
|||
if (hc < 0)
|
|||
{
|
|||
return -1; // return error
|
|||
}
|
|||
else
|
|||
{
|
|||
s = (unsigned char) hc;
|
|||
}
|
|||
n = huffr->read(s);
|
|||
block[0] = DEVLI(s, n);
|
|||
// decode ac
|
|||
for (bpos = 1; bpos < 64;)
|
|||
{
|
|||
// decode next
|
|||
hc = jpg_next_huffcode(huffr, actree);
|
|||
// analyse code
|
|||
if (hc > 0)
|
|||
{
|
|||
z = LBITS(hc, 4);
|
|||
s = RBITS(hc, 4);
|
|||
n = huffr->read(s);
|
|||
if ((z + bpos) >= 64)
|
|||
{
|
|||
return -1; // run is to long
|
|||
}
|
|||
while (z > 0) // write zeroes
|
|||
{
|
|||
block[bpos++] = 0;
|
|||
z--;
|
|||
}
|
|||
block[bpos++] = (short) DEVLI(s, n); // decode cvli
|
|||
}
|
|||
else if (hc == 0) // EOB
|
|||
{
|
|||
eob = bpos;
|
|||
// while( bpos < 64 ) // fill remaining block with zeroes
|
|||
// block[bpos++] = 0;
|
|||
break;
|
|||
}
|
|||
else
|
|||
{
|
|||
return -1; // return error
|
|||
}
|
|||
}
|
|||
// return position of eob
|
|||
return eob;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
sequential block encoding routine
|
|||
----------------------------------------------- */
|
|||
int packJPG::jpg_encode_block_seq(
|
|||
BitWriter* huffw,
|
|||
huffCodes* dctbl,
|
|||
huffCodes* actbl,
|
|||
short* block)
|
|||
{
|
|||
unsigned short n;
|
|||
unsigned char s;
|
|||
unsigned char z;
|
|||
int bpos;
|
|||
int hc;
|
|||
// encode DC
|
|||
s = BITLEN2048N(block[0]);
|
|||
n = ENVLI(s, block[0]);
|
|||
huffw->write_u16(dctbl->cval[s], dctbl->clen[s]);
|
|||
huffw->write_u16(n, s);
|
|||
// encode AC
|
|||
z = 0;
|
|||
for (bpos = 1; bpos < 64; bpos++)
|
|||
{
|
|||
// if nonzero is encountered
|
|||
if (block[bpos] != 0)
|
|||
{
|
|||
// write remaining zeroes
|
|||
while (z >= 16)
|
|||
{
|
|||
huffw->write_u16(actbl->cval[0xF0], actbl->clen[0xF0]);
|
|||
z -= 16;
|
|||
}
|
|||
// vli encode
|
|||
s = BITLEN2048N(block[bpos]);
|
|||
n = ENVLI(s, block[bpos]);
|
|||
hc = ((z << 4) + s);
|
|||
// write to huffman writer
|
|||
huffw->write_u16(actbl->cval[hc], actbl->clen[hc]);
|
|||
huffw->write_u16(n, s);
|
|||
// reset zeroes
|
|||
z = 0;
|
|||
}
|
|||
else // increment zero counter
|
|||
{
|
|||
z++;
|
|||
}
|
|||
}
|
|||
// write eob if needed
|
|||
if (z > 0)
|
|||
{
|
|||
huffw->write_u16(actbl->cval[0x00], actbl->clen[0x00]);
|
|||
}
|
|||
return 64 - z;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
progressive DC decoding routine
|
|||
----------------------------------------------- */
|
|||
int packJPG::jpg_decode_dc_prg_fs(
|
|||
BitReader* huffr,
|
|||
huffTree* dctree,
|
|||
short* block)
|
|||
{
|
|||
unsigned short n;
|
|||
unsigned char s;
|
|||
int hc;
|
|||
// decode dc
|
|||
hc = jpg_next_huffcode(huffr, dctree);
|
|||
if (hc < 0)
|
|||
{
|
|||
return -1; // return error
|
|||
}
|
|||
else
|
|||
{
|
|||
s = (unsigned char) hc;
|
|||
}
|
|||
n = huffr->read(s);
|
|||
block[0] = DEVLI(s, n);
|
|||
// return 0 if everything is ok
|
|||
return 0;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
progressive DC encoding routine
|
|||
----------------------------------------------- */
|
|||
int packJPG::jpg_encode_dc_prg_fs(
|
|||
BitWriter* huffw,
|
|||
huffCodes* dctbl,
|
|||
short* block)
|
|||
{
|
|||
unsigned short n;
|
|||
unsigned char s;
|
|||
// encode DC
|
|||
s = BITLEN2048N(block[0]);
|
|||
n = ENVLI(s, block[0]);
|
|||
huffw->write_u16(dctbl->cval[s], dctbl->clen[s]);
|
|||
huffw->write_u16(n, s);
|
|||
// return 0 if everything is ok
|
|||
return 0;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
progressive AC decoding routine
|
|||
----------------------------------------------- */
|
|||
int packJPG::jpg_decode_ac_prg_fs(
|
|||
BitReader* huffr,
|
|||
huffTree* actree,
|
|||
short* block,
|
|||
int* eobrun,
|
|||
int from,
|
|||
int to)
|
|||
{
|
|||
unsigned short n;
|
|||
unsigned char s;
|
|||
unsigned char z;
|
|||
int eob = to + 1;
|
|||
int bpos;
|
|||
int hc;
|
|||
int l;
|
|||
int r;
|
|||
// decode ac
|
|||
for (bpos = from; bpos <= to;)
|
|||
{
|
|||
// decode next
|
|||
hc = jpg_next_huffcode(huffr, actree);
|
|||
if (hc < 0)
|
|||
{
|
|||
return -1;
|
|||
}
|
|||
l = LBITS(hc, 4);
|
|||
r = RBITS(hc, 4);
|
|||
// analyse code
|
|||
if ((l == 15) || (r > 0)) // decode run/level combination
|
|||
{
|
|||
z = l;
|
|||
s = r;
|
|||
n = huffr->read(s);
|
|||
if ((z + bpos) > to)
|
|||
{
|
|||
return -1; // run is to long
|
|||
}
|
|||
while (z > 0) // write zeroes
|
|||
{
|
|||
block[bpos++] = 0;
|
|||
z--;
|
|||
}
|
|||
block[bpos++] = (short) DEVLI(s, n); // decode cvli
|
|||
}
|
|||
else // decode eobrun
|
|||
{
|
|||
eob = bpos;
|
|||
s = l;
|
|||
n = huffr->read(s);
|
|||
(*eobrun) = E_DEVLI(s, n);
|
|||
// while( bpos <= to ) // fill remaining block with zeroes
|
|||
// block[bpos++] = 0;
|
|||
break;
|
|||
}
|
|||
}
|
|||
// return position of eob
|
|||
return eob;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
progressive AC encoding routine
|
|||
----------------------------------------------- */
|
|||
int packJPG::jpg_encode_ac_prg_fs(
|
|||
BitWriter* huffw,
|
|||
huffCodes* actbl,
|
|||
short* block,
|
|||
int* eobrun,
|
|||
int from,
|
|||
int to)
|
|||
{
|
|||
unsigned short n;
|
|||
unsigned char s;
|
|||
unsigned char z;
|
|||
int bpos;
|
|||
int hc;
|
|||
// encode AC
|
|||
z = 0;
|
|||
for (bpos = from; bpos <= to; bpos++)
|
|||
{
|
|||
// if nonzero is encountered
|
|||
if (block[bpos] != 0)
|
|||
{
|
|||
// encode eobrun
|
|||
jpg_encode_eobrun(huffw, actbl, eobrun);
|
|||
// write remaining zeroes
|
|||
while (z >= 16)
|
|||
{
|
|||
huffw->write_u16(actbl->cval[0xF0], actbl->clen[0xF0]);
|
|||
z -= 16;
|
|||
}
|
|||
// vli encode
|
|||
s = BITLEN2048N(block[bpos]);
|
|||
n = ENVLI(s, block[bpos]);
|
|||
hc = ((z << 4) + s);
|
|||
// write to huffman writer
|
|||
huffw->write_u16(actbl->cval[hc], actbl->clen[hc]);
|
|||
huffw->write_u16(n, s);
|
|||
// reset zeroes
|
|||
z = 0;
|
|||
}
|
|||
else // increment zero counter
|
|||
{
|
|||
z++;
|
|||
}
|
|||
}
|
|||
// check eob, increment eobrun if needed
|
|||
if (z > 0)
|
|||
{
|
|||
(*eobrun)++;
|
|||
// check eobrun, encode if needed
|
|||
if ((*eobrun) == actbl->max_eobrun)
|
|||
{
|
|||
jpg_encode_eobrun(huffw, actbl, eobrun);
|
|||
}
|
|||
return 1 + to - z;
|
|||
}
|
|||
else
|
|||
{
|
|||
return 1 + to;
|
|||
}
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
progressive DC SA decoding routine
|
|||
----------------------------------------------- */
|
|||
int packJPG::jpg_decode_dc_prg_sa(BitReader* huffr, short* block)
|
|||
{
|
|||
// decode next bit of dc coefficient
|
|||
block[0] = huffr->read(1);
|
|||
// return 0 if everything is ok
|
|||
return 0;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
progressive DC SA encoding routine
|
|||
----------------------------------------------- */
|
|||
int packJPG::jpg_encode_dc_prg_sa(BitWriter* huffw, short* block)
|
|||
{
|
|||
// enocode next bit of dc coefficient
|
|||
huffw->write_u16(block[0], 1);
|
|||
// return 0 if everything is ok
|
|||
return 0;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
progressive AC SA decoding routine
|
|||
----------------------------------------------- */
|
|||
int packJPG::jpg_decode_ac_prg_sa(
|
|||
BitReader* huffr,
|
|||
huffTree* actree,
|
|||
short* block,
|
|||
int* eobrun,
|
|||
int from,
|
|||
int to)
|
|||
{
|
|||
unsigned short n;
|
|||
unsigned char s;
|
|||
signed char z;
|
|||
signed char v;
|
|||
int bpos = from;
|
|||
int eob = to;
|
|||
int hc;
|
|||
int l;
|
|||
int r;
|
|||
// decode AC succesive approximation bits
|
|||
if ((*eobrun) == 0) while (bpos <= to)
|
|||
{
|
|||
// decode next
|
|||
hc = jpg_next_huffcode(huffr, actree);
|
|||
if (hc < 0)
|
|||
{
|
|||
return -1;
|
|||
}
|
|||
l = LBITS(hc, 4);
|
|||
r = RBITS(hc, 4);
|
|||
// analyse code
|
|||
if ((l == 15) || (r > 0)) // decode run/level combination
|
|||
{
|
|||
z = l;
|
|||
s = r;
|
|||
if (s == 0)
|
|||
{
|
|||
v = 0;
|
|||
}
|
|||
else if (s == 1)
|
|||
{
|
|||
n = huffr->read(1);
|
|||
v = (n == 0) ? -1 : 1; // fast decode vli
|
|||
}
|
|||
else
|
|||
{
|
|||
return -1; // decoding error
|
|||
}
|
|||
// write zeroes / write correction bits
|
|||
while (true)
|
|||
{
|
|||
if (block[bpos] == 0) // skip zeroes / write value
|
|||
{
|
|||
if (z > 0)
|
|||
{
|
|||
z--;
|
|||
}
|
|||
else
|
|||
{
|
|||
block[bpos++] = v;
|
|||
break;
|
|||
}
|
|||
}
|
|||
else // read correction bit
|
|||
{
|
|||
n = huffr->read(1);
|
|||
block[bpos] = (block[bpos] > 0) ? n : -n;
|
|||
}
|
|||
if (bpos++ >= to)
|
|||
{
|
|||
return -1; // error check
|
|||
}
|
|||
}
|
|||
}
|
|||
else // decode eobrun
|
|||
{
|
|||
eob = bpos;
|
|||
s = l;
|
|||
n = huffr->read(s);
|
|||
(*eobrun) = E_DEVLI(s, n);
|
|||
break;
|
|||
}
|
|||
}
|
|||
// read after eob correction bits
|
|||
if ((*eobrun) > 0)
|
|||
{
|
|||
for (; bpos <= to; bpos++)
|
|||
{
|
|||
if (block[bpos] != 0)
|
|||
{
|
|||
n = huffr->read(1);
|
|||
block[bpos] = (block[bpos] > 0) ? n : -n;
|
|||
}
|
|||
}
|
|||
}
|
|||
// return eob
|
|||
return eob;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
progressive AC SA encoding routine
|
|||
----------------------------------------------- */
|
|||
int packJPG::jpg_encode_ac_prg_sa(
|
|||
BitWriter* huffw,
|
|||
std::vector<std::uint8_t>& storw,
|
|||
huffCodes* actbl,
|
|||
short* block,
|
|||
int* eobrun,
|
|||
int from,
|
|||
int to)
|
|||
{
|
|||
unsigned short n;
|
|||
unsigned char s;
|
|||
unsigned char z;
|
|||
int eob = from;
|
|||
int bpos;
|
|||
int hc;
|
|||
// check if block contains any newly nonzero coefficients and find out position of eob
|
|||
for (bpos = to; bpos >= from; bpos--)
|
|||
{
|
|||
if ((block[bpos] == 1) || (block[bpos] == -1))
|
|||
{
|
|||
eob = bpos + 1;
|
|||
break;
|
|||
}
|
|||
}
|
|||
// encode eobrun if needed
|
|||
if ((eob > from) && ((*eobrun) > 0))
|
|||
{
|
|||
jpg_encode_eobrun(huffw, actbl, eobrun);
|
|||
jpg_encode_crbits(huffw, storw);
|
|||
}
|
|||
// encode AC
|
|||
z = 0;
|
|||
for (bpos = from; bpos < eob; bpos++)
|
|||
{
|
|||
// if zero is encountered
|
|||
if (block[bpos] == 0)
|
|||
{
|
|||
z++; // increment zero counter
|
|||
if (z == 16) // write zeroes if needed
|
|||
{
|
|||
huffw->write_u16(actbl->cval[0xF0], actbl->clen[0xF0]);
|
|||
jpg_encode_crbits(huffw, storw);
|
|||
z = 0;
|
|||
}
|
|||
}
|
|||
// if nonzero is encountered
|
|||
else if ((block[bpos] == 1) || (block[bpos] == -1))
|
|||
{
|
|||
// vli encode
|
|||
s = BITLEN2048N(block[bpos]);
|
|||
n = ENVLI(s, block[bpos]);
|
|||
hc = ((z << 4) + s);
|
|||
// write to huffman writer
|
|||
huffw->write_u16(actbl->cval[hc], actbl->clen[hc]);
|
|||
huffw->write_u16(n, s);
|
|||
// write correction bits
|
|||
jpg_encode_crbits(huffw, storw);
|
|||
// reset zeroes
|
|||
z = 0;
|
|||
}
|
|||
else // store correction bits
|
|||
{
|
|||
n = block[bpos] & 0x1;
|
|||
storw.emplace_back(n);
|
|||
}
|
|||
}
|
|||
// fast processing after eob
|
|||
for (; bpos <= to; bpos++)
|
|||
{
|
|||
if (block[bpos] != 0) // store correction bits
|
|||
{
|
|||
n = block[bpos] & 0x1;
|
|||
storw.emplace_back(n);
|
|||
}
|
|||
}
|
|||
// check eob, increment eobrun if needed
|
|||
if (eob <= to)
|
|||
{
|
|||
(*eobrun)++;
|
|||
// check eobrun, encode if needed
|
|||
if ((*eobrun) == actbl->max_eobrun)
|
|||
{
|
|||
jpg_encode_eobrun(huffw, actbl, eobrun);
|
|||
jpg_encode_crbits(huffw, storw);
|
|||
}
|
|||
}
|
|||
// return eob
|
|||
return eob;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
run of EOB SA decoding routine
|
|||
----------------------------------------------- */
|
|||
int packJPG::jpg_decode_eobrun_sa(
|
|||
BitReader* huffr,
|
|||
short* block,
|
|||
int* eobrun,
|
|||
int from,
|
|||
int to)
|
|||
{
|
|||
unsigned short n;
|
|||
int bpos;
|
|||
// fast eobrun decoding routine for succesive approximation
|
|||
for (bpos = from; bpos <= to; bpos++)
|
|||
{
|
|||
if (block[bpos] != 0)
|
|||
{
|
|||
n = huffr->read(1);
|
|||
block[bpos] = (block[bpos] > 0) ? n : -n;
|
|||
}
|
|||
}
|
|||
return 0;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
run of EOB encoding routine
|
|||
----------------------------------------------- */
|
|||
int packJPG::jpg_encode_eobrun(
|
|||
BitWriter* huffw,
|
|||
huffCodes* actbl,
|
|||
int* eobrun)
|
|||
{
|
|||
unsigned short n;
|
|||
unsigned char s;
|
|||
int hc;
|
|||
if ((*eobrun) > 0)
|
|||
{
|
|||
while ((*eobrun) > actbl->max_eobrun)
|
|||
{
|
|||
huffw->write_u16(actbl->cval[0xE0], actbl->clen[0xE0]);
|
|||
huffw->write_u16(E_ENVLI(14, 32767), 14);
|
|||
(*eobrun) -= actbl->max_eobrun;
|
|||
}
|
|||
BITLEN(s, (*eobrun));
|
|||
s--;
|
|||
n = E_ENVLI(s, (*eobrun));
|
|||
hc = (s << 4);
|
|||
huffw->write_u16(actbl->cval[hc], actbl->clen[hc]);
|
|||
huffw->write_u16(n, s);
|
|||
(*eobrun) = 0;
|
|||
}
|
|||
return 0;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
correction bits encoding routine
|
|||
----------------------------------------------- */
|
|||
int packJPG::jpg_encode_crbits(
|
|||
BitWriter* huffw,
|
|||
std::vector<std::uint8_t>& storw)
|
|||
{
|
|||
for (const std::uint8_t bit : storw)
|
|||
{
|
|||
huffw->write_bit(bit);
|
|||
}
|
|||
storw.clear();
|
|||
return 0;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
returns next code (from huffman-tree & -data)
|
|||
----------------------------------------------- */
|
|||
int packJPG::jpg_next_huffcode(BitReader* huffw, huffTree* ctree)
|
|||
{
|
|||
int node = 0;
|
|||
while (node < 256)
|
|||
{
|
|||
node = (huffw->read(1) == 1) ? ctree->r[node] : ctree->l[node];
|
|||
if (node == 0)
|
|||
{
|
|||
break;
|
|||
}
|
|||
}
|
|||
return (node - 256);
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
calculates next position for MCU
|
|||
----------------------------------------------- */
|
|||
int packJPG::jpg_next_mcupos(
|
|||
int* mcu,
|
|||
int* cmp,
|
|||
int* csc,
|
|||
int* sub,
|
|||
int* dpos,
|
|||
int* rstw)
|
|||
{
|
|||
int sta = 0; // status
|
|||
// increment all counts where needed
|
|||
if ((++(*sub)) >= cmpnfo[(*cmp)].mbs)
|
|||
{
|
|||
(*sub) = 0;
|
|||
if ((++(*csc)) >= cs_cmpc)
|
|||
{
|
|||
(*csc) = 0;
|
|||
(*cmp) = cs_cmp[0];
|
|||
(*mcu)++;
|
|||
if ((*mcu) >= mcuc)
|
|||
{
|
|||
sta = 2;
|
|||
}
|
|||
else if (rsti > 0)
|
|||
if (--(*rstw) == 0)
|
|||
{
|
|||
sta = 1;
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
(*cmp) = cs_cmp[(*csc)];
|
|||
}
|
|||
}
|
|||
// get correct position in image ( x & y )
|
|||
if (cmpnfo[(*cmp)].sfh > 1) // to fix mcu order
|
|||
{
|
|||
(*dpos) = ((*mcu) / mcuh) * cmpnfo[(*cmp)].sfh + ((*sub) / cmpnfo[(*cmp)].sfv);
|
|||
(*dpos) *= cmpnfo[(*cmp)].bch;
|
|||
(*dpos) += ((*mcu) % mcuh) * cmpnfo[(*cmp)].sfv + ((*sub) % cmpnfo[(*cmp)].sfv);
|
|||
}
|
|||
else if (cmpnfo[(*cmp)].sfv > 1)
|
|||
{
|
|||
// simple calculation to speed up things if simple fixing is enough
|
|||
(*dpos) = ((*mcu) * cmpnfo[(*cmp)].mbs) + (*sub);
|
|||
}
|
|||
else
|
|||
{
|
|||
// no calculations needed without subsampling
|
|||
(*dpos) = (*mcu);
|
|||
}
|
|||
return sta;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
calculates next position (non interleaved)
|
|||
----------------------------------------------- */
|
|||
int packJPG::jpg_next_mcuposn(int* cmp, int* dpos, int* rstw)
|
|||
{
|
|||
// increment position
|
|||
(*dpos)++;
|
|||
// fix for non interleaved mcu - horizontal
|
|||
if (cmpnfo[(*cmp)].bch != cmpnfo[(*cmp)].nch)
|
|||
{
|
|||
if ((*dpos) % cmpnfo[(*cmp)].bch == cmpnfo[(*cmp)].nch)
|
|||
{
|
|||
(*dpos) += (cmpnfo[(*cmp)].bch - cmpnfo[(*cmp)].nch);
|
|||
}
|
|||
}
|
|||
// fix for non interleaved mcu - vertical
|
|||
if (cmpnfo[(*cmp)].bcv != cmpnfo[(*cmp)].ncv)
|
|||
{
|
|||
if ((*dpos) / cmpnfo[(*cmp)].bch == cmpnfo[(*cmp)].ncv)
|
|||
{
|
|||
(*dpos) = cmpnfo[(*cmp)].bc;
|
|||
}
|
|||
}
|
|||
// check position
|
|||
if ((*dpos) >= cmpnfo[(*cmp)].bc)
|
|||
{
|
|||
return 2;
|
|||
}
|
|||
else if (rsti > 0)
|
|||
if (--(*rstw) == 0)
|
|||
{
|
|||
return 1;
|
|||
}
|
|||
return 0;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
skips the eobrun, calculates next position
|
|||
----------------------------------------------- */
|
|||
int packJPG::jpg_skip_eobrun(int* cmp, int* dpos, int* rstw, int* eobrun)
|
|||
{
|
|||
if ((*eobrun) > 0) // error check for eobrun
|
|||
{
|
|||
// compare rst wait counter if needed
|
|||
if (rsti > 0)
|
|||
{
|
|||
if ((*eobrun) > (*rstw))
|
|||
{
|
|||
return -1;
|
|||
}
|
|||
else
|
|||
{
|
|||
(*rstw) -= (*eobrun);
|
|||
}
|
|||
}
|
|||
// fix for non interleaved mcu - horizontal
|
|||
if (cmpnfo[(*cmp)].bch != cmpnfo[(*cmp)].nch)
|
|||
{
|
|||
(*dpos) += ((((*dpos) % cmpnfo[(*cmp)].bch) + (*eobrun)) /
|
|||
cmpnfo[(*cmp)].nch) * (cmpnfo[(*cmp)].bch - cmpnfo[(*cmp)].nch);
|
|||
}
|
|||
// fix for non interleaved mcu - vertical
|
|||
if (cmpnfo[(*cmp)].bcv != cmpnfo[(*cmp)].ncv)
|
|||
{
|
|||
if ((*dpos) / cmpnfo[(*cmp)].bch >= cmpnfo[(*cmp)].ncv)
|
|||
(*dpos) += (cmpnfo[(*cmp)].bcv - cmpnfo[(*cmp)].ncv) *
|
|||
cmpnfo[(*cmp)].bch;
|
|||
}
|
|||
// skip blocks
|
|||
(*dpos) += (*eobrun);
|
|||
// reset eobrun
|
|||
(*eobrun) = 0;
|
|||
// check position
|
|||
if ((*dpos) == cmpnfo[(*cmp)].bc)
|
|||
{
|
|||
return 2;
|
|||
}
|
|||
else if ((*dpos) > cmpnfo[(*cmp)].bc)
|
|||
{
|
|||
return -1;
|
|||
}
|
|||
else if (rsti > 0)
|
|||
if ((*rstw) == 0)
|
|||
{
|
|||
return 1;
|
|||
}
|
|||
}
|
|||
return 0;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
creates huffman-codes & -trees from dht-data
|
|||
----------------------------------------------- */
|
|||
void packJPG::jpg_build_huffcodes(
|
|||
unsigned char* clen,
|
|||
unsigned char* cval,
|
|||
huffCodes* hc,
|
|||
huffTree* ht)
|
|||
{
|
|||
int nextfree;
|
|||
int code;
|
|||
int node;
|
|||
int i, j, k;
|
|||
// fill with zeroes
|
|||
memset(hc->clen, 0, 256 * sizeof(short));
|
|||
memset(hc->cval, 0, 256 * sizeof(short));
|
|||
memset(ht->l, 0, 256 * sizeof(short));
|
|||
memset(ht->r, 0, 256 * sizeof(short));
|
|||
// 1st part -> build huffman codes
|
|||
// creating huffman-codes
|
|||
k = 0;
|
|||
code = 0;
|
|||
// symbol-value of code is its position in the table
|
|||
for (i = 0; i < 16; i++)
|
|||
{
|
|||
for (j = 0; j < (int) clen[i]; j++)
|
|||
{
|
|||
hc->clen[(int) cval[k]] = 1 + i;
|
|||
hc->cval[(int) cval[k]] = code;
|
|||
k++;
|
|||
code++;
|
|||
}
|
|||
code = code << 1;
|
|||
}
|
|||
// find out eobrun max value
|
|||
hc->max_eobrun = 0;
|
|||
for (i = 14; i >= 0; i--)
|
|||
{
|
|||
if (hc->clen[i << 4] > 0)
|
|||
{
|
|||
hc->max_eobrun = (2 << i) - 1;
|
|||
break;
|
|||
}
|
|||
}
|
|||
// 2nd -> part use codes to build the coding tree
|
|||
// initial value for next free place
|
|||
nextfree = 1;
|
|||
// work through every code creating links between the nodes (represented through ints)
|
|||
for (i = 0; i < 256; i++)
|
|||
{
|
|||
// (re)set current node
|
|||
node = 0;
|
|||
// go through each code & store path
|
|||
for (j = hc->clen[i] - 1; j > 0; j--)
|
|||
{
|
|||
if (BITN(hc->cval[i], j) == 1)
|
|||
{
|
|||
if (ht->r[node] == 0)
|
|||
{
|
|||
ht->r[node] = nextfree++;
|
|||
}
|
|||
node = ht->r[node];
|
|||
}
|
|||
else
|
|||
{
|
|||
if (ht->l[node] == 0)
|
|||
{
|
|||
ht->l[node] = nextfree++;
|
|||
}
|
|||
node = ht->l[node];
|
|||
}
|
|||
}
|
|||
// last link is number of targetvalue + 256
|
|||
if (hc->clen[i] > 0)
|
|||
{
|
|||
if (BITN(hc->cval[i], 0) == 1)
|
|||
{
|
|||
ht->r[node] = i + 256;
|
|||
}
|
|||
else
|
|||
{
|
|||
ht->l[node] = i + 256;
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
/* ------------------- End of JPEG specific functions ---------------------- */
|
|||
/* ------------------- Begin PJG specific functions ------------------------ */
|
|||
/* -----------------------------------------------
|
|||
encodes frequency scanorder to pjg
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_encode_zstscan(ArithmeticEncoder* enc, int cmp)
|
|||
{
|
|||
model_s* model;
|
|||
unsigned char freqlist[64];
|
|||
int tpos; // true position
|
|||
int cpos; // coded position
|
|||
int c, i;
|
|||
// calculate zero sort scan
|
|||
pjg_get_zerosort_scan(zsrtscan[cmp], cmp);
|
|||
// preset freqlist
|
|||
for (i = 0; i < 64; i++)
|
|||
{
|
|||
freqlist[i] = stdscan[i];
|
|||
}
|
|||
// init model
|
|||
model = INIT_MODEL_S(64, 64, 1);
|
|||
// encode scanorder
|
|||
for (i = 1; i < 64; i++)
|
|||
{
|
|||
// reduce range of model
|
|||
model->exclude_symbols(64 - i);
|
|||
// compare remaining list to remainnig scan
|
|||
tpos = 0;
|
|||
for (c = i; c < 64; c++)
|
|||
{
|
|||
// search next val != 0 in list
|
|||
for (tpos++; freqlist[tpos] == 0; tpos++);
|
|||
// get out if not a match
|
|||
if (freqlist[tpos] != zsrtscan[cmp][c])
|
|||
{
|
|||
break;
|
|||
}
|
|||
}
|
|||
if (c == 64)
|
|||
{
|
|||
// remaining list is in sorted scanorder
|
|||
// encode zero and make a quick exit
|
|||
encode_ari(enc, model, 0);
|
|||
break;
|
|||
}
|
|||
// list is not in sorted order -> next pos hat to be encoded
|
|||
cpos = 1;
|
|||
// encode position
|
|||
for (tpos = 0; freqlist[tpos] != zsrtscan[cmp][i]; tpos++)
|
|||
{
|
|||
if (freqlist[tpos] != 0)
|
|||
{
|
|||
cpos++;
|
|||
}
|
|||
}
|
|||
// remove from list
|
|||
freqlist[tpos] = 0;
|
|||
// encode coded position in list
|
|||
encode_ari(enc, model, cpos);
|
|||
model->shift_context(cpos);
|
|||
}
|
|||
// delete model
|
|||
delete model;
|
|||
// set zero sort scan as freqscan
|
|||
freqscan[cmp] = zsrtscan[cmp];
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
encodes # of non zeroes to pjg (high)
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_encode_zdst_high(ArithmeticEncoder* enc, int cmp)
|
|||
{
|
|||
model_s* model;
|
|||
unsigned char* zdstls;
|
|||
int dpos;
|
|||
int a, b;
|
|||
int bc;
|
|||
int w;
|
|||
// init model, constants
|
|||
model = INIT_MODEL_S(49 + 1, 25 + 1, 1);
|
|||
zdstls = zdstdata[cmp];
|
|||
w = cmpnfo[cmp].bch;
|
|||
bc = cmpnfo[cmp].bc;
|
|||
// arithmetic encode zero-distribution-list
|
|||
for (dpos = 0; dpos < bc; dpos++)
|
|||
{
|
|||
// context modelling - use average of above and left as context
|
|||
get_context_nnb(dpos, w, &a, &b);
|
|||
a = (a >= 0) ? zdstls[a] : 0;
|
|||
b = (b >= 0) ? zdstls[b] : 0;
|
|||
// shift context
|
|||
model->shift_context((a + b + 2) / 4);
|
|||
// encode symbol
|
|||
encode_ari(enc, model, zdstls[dpos]);
|
|||
}
|
|||
// clean up
|
|||
delete model;
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
encodes # of non zeroes to pjg (low)
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_encode_zdst_low(ArithmeticEncoder* enc, int cmp)
|
|||
{
|
|||
model_s* model;
|
|||
unsigned char* zdstls_x;
|
|||
unsigned char* zdstls_y;
|
|||
unsigned char* ctx_zdst;
|
|||
unsigned char* ctx_eobx;
|
|||
unsigned char* ctx_eoby;
|
|||
int dpos;
|
|||
int bc;
|
|||
// init model, constants
|
|||
model = INIT_MODEL_S(8, 8, 2);
|
|||
zdstls_x = zdstxlow[cmp];
|
|||
zdstls_y = zdstylow[cmp];
|
|||
ctx_eobx = eobxhigh[cmp];
|
|||
ctx_eoby = eobyhigh[cmp];
|
|||
ctx_zdst = zdstdata[cmp];
|
|||
bc = cmpnfo[cmp].bc;
|
|||
// arithmetic encode zero-distribution-list (first row)
|
|||
for (dpos = 0; dpos < bc; dpos++)
|
|||
{
|
|||
model->shift_context((ctx_zdst[dpos] + 3) / 7); // shift context
|
|||
model->shift_context(ctx_eobx[dpos]); // shift context
|
|||
encode_ari(enc, model, zdstls_x[dpos]); // encode symbol
|
|||
}
|
|||
// arithmetic encode zero-distribution-list (first collumn)
|
|||
for (dpos = 0; dpos < bc; dpos++)
|
|||
{
|
|||
model->shift_context((ctx_zdst[dpos] + 3) / 7); // shift context
|
|||
model->shift_context(ctx_eoby[dpos]); // shift context
|
|||
encode_ari(enc, model, zdstls_y[dpos]); // encode symbol
|
|||
}
|
|||
// clean up
|
|||
delete model;
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
encodes DC coefficients to pjg
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_encode_dc(ArithmeticEncoder* enc, int cmp)
|
|||
{
|
|||
unsigned char* segm_tab;
|
|||
model_s* mod_len;
|
|||
model_b* mod_sgn;
|
|||
model_b* mod_res;
|
|||
unsigned char* zdstls; // pointer to zero distribution list
|
|||
signed short* coeffs; // pointer to current coefficent data
|
|||
unsigned short* absv_store; // absolute coefficients values storage
|
|||
unsigned short* c_absc[6]; // quick access array for contexts
|
|||
int c_weight[6]; // weighting for contexts
|
|||
int ctx_avr; // 'average' context
|
|||
int ctx_len; // context for bit length
|
|||
int max_val; // max value
|
|||
int max_len; // max bitlength
|
|||
int dpos;
|
|||
int clen, absv, sgn;
|
|||
int snum;
|
|||
int bt, bp;
|
|||
int p_x, p_y;
|
|||
int r_x; //, r_y;
|
|||
int w, bc;
|
|||
// decide segmentation setting
|
|||
segm_tab = segm_tables[segm_cnt[cmp] - 1];
|
|||
// get max absolute value/bit length
|
|||
max_val = MAX_V(cmp, 0);
|
|||
max_len = BITLEN1024P(max_val);
|
|||
// init models for bitlenghts and -patterns
|
|||
mod_len = INIT_MODEL_S(max_len + 1, (segm_cnt[cmp] > max_len) ? segm_cnt[cmp] : max_len + 1, 2);
|
|||
mod_res = INIT_MODEL_B((segm_cnt[cmp] < 16) ? 1 << 4 : segm_cnt[cmp], 2);
|
|||
mod_sgn = INIT_MODEL_B(1, 0);
|
|||
// set width/height of each band
|
|||
bc = cmpnfo[cmp].bc;
|
|||
w = cmpnfo[cmp].bch;
|
|||
// allocate memory for absolute values storage
|
|||
absv_store = (unsigned short*) calloc(bc, sizeof(short));
|
|||
if (absv_store == nullptr)
|
|||
{
|
|||
sprintf(errormessage, MEM_ERRMSG);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
// set up context quick access array
|
|||
pjg_aavrg_prepare(c_absc, c_weight, absv_store, cmp);
|
|||
// locally store pointer to coefficients and zero distribution list
|
|||
coeffs = colldata[cmp][0];
|
|||
zdstls = zdstdata[cmp];
|
|||
// arithmetic compression loop
|
|||
for (dpos = 0; dpos < bc; dpos++)
|
|||
{
|
|||
//calculate x/y positions in band
|
|||
p_y = dpos / w;
|
|||
// r_y = h - ( p_y + 1 );
|
|||
p_x = dpos % w;
|
|||
r_x = w - (p_x + 1);
|
|||
// get segment-number from zero distribution list and segmentation set
|
|||
snum = segm_tab[zdstls[dpos]];
|
|||
// calculate contexts (for bit length)
|
|||
ctx_avr = pjg_aavrg_context(c_absc, c_weight, dpos, p_y, p_x, r_x); // AVERAGE context
|
|||
ctx_len = BITLEN1024P(ctx_avr); // BITLENGTH context
|
|||
// shift context / do context modelling (segmentation is done per context)
|
|||
shift_model(mod_len, ctx_len, snum);
|
|||
// simple treatment if coefficient is zero
|
|||
if (coeffs[dpos] == 0)
|
|||
{
|
|||
// encode bit length (0) of current coefficient
|
|||
encode_ari(enc, mod_len, 0);
|
|||
}
|
|||
else
|
|||
{
|
|||
// get absolute val, sign & bit length for current coefficient
|
|||
absv = ABS(coeffs[dpos]);
|
|||
clen = BITLEN1024P(absv);
|
|||
sgn = (coeffs[dpos] > 0) ? 0 : 1;
|
|||
// encode bit length of current coefficient
|
|||
encode_ari(enc, mod_len, clen);
|
|||
// encoding of residual
|
|||
// first set bit must be 1, so we start at clen - 2
|
|||
for (bp = clen - 2; bp >= 0; bp--)
|
|||
{
|
|||
shift_model(mod_res, snum, bp); // shift in 2 contexts
|
|||
// encode/get bit
|
|||
bt = BITN(absv, bp);
|
|||
encode_ari(enc, mod_res, bt);
|
|||
}
|
|||
// encode sign
|
|||
encode_ari(enc, mod_sgn, sgn);
|
|||
// store absolute value
|
|||
absv_store[dpos] = absv;
|
|||
}
|
|||
}
|
|||
// free memory / clear models
|
|||
free(absv_store);
|
|||
delete mod_len;
|
|||
delete mod_res;
|
|||
delete mod_sgn;
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
encodes high (7x7) AC coefficients to pjg
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_encode_ac_high(ArithmeticEncoder* enc, int cmp)
|
|||
{
|
|||
unsigned char* segm_tab;
|
|||
model_s* mod_len;
|
|||
model_b* mod_sgn;
|
|||
model_b* mod_res;
|
|||
unsigned char* zdstls; // pointer to zero distribution list
|
|||
unsigned char* eob_x; // pointer to x eobs
|
|||
unsigned char* eob_y; // pointer to y eobs
|
|||
signed short* coeffs; // pointer to current coefficent data
|
|||
unsigned short* absv_store; // absolute coefficients values storage
|
|||
unsigned short* c_absc[6]; // quick access array for contexts
|
|||
int c_weight[6]; // weighting for contexts
|
|||
unsigned char* sgn_store; // sign storage for context
|
|||
unsigned char* sgn_nbh; // left signs neighbor
|
|||
unsigned char* sgn_nbv; // upper signs neighbor
|
|||
int ctx_avr; // 'average' context
|
|||
int ctx_len; // context for bit length
|
|||
int ctx_sgn; // context for sign
|
|||
int max_val; // max value
|
|||
int max_len; // max bitlength
|
|||
int bpos, dpos;
|
|||
int clen, absv, sgn;
|
|||
int snum;
|
|||
int bt, bp;
|
|||
int i;
|
|||
int b_x, b_y;
|
|||
int p_x, p_y;
|
|||
int r_x; //, r_y;
|
|||
int w, bc;
|
|||
// decide segmentation setting
|
|||
segm_tab = segm_tables[segm_cnt[cmp] - 1];
|
|||
// init models for bitlenghts and -patterns
|
|||
mod_len = INIT_MODEL_S(11, (segm_cnt[cmp] > 11) ? segm_cnt[cmp] : 11, 2);
|
|||
mod_res = INIT_MODEL_B((segm_cnt[cmp] < 16) ? 1 << 4 : segm_cnt[cmp], 2);
|
|||
mod_sgn = INIT_MODEL_B(9, 1);
|
|||
// set width/height of each band
|
|||
bc = cmpnfo[cmp].bc;
|
|||
w = cmpnfo[cmp].bch;
|
|||
// allocate memory for absolute values & signs storage
|
|||
absv_store = (unsigned short*) calloc(bc, sizeof(short));
|
|||
sgn_store = (unsigned char*) calloc(bc, sizeof(char));
|
|||
zdstls = (unsigned char*) calloc(bc, sizeof(char));
|
|||
if ((absv_store == nullptr) || (sgn_store == nullptr) || (zdstls == nullptr))
|
|||
{
|
|||
if (absv_store != nullptr)
|
|||
{
|
|||
free(absv_store);
|
|||
}
|
|||
if (sgn_store != nullptr)
|
|||
{
|
|||
free(sgn_store);
|
|||
}
|
|||
if (zdstls != nullptr)
|
|||
{
|
|||
free(zdstls);
|
|||
}
|
|||
sprintf(errormessage, MEM_ERRMSG);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
// set up quick access arrays for signs context
|
|||
sgn_nbh = sgn_store - 1;
|
|||
sgn_nbv = sgn_store - w;
|
|||
// locally store pointer to eob x / eob y
|
|||
eob_x = eobxhigh[cmp];
|
|||
eob_y = eobyhigh[cmp];
|
|||
// preset x/y eobs
|
|||
memset(eob_x, 0x00, bc * sizeof(char));
|
|||
memset(eob_y, 0x00, bc * sizeof(char));
|
|||
// make a local copy of the zero distribution list
|
|||
for (dpos = 0; dpos < bc; dpos++)
|
|||
{
|
|||
zdstls[dpos] = zdstdata[cmp][dpos];
|
|||
}
|
|||
// work through lower 7x7 bands in order of freqscan
|
|||
for (i = 1; i < 64; i++)
|
|||
{
|
|||
// work through blocks in order of frequency scan
|
|||
bpos = (int) freqscan[cmp][i];
|
|||
b_x = unzigzag[bpos] % 8;
|
|||
b_y = unzigzag[bpos] / 8;
|
|||
if ((b_x == 0) || (b_y == 0))
|
|||
{
|
|||
continue; // process remaining coefficients elsewhere
|
|||
}
|
|||
// preset absolute values/sign storage
|
|||
memset(absv_store, 0x00, bc * sizeof(short));
|
|||
memset(sgn_store, 0x00, bc * sizeof(char));
|
|||
// set up average context quick access arrays
|
|||
pjg_aavrg_prepare(c_absc, c_weight, absv_store, cmp);
|
|||
// locally store pointer to coefficients
|
|||
coeffs = colldata[cmp][bpos];
|
|||
// get max bit length
|
|||
max_val = MAX_V(cmp, bpos);
|
|||
max_len = BITLEN1024P(max_val);
|
|||
// arithmetic compression loo
|
|||
for (dpos = 0; dpos < bc; dpos++)
|
|||
{
|
|||
// skip if beyound eob
|
|||
if (zdstls[dpos] == 0)
|
|||
{
|
|||
continue;
|
|||
}
|
|||
//calculate x/y positions in band
|
|||
p_y = dpos / w;
|
|||
// r_y = h - ( p_y + 1 );
|
|||
p_x = dpos % w;
|
|||
r_x = w - (p_x + 1);
|
|||
// get segment-number from zero distribution list and segmentation set
|
|||
snum = segm_tab[zdstls[dpos]];
|
|||
// calculate contexts (for bit length)
|
|||
ctx_avr = pjg_aavrg_context(c_absc, c_weight, dpos, p_y, p_x, r_x); // AVERAGE context
|
|||
ctx_len = BITLEN1024P(ctx_avr); // BITLENGTH context
|
|||
// shift context / do context modelling (segmentation is done per context)
|
|||
shift_model(mod_len, ctx_len, snum);
|
|||
mod_len->exclude_symbols(max_len);
|
|||
// simple treatment if coefficient is zero
|
|||
if (coeffs[dpos] == 0)
|
|||
{
|
|||
// encode bit length (0) of current coefficien
|
|||
encode_ari(enc, mod_len, 0);
|
|||
}
|
|||
else
|
|||
{
|
|||
// get absolute val, sign & bit length for current coefficient
|
|||
absv = ABS(coeffs[dpos]);
|
|||
clen = BITLEN1024P(absv);
|
|||
sgn = (coeffs[dpos] > 0) ? 0 : 1;
|
|||
// encode bit length of current coefficient
|
|||
encode_ari(enc, mod_len, clen);
|
|||
// encoding of residual
|
|||
// first set bit must be 1, so we start at clen - 2
|
|||
for (bp = clen - 2; bp >= 0; bp--)
|
|||
{
|
|||
shift_model(mod_res, snum, bp); // shift in 2 contexts
|
|||
// encode/get bit
|
|||
bt = BITN(absv, bp);
|
|||
encode_ari(enc, mod_res, bt);
|
|||
}
|
|||
// encode sign
|
|||
ctx_sgn = (p_x > 0) ? sgn_nbh[dpos] : 0; // sign context
|
|||
if (p_y > 0)
|
|||
{
|
|||
ctx_sgn += 3 * sgn_nbv[dpos]; // IMPROVE !!!!!!!!!!!
|
|||
}
|
|||
mod_sgn->shift_context(ctx_sgn);
|
|||
encode_ari(enc, mod_sgn, sgn);
|
|||
// store absolute value/sign, decrement zdst
|
|||
absv_store[dpos] = absv;
|
|||
sgn_store[dpos] = sgn + 1;
|
|||
zdstls[dpos]--;
|
|||
// recalculate x/y eob
|
|||
if (b_x > eob_x[dpos])
|
|||
{
|
|||
eob_x[dpos] = b_x;
|
|||
}
|
|||
if (b_y > eob_y[dpos])
|
|||
{
|
|||
eob_y[dpos] = b_y;
|
|||
}
|
|||
}
|
|||
}
|
|||
// flush models
|
|||
mod_len->flush_model();
|
|||
mod_res->flush_model();
|
|||
mod_sgn->flush_model();
|
|||
}
|
|||
// free memory / clear models
|
|||
free(absv_store);
|
|||
free(sgn_store);
|
|||
free(zdstls);
|
|||
delete mod_len;
|
|||
delete mod_res;
|
|||
delete mod_sgn;
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
encodes first row/col AC coefficients to pjg
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_encode_ac_low(ArithmeticEncoder* enc, int cmp)
|
|||
{
|
|||
model_s* mod_len;
|
|||
model_b* mod_sgn;
|
|||
model_b* mod_res;
|
|||
model_b* mod_top;
|
|||
unsigned char* zdstls; // pointer to row/col # of non-zeroes
|
|||
signed short* coeffs; // pointer to current coefficent data
|
|||
signed short* coeffs_x[8]; // prediction coeffs - current block
|
|||
signed short* coeffs_a[8]; // prediction coeffs - neighboring block
|
|||
int pred_cf[8]; // prediction multipliers
|
|||
int ctx_lak; // lakhani context
|
|||
int ctx_abs; // absolute context
|
|||
int ctx_len; // context for bit length
|
|||
int ctx_res; // bit plane context for residual
|
|||
int ctx_sgn; // context for sign
|
|||
int max_valp; // max value (+)
|
|||
int max_valn; // max value (-)
|
|||
int max_len; // max bitlength
|
|||
int thrs_bp; // residual threshold bitplane
|
|||
int* edge_c; // edge criteria
|
|||
int bpos, dpos;
|
|||
int clen, absv, sgn;
|
|||
int bt, bp;
|
|||
int i;
|
|||
int b_x, b_y;
|
|||
int p_x, p_y;
|
|||
int w, bc;
|
|||
// init models for bitlenghts and -patterns
|
|||
mod_len = INIT_MODEL_S(11, (segm_cnt[cmp] > 11) ? segm_cnt[cmp] : 11, 2);
|
|||
mod_res = INIT_MODEL_B(1 << 4, 2);
|
|||
mod_top = INIT_MODEL_B((nois_trs[cmp] > 4) ? 1 << nois_trs[cmp] : 1 << 4, 3);
|
|||
mod_sgn = INIT_MODEL_B(11, 1);
|
|||
// set width/height of each band
|
|||
bc = cmpnfo[cmp].bc;
|
|||
w = cmpnfo[cmp].bch;
|
|||
// work through each first row / first collumn band
|
|||
for (i = 2; i < 16; i++)
|
|||
{
|
|||
// alternate between first row and first collumn
|
|||
b_x = (i % 2 == 0) ? i / 2 : 0;
|
|||
b_y = (i % 2 == 1) ? i / 2 : 0;
|
|||
bpos = (int) zigzag[b_x + (8*b_y)];
|
|||
// locally store pointer to band coefficients
|
|||
coeffs = colldata[cmp][bpos];
|
|||
// store pointers to prediction coefficients
|
|||
if (b_x == 0)
|
|||
{
|
|||
for (; b_x < 8; b_x++)
|
|||
{
|
|||
coeffs_x[b_x] = colldata[cmp][zigzag[b_x+(8*b_y)]];
|
|||
coeffs_a[b_x] = colldata[cmp][zigzag[b_x+(8*b_y)]] - 1;
|
|||
pred_cf[b_x] = icos_base_8x8[b_x * 8] * QUANT(cmp, zigzag[b_x+(8*b_y)]);
|
|||
}
|
|||
b_x = 0;
|
|||
zdstls = zdstylow[cmp];
|
|||
edge_c = &p_x;
|
|||
}
|
|||
else // if ( b_y == 0 )
|
|||
{
|
|||
for (; b_y < 8; b_y++)
|
|||
{
|
|||
coeffs_x[b_y] = colldata[cmp][zigzag[b_x+(8*b_y)]];
|
|||
coeffs_a[b_y] = colldata[cmp][zigzag[b_x+(8*b_y)]] - w;
|
|||
pred_cf[b_y] = icos_base_8x8[b_y * 8] * QUANT(cmp, zigzag[b_x+(8*b_y)]);
|
|||
}
|
|||
b_y = 0;
|
|||
zdstls = zdstxlow[cmp];
|
|||
edge_c = &p_y;
|
|||
}
|
|||
// get max bit length / other info
|
|||
max_valp = MAX_V(cmp, bpos);
|
|||
max_valn = -max_valp;
|
|||
max_len = BITLEN1024P(max_valp);
|
|||
thrs_bp = (max_len > nois_trs[cmp]) ? max_len - nois_trs[cmp] : 0;
|
|||
// arithmetic compression loop
|
|||
for (dpos = 0; dpos < bc; dpos++)
|
|||
{
|
|||
// skip if beyound eob
|
|||
if (zdstls[dpos] == 0)
|
|||
{
|
|||
continue;
|
|||
}
|
|||
// calculate x/y positions in band
|
|||
p_y = dpos / w;
|
|||
p_x = dpos % w;
|
|||
// edge treatment / calculate LAKHANI context
|
|||
if ((*edge_c) > 0)
|
|||
{
|
|||
ctx_lak = pjg_lakh_context(coeffs_x, coeffs_a, pred_cf, dpos);
|
|||
}
|
|||
else
|
|||
{
|
|||
ctx_lak = 0;
|
|||
}
|
|||
ctx_lak = CLAMPED(max_valn, max_valp, ctx_lak);
|
|||
ctx_len = BITLEN2048N(ctx_lak); // BITLENGTH context
|
|||
// shift context / do context modelling (segmentation is done per context)
|
|||
shift_model(mod_len, ctx_len, zdstls[dpos]);
|
|||
mod_len->exclude_symbols(max_len);
|
|||
// simple treatment if coefficient is zero
|
|||
if (coeffs[dpos] == 0)
|
|||
{
|
|||
// encode bit length (0) of current coefficient
|
|||
encode_ari(enc, mod_len, 0);
|
|||
}
|
|||
else
|
|||
{
|
|||
// get absolute val, sign & bit length for current coefficient
|
|||
absv = ABS(coeffs[dpos]);
|
|||
clen = BITLEN2048N(absv);
|
|||
sgn = (coeffs[dpos] > 0) ? 0 : 1;
|
|||
// encode bit length of current coefficient
|
|||
encode_ari(enc, mod_len, clen);
|
|||
// encoding of residual
|
|||
bp = clen - 2; // first set bit must be 1, so we start at clen - 2
|
|||
ctx_res = (bp >= thrs_bp) ? 1 : 0;
|
|||
ctx_abs = ABS(ctx_lak);
|
|||
ctx_sgn = (ctx_lak == 0) ? 0 : (ctx_lak > 0) ? 1 : 2;
|
|||
for (; bp >= thrs_bp; bp--)
|
|||
{
|
|||
shift_model(mod_top, ctx_abs >> thrs_bp, ctx_res, clen - thrs_bp); // shift in 3 contexts
|
|||
// encode/get bit
|
|||
bt = BITN(absv, bp);
|
|||
encode_ari(enc, mod_top, bt);
|
|||
// update context
|
|||
ctx_res = ctx_res << 1;
|
|||
if (bt)
|
|||
{
|
|||
ctx_res |= 1;
|
|||
}
|
|||
}
|
|||
for (; bp >= 0; bp--)
|
|||
{
|
|||
shift_model(mod_res, zdstls[dpos], bp); // shift in 2 contexts
|
|||
// encode/get bit
|
|||
bt = BITN(absv, bp);
|
|||
encode_ari(enc, mod_res, bt);
|
|||
}
|
|||
// encode sign
|
|||
shift_model(mod_sgn, ctx_len, ctx_sgn);
|
|||
encode_ari(enc, mod_sgn, sgn);
|
|||
// decrement # of non zeroes
|
|||
zdstls[dpos]--;
|
|||
}
|
|||
}
|
|||
// flush models
|
|||
mod_len->flush_model();
|
|||
mod_res->flush_model();
|
|||
mod_top->flush_model();
|
|||
mod_sgn->flush_model();
|
|||
}
|
|||
// free memory / clear models
|
|||
delete mod_len;
|
|||
delete mod_res;
|
|||
delete mod_top;
|
|||
delete mod_sgn;
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
encodes a stream of generic (8bit) data to pjg
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_encode_generic(
|
|||
ArithmeticEncoder* enc,
|
|||
unsigned char* data,
|
|||
int len)
|
|||
{
|
|||
model_s* model;
|
|||
int i;
|
|||
// arithmetic encode data
|
|||
model = INIT_MODEL_S(256 + 1, 256, 1);
|
|||
for (i = 0; i < len; i++)
|
|||
{
|
|||
encode_ari(enc, model, data[i]);
|
|||
model->shift_context(data[i]);
|
|||
}
|
|||
// encode end-of-data symbol (256)
|
|||
encode_ari(enc, model, 256);
|
|||
delete model;
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
encodes one bit to pjg
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_encode_bit(ArithmeticEncoder* enc, unsigned char bit)
|
|||
{
|
|||
model_b* model;
|
|||
// encode one bit
|
|||
model = INIT_MODEL_B(1, -1);
|
|||
encode_ari(enc, model, bit);
|
|||
delete model;
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
encodes frequency scanorder to pjg
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_decode_zstscan(ArithmeticDecoder* dec, int cmp)
|
|||
{
|
|||
model_s* model;;
|
|||
unsigned char freqlist[64];
|
|||
int tpos; // true position
|
|||
int cpos; // coded position
|
|||
int i;
|
|||
// set first position in zero sort scan
|
|||
zsrtscan[cmp][0] = 0;
|
|||
// preset freqlist
|
|||
for (i = 0; i < 64; i++)
|
|||
{
|
|||
freqlist[i] = stdscan[i];
|
|||
}
|
|||
// init model
|
|||
model = INIT_MODEL_S(64, 64, 1);
|
|||
// encode scanorder
|
|||
for (i = 1; i < 64; i++)
|
|||
{
|
|||
// reduce range of model
|
|||
model->exclude_symbols(64 - i);
|
|||
// decode symbol
|
|||
cpos = decode_ari(dec, model);
|
|||
model->shift_context(cpos);
|
|||
if (cpos == 0)
|
|||
{
|
|||
// remaining list is identical to scan
|
|||
// fill the scan & make a quick exit
|
|||
for (tpos = 0; i < 64; i++)
|
|||
{
|
|||
while (freqlist[++tpos] == 0);
|
|||
zsrtscan[cmp][i] = freqlist[tpos];
|
|||
}
|
|||
break;
|
|||
}
|
|||
// decode position from list
|
|||
for (tpos = 0; tpos < 64; tpos++)
|
|||
{
|
|||
if (freqlist[tpos] != 0)
|
|||
{
|
|||
cpos--;
|
|||
}
|
|||
if (cpos == 0)
|
|||
{
|
|||
break;
|
|||
}
|
|||
}
|
|||
// write decoded position to zero sort scan
|
|||
zsrtscan[cmp][i] = freqlist[tpos];
|
|||
// remove from list
|
|||
freqlist[tpos] = 0;
|
|||
}
|
|||
// delete model
|
|||
delete model;
|
|||
// set zero sort scan as freqscan
|
|||
freqscan[cmp] = zsrtscan[cmp];
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
decodes # of non zeroes from pjg (high)
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_decode_zdst_high(ArithmeticDecoder* dec, int cmp)
|
|||
{
|
|||
model_s* model;
|
|||
unsigned char* zdstls;
|
|||
int dpos;
|
|||
int a, b;
|
|||
int bc;
|
|||
int w;
|
|||
// init model, constants
|
|||
model = INIT_MODEL_S(49 + 1, 25 + 1, 1);
|
|||
zdstls = zdstdata[cmp];
|
|||
w = cmpnfo[cmp].bch;
|
|||
bc = cmpnfo[cmp].bc;
|
|||
// arithmetic decode zero-distribution-list
|
|||
for (dpos = 0; dpos < bc; dpos++)
|
|||
{
|
|||
// context modelling - use average of above and left as context
|
|||
get_context_nnb(dpos, w, &a, &b);
|
|||
a = (a >= 0) ? zdstls[a] : 0;
|
|||
b = (b >= 0) ? zdstls[b] : 0;
|
|||
// shift context
|
|||
model->shift_context((a + b + 2) / 4);
|
|||
// decode symbol
|
|||
zdstls[dpos] = decode_ari(dec, model);
|
|||
}
|
|||
// clean up
|
|||
delete model;
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
decodes # of non zeroes from pjg (low)
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_decode_zdst_low(ArithmeticDecoder* dec, int cmp)
|
|||
{
|
|||
model_s* model;
|
|||
unsigned char* zdstls_x;
|
|||
unsigned char* zdstls_y;
|
|||
unsigned char* ctx_zdst;
|
|||
unsigned char* ctx_eobx;
|
|||
unsigned char* ctx_eoby;
|
|||
int dpos;
|
|||
int bc;
|
|||
// init model, constants
|
|||
model = INIT_MODEL_S(8, 8, 2);
|
|||
zdstls_x = zdstxlow[cmp];
|
|||
zdstls_y = zdstylow[cmp];
|
|||
ctx_eobx = eobxhigh[cmp];
|
|||
ctx_eoby = eobyhigh[cmp];
|
|||
ctx_zdst = zdstdata[cmp];
|
|||
bc = cmpnfo[cmp].bc;
|
|||
// arithmetic encode zero-distribution-list (first row)
|
|||
for (dpos = 0; dpos < bc; dpos++)
|
|||
{
|
|||
model->shift_context((ctx_zdst[dpos] + 3) / 7); // shift context
|
|||
model->shift_context(ctx_eobx[dpos]); // shift context
|
|||
zdstls_x[dpos] = decode_ari(dec, model); // decode symbol
|
|||
}
|
|||
// arithmetic encode zero-distribution-list (first collumn)
|
|||
for (dpos = 0; dpos < bc; dpos++)
|
|||
{
|
|||
model->shift_context((ctx_zdst[dpos] + 3) / 7); // shift context
|
|||
model->shift_context(ctx_eoby[dpos]); // shift context
|
|||
zdstls_y[dpos] = decode_ari(dec, model); // decode symbol
|
|||
}
|
|||
// clean up
|
|||
delete model;
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
decodes DC coefficients from pjg
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_decode_dc(ArithmeticDecoder* dec, int cmp)
|
|||
{
|
|||
unsigned char* segm_tab;
|
|||
model_s* mod_len;
|
|||
model_b* mod_sgn;
|
|||
model_b* mod_res;
|
|||
unsigned char* zdstls; // pointer to zero distribution list
|
|||
signed short* coeffs; // pointer to current coefficent data
|
|||
unsigned short* absv_store; // absolute coefficients values storage
|
|||
unsigned short* c_absc[6]; // quick access array for contexts
|
|||
int c_weight[6]; // weighting for contexts
|
|||
int ctx_avr; // 'average' context
|
|||
int ctx_len; // context for bit length
|
|||
int max_val; // max value
|
|||
int max_len; // max bitlength
|
|||
int dpos;
|
|||
int clen, absv, sgn;
|
|||
int snum;
|
|||
int bt, bp;
|
|||
int p_x, p_y;
|
|||
int r_x; //, r_y;
|
|||
int w, bc;
|
|||
// decide segmentation setting
|
|||
segm_tab = segm_tables[segm_cnt[cmp] - 1];
|
|||
// get max absolute value/bit length
|
|||
max_val = MAX_V(cmp, 0);
|
|||
max_len = BITLEN1024P(max_val);
|
|||
// init models for bitlenghts and -patterns
|
|||
mod_len = INIT_MODEL_S(max_len + 1, (segm_cnt[cmp] > max_len) ? segm_cnt[cmp] : max_len + 1, 2);
|
|||
mod_res = INIT_MODEL_B((segm_cnt[cmp] < 16) ? 1 << 4 : segm_cnt[cmp], 2);
|
|||
mod_sgn = INIT_MODEL_B(1, 0);
|
|||
// set width/height of each band
|
|||
bc = cmpnfo[cmp].bc;
|
|||
w = cmpnfo[cmp].bch;
|
|||
// allocate memory for absolute values storage
|
|||
absv_store = (unsigned short*) calloc(bc, sizeof(short));
|
|||
if (absv_store == nullptr)
|
|||
{
|
|||
sprintf(errormessage, MEM_ERRMSG);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
// set up context quick access array
|
|||
pjg_aavrg_prepare(c_absc, c_weight, absv_store, cmp);
|
|||
// locally store pointer to coefficients and zero distribution list
|
|||
coeffs = colldata[cmp][0];
|
|||
zdstls = zdstdata[cmp];
|
|||
// arithmetic compression loop
|
|||
for (dpos = 0; dpos < bc; dpos++)
|
|||
{
|
|||
//calculate x/y positions in band
|
|||
p_y = dpos / w;
|
|||
// r_y = h - ( p_y + 1 );
|
|||
p_x = dpos % w;
|
|||
r_x = w - (p_x + 1);
|
|||
// get segment-number from zero distribution list and segmentation set
|
|||
snum = segm_tab[zdstls[dpos]];
|
|||
// calculate contexts (for bit length)
|
|||
ctx_avr = pjg_aavrg_context(c_absc, c_weight, dpos, p_y, p_x, r_x); // AVERAGE context
|
|||
ctx_len = BITLEN1024P(ctx_avr); // BITLENGTH context
|
|||
// shift context / do context modelling (segmentation is done per context)
|
|||
shift_model(mod_len, ctx_len, snum);
|
|||
// decode bit length of current coefficient
|
|||
clen = decode_ari(dec, mod_len);
|
|||
// simple treatment if coefficient is zero
|
|||
if (clen == 0)
|
|||
{
|
|||
// coeffs[dpos] = 0;
|
|||
}
|
|||
else
|
|||
{
|
|||
// decoding of residual
|
|||
absv = 1;
|
|||
// first set bit must be 1, so we start at clen - 2
|
|||
for (bp = clen - 2; bp >= 0; bp--)
|
|||
{
|
|||
shift_model(mod_res, snum, bp); // shift in 2 contexts
|
|||
// decode bit
|
|||
bt = decode_ari(dec, mod_res);
|
|||
// update absv
|
|||
absv = absv << 1;
|
|||
if (bt)
|
|||
{
|
|||
absv |= 1;
|
|||
}
|
|||
}
|
|||
// decode sign
|
|||
sgn = decode_ari(dec, mod_sgn);
|
|||
// copy to colldata
|
|||
coeffs[dpos] = (sgn == 0) ? absv : -absv;
|
|||
// store absolute value/sign
|
|||
absv_store[dpos] = absv;
|
|||
}
|
|||
}
|
|||
// free memory / clear models
|
|||
free(absv_store);
|
|||
delete mod_len;
|
|||
delete mod_res;
|
|||
delete mod_sgn;
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
decodes high (7x7) AC coefficients to pjg
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_decode_ac_high(ArithmeticDecoder* dec, int cmp)
|
|||
{
|
|||
unsigned char* segm_tab;
|
|||
model_s* mod_len;
|
|||
model_b* mod_sgn;
|
|||
model_b* mod_res;
|
|||
unsigned char* zdstls; // pointer to zero distribution list
|
|||
unsigned char* eob_x; // pointer to x eobs
|
|||
unsigned char* eob_y; // pointer to y eobs
|
|||
signed short* coeffs; // pointer to current coefficent data
|
|||
unsigned short* absv_store; // absolute coefficients values storage
|
|||
unsigned short* c_absc[6]; // quick access array for contexts
|
|||
int c_weight[6]; // weighting for contexts
|
|||
unsigned char* sgn_store; // sign storage for context
|
|||
unsigned char* sgn_nbh; // left signs neighbor
|
|||
unsigned char* sgn_nbv; // upper signs neighbor
|
|||
int ctx_avr; // 'average' context
|
|||
int ctx_len; // context for bit length
|
|||
int ctx_sgn; // context for sign
|
|||
int max_val; // max value
|
|||
int max_len; // max bitlength
|
|||
int bpos, dpos;
|
|||
int clen, absv, sgn;
|
|||
int snum;
|
|||
int bt, bp;
|
|||
int i;
|
|||
int b_x, b_y;
|
|||
int p_x, p_y;
|
|||
int r_x;
|
|||
int w, bc;
|
|||
// decide segmentation setting
|
|||
segm_tab = segm_tables[segm_cnt[cmp] - 1];
|
|||
// init models for bitlenghts and -patterns
|
|||
mod_len = INIT_MODEL_S(11, (segm_cnt[cmp] > 11) ? segm_cnt[cmp] : 11, 2);
|
|||
mod_res = INIT_MODEL_B((segm_cnt[cmp] < 16) ? 1 << 4 : segm_cnt[cmp], 2);
|
|||
mod_sgn = INIT_MODEL_B(9, 1);
|
|||
// set width/height of each band
|
|||
bc = cmpnfo[cmp].bc;
|
|||
w = cmpnfo[cmp].bch;
|
|||
// allocate memory for absolute values & signs storage
|
|||
absv_store = (unsigned short*) calloc(bc, sizeof(short));
|
|||
sgn_store = (unsigned char*) calloc(bc, sizeof(char));
|
|||
zdstls = (unsigned char*) calloc(bc, sizeof(char));
|
|||
if ((absv_store == nullptr) || (sgn_store == nullptr) || (zdstls == nullptr))
|
|||
{
|
|||
if (absv_store != nullptr)
|
|||
{
|
|||
free(absv_store);
|
|||
}
|
|||
if (sgn_store != nullptr)
|
|||
{
|
|||
free(sgn_store);
|
|||
}
|
|||
if (zdstls != nullptr)
|
|||
{
|
|||
free(zdstls);
|
|||
}
|
|||
sprintf(errormessage, MEM_ERRMSG);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
// set up quick access arrays for signs context
|
|||
sgn_nbh = sgn_store - 1;
|
|||
sgn_nbv = sgn_store - w;
|
|||
// locally store pointer to eob x / eob y
|
|||
eob_x = eobxhigh[cmp];
|
|||
eob_y = eobyhigh[cmp];
|
|||
// preset x/y eobs
|
|||
memset(eob_x, 0x00, bc * sizeof(char));
|
|||
memset(eob_y, 0x00, bc * sizeof(char));
|
|||
// make a local copy of the zero distribution list
|
|||
for (dpos = 0; dpos < bc; dpos++)
|
|||
{
|
|||
zdstls[dpos] = zdstdata[cmp][dpos];
|
|||
}
|
|||
// work through lower 7x7 bands in order of freqscan
|
|||
for (i = 1; i < 64; i++)
|
|||
{
|
|||
// work through blocks in order of frequency scan
|
|||
bpos = (int) freqscan[cmp][i];
|
|||
b_x = unzigzag[bpos] % 8;
|
|||
b_y = unzigzag[bpos] / 8;
|
|||
if ((b_x == 0) || (b_y == 0))
|
|||
{
|
|||
continue; // process remaining coefficients elsewhere
|
|||
}
|
|||
// preset absolute values/sign storage
|
|||
memset(absv_store, 0x00, bc * sizeof(short));
|
|||
memset(sgn_store, 0x00, bc * sizeof(char));
|
|||
// set up average context quick access arrays
|
|||
pjg_aavrg_prepare(c_absc, c_weight, absv_store, cmp);
|
|||
// locally store pointer to coefficients
|
|||
coeffs = colldata[cmp][bpos];
|
|||
// get max bit length
|
|||
max_val = MAX_V(cmp, bpos);
|
|||
max_len = BITLEN1024P(max_val);
|
|||
// arithmetic compression loop
|
|||
for (dpos = 0; dpos < bc; dpos++)
|
|||
{
|
|||
// skip if beyound eob
|
|||
if (zdstls[dpos] == 0)
|
|||
{
|
|||
continue;
|
|||
}
|
|||
//calculate x/y positions in band
|
|||
p_y = dpos / w;
|
|||
// r_y = h - ( p_y + 1 );
|
|||
p_x = dpos % w;
|
|||
r_x = w - (p_x + 1);
|
|||
// get segment-number from zero distribution list and segmentation set
|
|||
snum = segm_tab[zdstls[dpos]];
|
|||
// calculate contexts (for bit length)
|
|||
ctx_avr = pjg_aavrg_context(c_absc, c_weight, dpos, p_y, p_x, r_x); // AVERAGE context
|
|||
ctx_len = BITLEN1024P(ctx_avr); // BITLENGTH context
|
|||
// shift context / do context modelling (segmentation is done per context)
|
|||
shift_model(mod_len, ctx_len, snum);
|
|||
mod_len->exclude_symbols(max_len);
|
|||
// decode bit length of current coefficient
|
|||
clen = decode_ari(dec, mod_len);
|
|||
// simple treatment if coefficient is zero
|
|||
if (clen == 0)
|
|||
{
|
|||
// coeffs[dpos] = 0;
|
|||
}
|
|||
else
|
|||
{
|
|||
// decoding of residual
|
|||
absv = 1;
|
|||
// first set bit must be 1, so we start at clen - 2
|
|||
for (bp = clen - 2; bp >= 0; bp--)
|
|||
{
|
|||
shift_model(mod_res, snum, bp); // shift in 2 contexts
|
|||
// decode bit
|
|||
bt = decode_ari(dec, mod_res);
|
|||
// update absv
|
|||
absv = absv << 1;
|
|||
if (bt)
|
|||
{
|
|||
absv |= 1;
|
|||
}
|
|||
}
|
|||
// decode sign
|
|||
ctx_sgn = (p_x > 0) ? sgn_nbh[dpos] : 0; // sign context
|
|||
if (p_y > 0)
|
|||
{
|
|||
ctx_sgn += 3 * sgn_nbv[dpos]; // IMPROVE! !!!!!!!!!!!
|
|||
}
|
|||
mod_sgn->shift_context(ctx_sgn);
|
|||
sgn = decode_ari(dec, mod_sgn);
|
|||
// copy to colldata
|
|||
coeffs[dpos] = (sgn == 0) ? absv : -absv;
|
|||
// store absolute value/sign, decrement zdst
|
|||
absv_store[dpos] = absv;
|
|||
sgn_store[dpos] = sgn + 1;
|
|||
zdstls[dpos]--;
|
|||
// recalculate x/y eob
|
|||
if (b_x > eob_x[dpos])
|
|||
{
|
|||
eob_x[dpos] = b_x;
|
|||
}
|
|||
if (b_y > eob_y[dpos])
|
|||
{
|
|||
eob_y[dpos] = b_y;
|
|||
}
|
|||
}
|
|||
}
|
|||
// flush models
|
|||
mod_len->flush_model();
|
|||
mod_res->flush_model();
|
|||
mod_sgn->flush_model();
|
|||
}
|
|||
// free memory / clear models
|
|||
free(absv_store);
|
|||
free(sgn_store);
|
|||
free(zdstls);
|
|||
delete mod_len;
|
|||
delete mod_res;
|
|||
delete mod_sgn;
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
decodes high (7x7) AC coefficients to pjg
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_decode_ac_low(ArithmeticDecoder* dec, int cmp)
|
|||
{
|
|||
model_s* mod_len;
|
|||
model_b* mod_sgn;
|
|||
model_b* mod_res;
|
|||
model_b* mod_top;
|
|||
unsigned char* zdstls; // pointer to row/col # of non-zeroes
|
|||
signed short* coeffs; // pointer to current coefficent data
|
|||
signed short* coeffs_x[8]; // prediction coeffs - current block
|
|||
signed short* coeffs_a[8]; // prediction coeffs - neighboring block
|
|||
int pred_cf[8]; // prediction multipliers
|
|||
int ctx_lak; // lakhani context
|
|||
int ctx_abs; // absolute context
|
|||
int ctx_len; // context for bit length
|
|||
int ctx_res; // bit plane context for residual
|
|||
int ctx_sgn; // context for sign
|
|||
int max_valp; // max value (+)
|
|||
int max_valn; // max value (-)
|
|||
int max_len; // max bitlength
|
|||
int thrs_bp; // residual threshold bitplane
|
|||
int* edge_c; // edge criteria
|
|||
int bpos, dpos;
|
|||
int clen, absv, sgn;
|
|||
int bt, bp;
|
|||
int i;
|
|||
int b_x, b_y;
|
|||
int p_x, p_y;
|
|||
int w, bc;
|
|||
// init models for bitlenghts and -patterns
|
|||
mod_len = INIT_MODEL_S(11, (segm_cnt[cmp] > 11) ? segm_cnt[cmp] : 11, 2);
|
|||
mod_res = INIT_MODEL_B(1 << 4, 2);
|
|||
mod_top = INIT_MODEL_B((nois_trs[cmp] > 4) ? 1 << nois_trs[cmp] : 1 << 4, 3);
|
|||
mod_sgn = INIT_MODEL_B(11, 1);
|
|||
// set width/height of each band
|
|||
bc = cmpnfo[cmp].bc;
|
|||
w = cmpnfo[cmp].bch;
|
|||
// work through each first row / first collumn band
|
|||
for (i = 2; i < 16; i++)
|
|||
{
|
|||
// alternate between first row and first collumn
|
|||
b_x = (i % 2 == 0) ? i / 2 : 0;
|
|||
b_y = (i % 2 == 1) ? i / 2 : 0;
|
|||
bpos = (int) zigzag[b_x + (8*b_y)];
|
|||
// locally store pointer to band coefficients
|
|||
coeffs = colldata[cmp][bpos];
|
|||
// store pointers to prediction coefficients
|
|||
if (b_x == 0)
|
|||
{
|
|||
for (; b_x < 8; b_x++)
|
|||
{
|
|||
coeffs_x[b_x] = colldata[cmp][zigzag[b_x+(8*b_y)]];
|
|||
coeffs_a[b_x] = colldata[cmp][zigzag[b_x+(8*b_y)]] - 1;
|
|||
pred_cf[b_x] = icos_base_8x8[b_x * 8] * QUANT(cmp, zigzag[b_x+(8*b_y)]);
|
|||
}
|
|||
b_x = 0;
|
|||
zdstls = zdstylow[cmp];
|
|||
edge_c = &p_x;
|
|||
}
|
|||
else // if ( b_y == 0 )
|
|||
{
|
|||
for (; b_y < 8; b_y++)
|
|||
{
|
|||
coeffs_x[b_y] = colldata[cmp][zigzag[b_x+(8*b_y)]];
|
|||
coeffs_a[b_y] = colldata[cmp][zigzag[b_x+(8*b_y)]] - w;
|
|||
pred_cf[b_y] = icos_base_8x8[b_y * 8] * QUANT(cmp, zigzag[b_x+(8*b_y)]);
|
|||
}
|
|||
b_y = 0;
|
|||
zdstls = zdstxlow[cmp];
|
|||
edge_c = &p_y;
|
|||
}
|
|||
// get max bit length / other info
|
|||
max_valp = MAX_V(cmp, bpos);
|
|||
max_valn = -max_valp;
|
|||
max_len = BITLEN1024P(max_valp);
|
|||
thrs_bp = (max_len > nois_trs[cmp]) ? max_len - nois_trs[cmp] : 0;
|
|||
// arithmetic compression loop
|
|||
for (dpos = 0; dpos < bc; dpos++)
|
|||
{
|
|||
// skip if beyound eob
|
|||
if (zdstls[dpos] == 0)
|
|||
{
|
|||
continue;
|
|||
}
|
|||
//calculate x/y positions in band
|
|||
p_y = dpos / w;
|
|||
p_x = dpos % w;
|
|||
// edge treatment / calculate LAKHANI context
|
|||
if ((*edge_c) > 0)
|
|||
{
|
|||
ctx_lak = pjg_lakh_context(coeffs_x, coeffs_a, pred_cf, dpos);
|
|||
}
|
|||
else
|
|||
{
|
|||
ctx_lak = 0;
|
|||
}
|
|||
ctx_lak = CLAMPED(max_valn, max_valp, ctx_lak);
|
|||
ctx_len = BITLEN2048N(ctx_lak); // BITLENGTH context
|
|||
// shift context / do context modelling (segmentation is done per context)
|
|||
shift_model(mod_len, ctx_len, zdstls[dpos]);
|
|||
mod_len->exclude_symbols(max_len);
|
|||
// decode bit length of current coefficient
|
|||
clen = decode_ari(dec, mod_len);
|
|||
// simple treatment if coefficients == 0
|
|||
if (clen == 0)
|
|||
{
|
|||
// coeffs[dpos] = 0;
|
|||
}
|
|||
else
|
|||
{
|
|||
// decoding of residual
|
|||
bp = clen - 2; // first set bit must be 1, so we start at clen - 2
|
|||
ctx_res = (bp >= thrs_bp) ? 1 : 0;
|
|||
ctx_abs = ABS(ctx_lak);
|
|||
ctx_sgn = (ctx_lak == 0) ? 0 : (ctx_lak > 0) ? 1 : 2;
|
|||
for (; bp >= thrs_bp; bp--)
|
|||
{
|
|||
shift_model(mod_top, ctx_abs >> thrs_bp, ctx_res, clen - thrs_bp); // shift in 3 contexts
|
|||
// decode bit
|
|||
bt = decode_ari(dec, mod_top);
|
|||
// update context
|
|||
ctx_res = ctx_res << 1;
|
|||
if (bt)
|
|||
{
|
|||
ctx_res |= 1;
|
|||
}
|
|||
}
|
|||
absv = (ctx_res == 0) ? 1 : ctx_res; // !!!!
|
|||
for (; bp >= 0; bp--)
|
|||
{
|
|||
shift_model(mod_res, zdstls[dpos], bp); // shift in 2 contexts
|
|||
// decode bit
|
|||
bt = decode_ari(dec, mod_res);
|
|||
// update absv
|
|||
absv = absv << 1;
|
|||
if (bt)
|
|||
{
|
|||
absv |= 1;
|
|||
}
|
|||
}
|
|||
// decode sign
|
|||
shift_model(mod_sgn, zdstls[dpos], ctx_sgn);
|
|||
sgn = decode_ari(dec, mod_sgn);
|
|||
// copy to colldata
|
|||
coeffs[dpos] = (sgn == 0) ? absv : -absv;
|
|||
// decrement # of non zeroes
|
|||
zdstls[dpos]--;
|
|||
}
|
|||
}
|
|||
// flush models
|
|||
mod_len->flush_model();
|
|||
mod_res->flush_model();
|
|||
mod_top->flush_model();
|
|||
mod_sgn->flush_model();
|
|||
}
|
|||
// free memory / clear models
|
|||
delete mod_len;
|
|||
delete mod_res;
|
|||
delete mod_top;
|
|||
delete mod_sgn;
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
deodes a stream of generic (8bit) data from pjg
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_decode_generic(
|
|||
ArithmeticDecoder* dec,
|
|||
unsigned char** data,
|
|||
int* len)
|
|||
{
|
|||
MemoryWriter* bwrt;
|
|||
model_s* model;
|
|||
int c;
|
|||
// start byte writer
|
|||
bwrt = new MemoryWriter();
|
|||
// decode header, ending with 256 symbol
|
|||
model = INIT_MODEL_S(256 + 1, 256, 1);
|
|||
while (true)
|
|||
{
|
|||
c = decode_ari(dec, model);
|
|||
if (c == 256)
|
|||
{
|
|||
break;
|
|||
}
|
|||
bwrt->write_byte((unsigned char) c);
|
|||
model->shift_context(c);
|
|||
}
|
|||
delete model;
|
|||
// check for out of memory
|
|||
if (bwrt->error())
|
|||
{
|
|||
delete bwrt;
|
|||
sprintf(errormessage, MEM_ERRMSG);
|
|||
errorlevel = 2;
|
|||
return false;
|
|||
}
|
|||
// get data/length and close byte writer
|
|||
(*data) = bwrt->get_c_data();
|
|||
if (len != nullptr)
|
|||
{
|
|||
(*len) = bwrt->num_bytes_written();
|
|||
}
|
|||
delete bwrt;
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
decodes one bit from pjg
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_decode_bit(ArithmeticDecoder* dec, unsigned char* bit)
|
|||
{
|
|||
model_b* model = INIT_MODEL_B(1, -1);
|
|||
(*bit) = decode_ari(dec, model);
|
|||
delete model;
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
get zero sort frequency scan vector
|
|||
----------------------------------------------- */
|
|||
void packJPG::pjg_get_zerosort_scan(unsigned char* sv, int cmp)
|
|||
{
|
|||
unsigned int zdist[64]; // distributions of zeroes per band
|
|||
int bc = cmpnfo[cmp].bc;
|
|||
int bpos, dpos;
|
|||
bool done = false;
|
|||
int swap;
|
|||
int i;
|
|||
// preset sv & zdist
|
|||
for (i = 0; i < 64; i++)
|
|||
{
|
|||
sv[i] = i;
|
|||
zdist[i] = 0;
|
|||
}
|
|||
// count zeroes for each frequency
|
|||
for (bpos = 0; bpos < 64; bpos++)
|
|||
{
|
|||
for (dpos = 0; dpos < bc; dpos++)
|
|||
if (colldata[cmp][bpos][dpos] == 0)
|
|||
{
|
|||
zdist[bpos]++;
|
|||
}
|
|||
}
|
|||
// bubble sort according to count of zeroes (descending order)
|
|||
while (!done)
|
|||
{
|
|||
done = true;
|
|||
for (i = 2; i < 64; i++)
|
|||
if (zdist[i] < zdist[i - 1])
|
|||
{
|
|||
swap = zdist[i];
|
|||
zdist[i] = zdist[i - 1];
|
|||
zdist[i - 1] = swap;
|
|||
swap = sv[i];
|
|||
sv[i] = sv[i - 1];
|
|||
sv[i - 1] = swap;
|
|||
done = false;
|
|||
}
|
|||
}
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
optimizes JFIF header for compression
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_optimize_header(void)
|
|||
{
|
|||
unsigned char type = 0x00; // type of current marker segment
|
|||
unsigned int len = 0; // length of current marker segment
|
|||
unsigned int hpos = 0; // position in header
|
|||
unsigned int fpos; // end of marker position
|
|||
unsigned int skip; // bytes to skip
|
|||
unsigned int spos; // sub position
|
|||
int i;
|
|||
// search for DHT (0xFFC4) & DQT (0xFFDB) marker segments
|
|||
// header parser loop
|
|||
while ((int) hpos < hdrs)
|
|||
{
|
|||
type = hdrdata[hpos + 1];
|
|||
len = 2 + B_SHORT(hdrdata[hpos + 2], hdrdata[hpos + 3]);
|
|||
if (type == 0xC4) // for DHT
|
|||
{
|
|||
fpos = hpos + len; // reassign length to end position
|
|||
hpos += 4; // skip marker & length
|
|||
while (hpos < fpos)
|
|||
{
|
|||
hpos++;
|
|||
// table found - compare with each of the four standard tables
|
|||
for (i = 0; i < 4; i++)
|
|||
{
|
|||
for (spos = 0; spos < std_huff_lengths[i]; spos++)
|
|||
{
|
|||
if (hdrdata[hpos + spos] != std_huff_tables[i][spos])
|
|||
{
|
|||
break;
|
|||
}
|
|||
}
|
|||
// check if comparison ok
|
|||
if (spos != std_huff_lengths[i])
|
|||
{
|
|||
continue;
|
|||
}
|
|||
// if we get here, the table matches the standard table
|
|||
// number 'i', so it can be replaced
|
|||
hdrdata[hpos + 0] = std_huff_lengths[i] - 16 - i;
|
|||
hdrdata[hpos + 1] = i;
|
|||
for (spos = 2; spos < std_huff_lengths[i]; spos++)
|
|||
{
|
|||
hdrdata[hpos + spos] = 0x00;
|
|||
}
|
|||
// everything done here, so leave
|
|||
break;
|
|||
}
|
|||
skip = 16;
|
|||
for (i = 0; i < 16; i++)
|
|||
{
|
|||
skip += (int) hdrdata[hpos + i];
|
|||
}
|
|||
hpos += skip;
|
|||
}
|
|||
}
|
|||
else if (type == 0xDB) // for DQT
|
|||
{
|
|||
fpos = hpos + len; // reassign length to end position
|
|||
hpos += 4; // skip marker & length
|
|||
while (hpos < fpos)
|
|||
{
|
|||
i = LBITS(hdrdata[hpos], 4);
|
|||
hpos++;
|
|||
// table found
|
|||
if (i == 1) // get out for 16 bit precision
|
|||
{
|
|||
hpos += 128;
|
|||
continue;
|
|||
}
|
|||
// do diff coding for 8 bit precision
|
|||
for (spos = 63; spos > 0; spos--)
|
|||
{
|
|||
hdrdata[hpos + spos] -= hdrdata[hpos + spos - 1];
|
|||
}
|
|||
hpos += 64;
|
|||
}
|
|||
}
|
|||
else // skip segment
|
|||
{
|
|||
hpos += len;
|
|||
}
|
|||
}
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
undoes the header optimizations
|
|||
----------------------------------------------- */
|
|||
bool packJPG::pjg_unoptimize_header(void)
|
|||
{
|
|||
unsigned char type = 0x00; // type of current marker segment
|
|||
unsigned int len = 0; // length of current marker segment
|
|||
unsigned int hpos = 0; // position in header
|
|||
unsigned int fpos; // end of marker position
|
|||
unsigned int skip; // bytes to skip
|
|||
unsigned int spos; // sub position
|
|||
int i;
|
|||
// search for DHT (0xFFC4) & DQT (0xFFDB) marker segments
|
|||
// header parser loop
|
|||
while ((int) hpos < hdrs)
|
|||
{
|
|||
type = hdrdata[hpos + 1];
|
|||
len = 2 + B_SHORT(hdrdata[hpos + 2], hdrdata[hpos + 3]);
|
|||
if (type == 0xC4) // for DHT
|
|||
{
|
|||
fpos = hpos + len; // reassign length to end position
|
|||
hpos += 4; // skip marker & length
|
|||
while (hpos < fpos)
|
|||
{
|
|||
hpos++;
|
|||
// table found - check if modified
|
|||
if (hdrdata[hpos] > 2)
|
|||
{
|
|||
// reinsert the standard table
|
|||
i = hdrdata[hpos + 1];
|
|||
for (spos = 0; spos < std_huff_lengths[i]; spos++)
|
|||
{
|
|||
hdrdata[hpos + spos] = std_huff_tables[i][spos];
|
|||
}
|
|||
}
|
|||
skip = 16;
|
|||
for (i = 0; i < 16; i++)
|
|||
{
|
|||
skip += (int) hdrdata[hpos + i];
|
|||
}
|
|||
hpos += skip;
|
|||
}
|
|||
}
|
|||
else if (type == 0xDB) // for DQT
|
|||
{
|
|||
fpos = hpos + len; // reassign length to end position
|
|||
hpos += 4; // skip marker & length
|
|||
while (hpos < fpos)
|
|||
{
|
|||
i = LBITS(hdrdata[hpos], 4);
|
|||
hpos++;
|
|||
// table found
|
|||
if (i == 1) // get out for 16 bit precision
|
|||
{
|
|||
hpos += 128;
|
|||
continue;
|
|||
}
|
|||
// undo diff coding for 8 bit precision
|
|||
for (spos = 1; spos < 64; spos++)
|
|||
{
|
|||
hdrdata[hpos + spos] += hdrdata[hpos + spos - 1];
|
|||
}
|
|||
hpos += 64;
|
|||
}
|
|||
}
|
|||
else // skip segment
|
|||
{
|
|||
hpos += len;
|
|||
}
|
|||
}
|
|||
return true;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
preparations for special average context
|
|||
----------------------------------------------- */
|
|||
void packJPG::pjg_aavrg_prepare(
|
|||
unsigned short** abs_coeffs,
|
|||
int* weights,
|
|||
unsigned short* abs_store,
|
|||
int cmp)
|
|||
{
|
|||
int w = cmpnfo[cmp].bch;
|
|||
// set up quick access arrays for all prediction positions
|
|||
abs_coeffs[0] = abs_store + (0 + ((-2)*w)); // top-top
|
|||
abs_coeffs[1] = abs_store + (-1 + ((-1)*w)); // top-left
|
|||
abs_coeffs[2] = abs_store + (0 + ((-1)*w)); // top
|
|||
abs_coeffs[3] = abs_store + (1 + ((-1)*w)); // top-right
|
|||
abs_coeffs[4] = abs_store + (-2 + ((0)*w)); // left-left
|
|||
abs_coeffs[5] = abs_store + (-1 + ((0)*w)); // left
|
|||
// copy context weighting factors
|
|||
weights[0] = abs_ctx_weights_lum[0][0][2]; // top-top
|
|||
weights[1] = abs_ctx_weights_lum[0][1][1]; // top-left
|
|||
weights[2] = abs_ctx_weights_lum[0][1][2]; // top
|
|||
weights[3] = abs_ctx_weights_lum[0][1][3]; // top-right
|
|||
weights[4] = abs_ctx_weights_lum[0][2][0]; // left-left
|
|||
weights[5] = abs_ctx_weights_lum[0][2][1]; // left
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
special average context used in coeff encoding
|
|||
----------------------------------------------- */
|
|||
int packJPG::pjg_aavrg_context(
|
|||
unsigned short** abs_coeffs,
|
|||
int* weights,
|
|||
int pos,
|
|||
int p_y,
|
|||
int p_x,
|
|||
int r_x)
|
|||
{
|
|||
int ctx_avr = 0; // AVERAGE context
|
|||
int w_ctx = 0; // accumulated weight of context
|
|||
int w_curr; // current weight of context
|
|||
// different cases due to edge treatment
|
|||
if (p_y >= 2)
|
|||
{
|
|||
w_curr = weights[0];
|
|||
ctx_avr += abs_coeffs[0][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
w_curr = weights[2];
|
|||
ctx_avr += abs_coeffs[2][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
if (p_x >= 2)
|
|||
{
|
|||
w_curr = weights[1];
|
|||
ctx_avr += abs_coeffs[1][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
w_curr = weights[4];
|
|||
ctx_avr += abs_coeffs[4][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
w_curr = weights[5];
|
|||
ctx_avr += abs_coeffs[5][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
}
|
|||
else if (p_x == 1)
|
|||
{
|
|||
w_curr = weights[1];
|
|||
ctx_avr += abs_coeffs[1][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
w_curr = weights[5];
|
|||
ctx_avr += abs_coeffs[5][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
}
|
|||
if (r_x >= 1)
|
|||
{
|
|||
w_curr = weights[3];
|
|||
ctx_avr += abs_coeffs[3][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
}
|
|||
}
|
|||
else if (p_y == 1)
|
|||
{
|
|||
w_curr = weights[2];
|
|||
ctx_avr += abs_coeffs[2][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
if (p_x >= 2)
|
|||
{
|
|||
w_curr = weights[1];
|
|||
ctx_avr += abs_coeffs[1][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
w_curr = weights[4];
|
|||
ctx_avr += abs_coeffs[4][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
w_curr = weights[5];
|
|||
ctx_avr += abs_coeffs[5][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
}
|
|||
else if (p_x == 1)
|
|||
{
|
|||
w_curr = weights[1];
|
|||
ctx_avr += abs_coeffs[1][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
w_curr = weights[5];
|
|||
ctx_avr += abs_coeffs[5][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
}
|
|||
if (r_x >= 1)
|
|||
{
|
|||
w_curr = weights[3];
|
|||
ctx_avr += abs_coeffs[3][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
if (p_x >= 2)
|
|||
{
|
|||
w_curr = weights[4];
|
|||
ctx_avr += abs_coeffs[4][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
w_curr = weights[5];
|
|||
ctx_avr += abs_coeffs[5][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
}
|
|||
else if (p_x == 1)
|
|||
{
|
|||
w_curr = weights[5];
|
|||
ctx_avr += abs_coeffs[5][pos] * w_curr;
|
|||
w_ctx += w_curr;
|
|||
}
|
|||
}
|
|||
// return average context
|
|||
return (w_ctx != 0) ? (ctx_avr + (w_ctx / 2)) / w_ctx : 0;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
lakhani ac context used in coeff encoding
|
|||
----------------------------------------------- */
|
|||
int packJPG::pjg_lakh_context(
|
|||
signed short** coeffs_x,
|
|||
signed short** coeffs_a,
|
|||
int* pred_cf,
|
|||
int pos)
|
|||
{
|
|||
int pred = 0;
|
|||
// calculate partial prediction
|
|||
pred -= (coeffs_x[1][pos] + coeffs_a[1][pos]) * pred_cf[1];
|
|||
pred -= (coeffs_x[2][pos] - coeffs_a[2][pos]) * pred_cf[2];
|
|||
pred -= (coeffs_x[3][pos] + coeffs_a[3][pos]) * pred_cf[3];
|
|||
pred -= (coeffs_x[4][pos] - coeffs_a[4][pos]) * pred_cf[4];
|
|||
pred -= (coeffs_x[5][pos] + coeffs_a[5][pos]) * pred_cf[5];
|
|||
pred -= (coeffs_x[6][pos] - coeffs_a[6][pos]) * pred_cf[6];
|
|||
pred -= (coeffs_x[7][pos] + coeffs_a[7][pos]) * pred_cf[7];
|
|||
// normalize / quantize partial prediction
|
|||
pred = ((pred > 0) ? (pred + (pred_cf[0]/2)) : (pred - (pred_cf[0]/2))) / pred_cf[0];
|
|||
// complete prediction
|
|||
pred += coeffs_a[0][pos];
|
|||
return pred;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
Calculates coordinates for nearest neighbor context
|
|||
----------------------------------------------- */
|
|||
void packJPG::get_context_nnb(int pos, int w, int* a, int* b)
|
|||
{
|
|||
// this function calculates and returns coordinates for
|
|||
// a simple 2D context
|
|||
if (pos == 0)
|
|||
{
|
|||
*a = -1;
|
|||
*b = -1;
|
|||
}
|
|||
else if ((pos % w) == 0)
|
|||
{
|
|||
*b = pos - w;
|
|||
if (pos >= (w << 1))
|
|||
{
|
|||
*a = pos - (w << 1);
|
|||
}
|
|||
else
|
|||
{
|
|||
*a = *b;
|
|||
}
|
|||
}
|
|||
else if (pos < w)
|
|||
{
|
|||
*a = pos - 1;
|
|||
if (pos >= 2)
|
|||
{
|
|||
*b = pos - 2;
|
|||
}
|
|||
else
|
|||
{
|
|||
*b = *a;
|
|||
}
|
|||
}
|
|||
else
|
|||
{
|
|||
*a = pos - 1;
|
|||
*b = pos - w;
|
|||
}
|
|||
}
|
|||
/* -------------------- End of PJG specific functions ---------------------- */
|
|||
/* ------------------- Begin of DCT specific functions --------------------- */
|
|||
/* -----------------------------------------------
|
|||
inverse DCT transform using precalc tables (fast)
|
|||
----------------------------------------------- */
|
|||
int packJPG::idct_2d_fst_8x1(int cmp, int dpos, int ix, int iy)
|
|||
{
|
|||
int idct = 0;
|
|||
int ixy;
|
|||
// calculate start index
|
|||
ixy = ix << 3;
|
|||
// begin transform
|
|||
idct += colldata[cmp][ 0][dpos] * adpt_idct_8x1[cmp][ixy + 0];
|
|||
idct += colldata[cmp][ 1][dpos] * adpt_idct_8x1[cmp][ixy + 1];
|
|||
idct += colldata[cmp][ 5][dpos] * adpt_idct_8x1[cmp][ixy + 2];
|
|||
idct += colldata[cmp][ 6][dpos] * adpt_idct_8x1[cmp][ixy + 3];
|
|||
idct += colldata[cmp][14][dpos] * adpt_idct_8x1[cmp][ixy + 4];
|
|||
idct += colldata[cmp][15][dpos] * adpt_idct_8x1[cmp][ixy + 5];
|
|||
idct += colldata[cmp][27][dpos] * adpt_idct_8x1[cmp][ixy + 6];
|
|||
idct += colldata[cmp][28][dpos] * adpt_idct_8x1[cmp][ixy + 7];
|
|||
return idct;
|
|||
}
|
|||
/* -----------------------------------------------
|
|||
inverse DCT transform using precalc tables (fast)
|
|||
----------------------------------------------- */
|
|||
int packJPG::idct_2d_fst_1x8(int cmp, int dpos, int ix, int iy)
|
|||
{
|
|||
int idct = 0;
|
|||
int ixy;
|
|||
// calculate start index
|
|||
ixy = iy << 3;
|
|||
// begin transform
|
|||
idct += colldata[cmp][ 0][dpos] * adpt_idct_1x8[cmp][ixy + 0];
|
|||
idct += colldata[cmp][ 2][dpos] * adpt_idct_1x8[cmp][ixy + 1];
|
|||
idct += colldata[cmp][ 3][dpos] * adpt_idct_1x8[cmp][ixy + 2];
|
|||
idct += colldata[cmp][ 9][dpos] * adpt_idct_1x8[cmp][ixy + 3];
|
|||
idct += colldata[cmp][10][dpos] * adpt_idct_1x8[cmp][ixy + 4];
|
|||
idct += colldata[cmp][20][dpos] * adpt_idct_1x8[cmp][ixy + 5];
|
|||
idct += colldata[cmp][21][dpos] * adpt_idct_1x8[cmp][ixy + 6];
|
|||
idct += colldata[cmp][35][dpos] * adpt_idct_1x8[cmp][ixy + 7];
|
|||
return idct;
|
|||
}
|
|||
/* ------------------- End of DCT specific functions ----------------------- */
|
|||
/* -------------------- Begin of prediction functions ---------------------- */
|
|||
/* -----------------------------------------------
|
|||
returns predictor for collection data
|
|||
----------------------------------------------- */
|
|||
//~ #if defined(USE_PLOCOI)
|
|||
int packJPG::dc_coll_predictor(int cmp, int dpos)
|
|||
{
|
|||
signed short* coefs = colldata[cmp][0];
|
|||
int w = cmpnfo[cmp].bch;
|
|||
int a, b, c;
|
|||
if (dpos < w)
|
|||
{
|
|||
a = coefs[dpos - 1];
|
|||
b = 0;
|
|||
c = 0;
|
|||
}
|
|||
else if ((dpos%w) == 0)
|
|||
{
|
|||
a = 0;
|
|||
b = coefs[dpos - w];
|
|||
c = 0;
|
|||
}
|
|||
else
|
|||
{
|
|||
a = coefs[dpos - 1];
|
|||
b = coefs[dpos - w];
|
|||
c = coefs[dpos - 1 - w];
|
|||
}
|
|||
return plocoi(a, b, c);
|
|||
}
|
|||
//~ #endif
|
|||
/* -----------------------------------------------
|
|||
1D DCT predictor for DC coefficients
|
|||
----------------------------------------------- */
|
|||
//~ #if !defined(USE_PLOCOI)
|
|||
int packJPG::dc_1ddct_predictor(int cmp, int dpos)
|
|||
{
|
|||
int w = cmpnfo[cmp].bch;
|
|||
int px = (dpos % w);
|
|||
int py = (dpos / w);
|
|||
int pred;
|
|||
int pa = 0;
|
|||
int pb = 0;
|
|||
int xa = 0;
|
|||
int xb = 0;
|
|||
int swap;
|
|||
// store current block DC coefficient
|
|||
swap = colldata[cmp][0][dpos];
|
|||
colldata[cmp][0][dpos] = 0;
|
|||
// calculate prediction
|
|||
if ((px > 0) && (py > 0))
|
|||
{
|
|||
pa = idct_2d_fst_8x1(cmp, dpos - 1, 7, 0);
|
|||
pb = idct_2d_fst_1x8(cmp, dpos - w, 0, 7);
|
|||
xa = idct_2d_fst_8x1(cmp, dpos, 0, 0);
|
|||
xb = idct_2d_fst_1x8(cmp, dpos, 0, 0);
|
|||
pred = ((pa - xa) + (pb - xb)) * (8 / 2);
|
|||
}
|
|||
else if (px > 0)
|
|||
{
|
|||
pa = idct_2d_fst_8x1(cmp, dpos - 1, 7, 0);
|
|||
xa = idct_2d_fst_8x1(cmp, dpos, 0, 0);
|
|||
pred = (pa - xa) * 8;
|
|||
}
|
|||
else if (py > 0)
|
|||
{
|
|||
pb = idct_2d_fst_1x8(cmp, dpos - w, 0, 7);
|
|||
xb = idct_2d_fst_1x8(cmp, dpos, 0, 0);
|
|||
pred = (pb - xb) * 8;
|
|||
}
|
|||
else
|
|||
{
|
|||
pred = 0;
|
|||
}
|
|||
// write back current DCT coefficient
|
|||
colldata[cmp][0][dpos] = swap;
|
|||
// clamp and quantize predictor
|
|||
pred = CLAMPED(-(1024 * DCT_RSC_FACTOR), (1016 * DCT_RSC_FACTOR), pred);
|
|||
pred = pred / QUANT(cmp, 0);
|
|||
pred = DCT_RESCALE(pred);
|
|||
return pred;
|
|||
}
|
|||
//~ #endif
|