diff --git a/Makefile.in b/Makefile.in index ca44a62..0041d9f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -28,11 +28,9 @@ LINKLIB=pcompress LIBVER=1 MAINSRCS = utils/utils.c allocator.c lzma_compress.c ppmd_compress.c \ adaptive_compress.c lzfx_compress.c lz4_compress.c none_compress.c \ - utils/xxhash_base.c utils/heap.c utils/cpuid.c archive/pc_archive.c \ - utils/phash/phash.c utils/phash/lookupa.c utils/phash/recycle.c pcompress.c + utils/xxhash_base.c utils/heap.c utils/cpuid.c pcompress.c MAINHDRS = allocator.h pcompress.h utils/utils.h utils/xxhash.h utils/heap.h \ - utils/cpuid.h utils/xxhash.h archive/pc_archive.h utils/phash/standard.h \ - utils/phash/lookupa.h utils/phash/recycle.h utils/phash/phash.h + utils/cpuid.h utils/xxhash.h archive/pc_archive.h MAINOBJS = $(MAINSRCS:.c=.o) PROGSRCS = main.c @@ -124,14 +122,26 @@ CRCHDRS = lzma/crc64_table_le.h lzma/crc64_table_be.h lzma/crc_macros.h \ lzma/crc32_table_le.h lzma/crc32_table_be.h lzma/lzma_crc.h CRCOBJS = $(CRCSRCS:.c=.o) -LZPSRCS = lzp/lzp.c -LZPHDRS = lzp/lzp.h +LZPSRCS = filters/lzp/lzp.c +LZPHDRS = filters/lzp/lzp.h LZPOBJS = $(LZPSRCS:.c=.o) -DELTA2SRCS = delta2/delta2.c -DELTA2HDRS = delta2/delta2.h +DELTA2SRCS = filters/delta2/delta2.c +DELTA2HDRS = filters/delta2/delta2.h DELTA2OBJS = $(DELTA2SRCS:.c=.o) +ARCHIVESRCS = archive/pc_archive.c archive/pc_arc_filter.c utils/phash/phash.c \ + utils/phash/lookupa.c utils/phash/recycle.c +ARCHIVEHDRS = pcompress.h utils/utils.h archive/pc_archive.h utils/phash/standard.h \ + utils/phash/lookupa.h utils/phash/recycle.h utils/phash/phash.h archive/pc_arc_filter.h +ARCHIVEOBJS = $(ARCHIVESRCS:.c=.o) + +PJPGSRCS = filters/packjpg/aricoder.cpp filters/packjpg/bitops.cpp filters/packjpg/packjpg.cpp \ + archive/pjpg_helper.cpp +PJPGHDRS = filters/packjpg/aricoder.h filters/packjpg/bitops.h filters/packjpg/dct8x8.h \ + filters/packjpg/packjpglib.h filters/packjpg/pjpgtbl.h +PJPGOBJS = $(PJPGSRCS:.cpp=.o) + SKEIN_BLOCK_C = crypto/skein/skein_block.c SKEIN_BLOCK_ASM = crypto/skein/skein_block_x64.s SKEIN_BLOCK_SRC = @SKEIN_BLOCK@ @@ -157,8 +167,8 @@ LIBBSCLIB = @LIBBSCLIB@ LIBBSCGEN_OPT = -fopenmp LIBBSCCPPFLAGS = -I$(LIBBSCDIR)/libbsc -DENABLE_PC_LIBBSC -TRANSP_SRCS = transpose/transpose.c -TRANSP_HDRS = transpose/transpose.h +TRANSP_SRCS = filters/transpose/transpose.c +TRANSP_HDRS = filters/transpose/transpose.h TRANSP_OBJS = $(TRANSP_SRCS:.c=.o) KECCAK_SRC_COMMON = crypto/keccak/genKAT.c crypto/keccak/KeccakDuplex.c \ @@ -182,21 +192,23 @@ KECCAK_HDRS = @KECCAK_HDRS@ KECCAK_OBJS = $(KECCAK_SRCS:.c=.o) KECCAK_OBJS_ASM = $(KECCAK_SRCS_ASM:.s=.o) -BAKFILES = *~ lzma/*~ lzfx/*~ lz4/*~ rabin/*~ bsdiff/*~ lzp/*~ utils/*~ crypto/sha2/*~ \ +BAKFILES = *~ lzma/*~ lzfx/*~ lz4/*~ rabin/*~ bsdiff/*~ filters/lzp/*~ utils/*~ crypto/sha2/*~ \ crypto/sha2/intel/*~ crypto/aes/*~ crypto/scrypt/*~ crypto/*~ rabin/global/*~ \ delta2/*~ crypto/keccak/*~ transpose/*~ crypto/skein/*~ crypto/keccak/*.o \ - archive/*~ + archive/*~ filters/delta2/*~ filters/packjpg/*~ filters/transpose/*~ RM = rm -f RM_RF = rm -rf -COMMON_CPPFLAGS = -I. -I./lzma -I./lzfx -I./lz4 -I./rabin -I./bsdiff -DNODEFAULT_PROPS \ +BASE_CPPFLAGS = -I. -I./lzma -I./lzfx -I./lz4 -I./rabin -I./bsdiff -DNODEFAULT_PROPS \ -DFILE_OFFSET_BITS=64 -D_REENTRANT -D__USE_SSE_INTRIN__ -D_LZMA_PROB32 \ - -I./lzp @LIBBSCCPPFLAGS@ -I./crypto/skein -I./utils -I./crypto/sha2 \ + -I./filters/lzp @LIBBSCCPPFLAGS@ -I./crypto/skein -I./utils -I./crypto/sha2 \ -I./crypto/scrypt -I./crypto/aes -I./crypto @KEYLEN@ -I./rabin/global \ - -I./crypto/keccak -I./transpose -I./crypto/blake2 $(EXTRA_CPPFLAGS) \ - -I./crypto/xsalsa20 -I./archive -pedantic -Wall -std=gnu99 \ - -fno-strict-aliasing -Wno-unused-but-set-variable -Wno-enum-compare \ - @COMPAT_CPPFLAGS@ @XSALSA20_DEBUG@ -I@LIBARCHIVE_INC@ + -I./crypto/keccak -I./filters/transpose -I./crypto/blake2 $(EXTRA_CPPFLAGS) \ + -I./crypto/xsalsa20 -I./archive -pedantic -Wall -I./filters -fno-strict-aliasing \ + -Wno-unused-but-set-variable -Wno-enum-compare \ + @COMPAT_CPPFLAGS@ @XSALSA20_DEBUG@ -I@LIBARCHIVE_INC@ -I./filters/packjpg +COMMON_CPPFLAGS = $(BASE_CPPFLAGS) -std=gnu99 +COMMON_CPPFLAGS_cpp = $(BASE_CPPFLAGS) COMMON_VEC_FLAGS = -ftree-vectorize COMMON_LOOP_OPTFLAGS = $(VEC_FLAGS) -floop-interchange -floop-block LDLIBS = -ldl -L./buildtmp -Wl,-R@LIBBZ2_DIR@ -lbz2 -L./buildtmp -Wl,-R@LIBZ_DIR@ -lz -lm @LIBBSCLFLAGS@ \ @@ -206,7 +218,7 @@ OBJS = $(MAINOBJS) $(LZMAOBJS) $(PPMDOBJS) $(LZFXOBJS) $(LZ4OBJS) $(CRCOBJS) \ $(RABINOBJS) $(BSDIFFOBJS) $(LZPOBJS) $(DELTA2OBJS) @LIBBSCWRAPOBJ@ $(SKEINOBJS) \ $(SKEIN_BLOCK_OBJ) @SHA2ASM_OBJS@ @SHA2_OBJS@ $(KECCAK_OBJS) $(KECCAK_OBJS_ASM) \ $(TRANSP_OBJS) $(CRYPTO_OBJS) $(ZLIB_OBJS) $(BZLIB_OBJS) $(XXHASH_OBJS) $(BLAKE2_OBJS) \ -@CRYPTO_COMPAT_OBJS@ $(CRYPTO_ASM_OBJS) +@CRYPTO_COMPAT_OBJS@ $(CRYPTO_ASM_OBJS) $(ARCHIVEOBJS) $(PJPGOBJS) DEBUG_LINK = g++ -pthread @LIBBSCGEN_OPT@ @EXTRA_OPT_FLAGS@ -fopenmp -fPIC DEBUG_COMPILE = gcc -g -c @EXTRA_OPT_FLAGS@ -fPIC @@ -277,6 +289,13 @@ $(LZPOBJS): $(LZPSRCS) $(LZPHDRS) $(DELTA2OBJS): $(DELTA2SRCS) $(DELTA2HDRS) $(COMPILE) $(GEN_OPT) $(VEC_FLAGS) $(CPPFLAGS) $(@:.o=.c) -o $@ +$(ARCHIVEOBJS): $(ARCHIVESRCS) $(ARCHIVEHDRS) + $(COMPILE) $(GEN_OPT) $(VEC_FLAGS) $(CPPFLAGS) $(@:.o=.c) -o $@ + +$(PJPGOBJS): $(PJPGSRCS) $(PJPGHDRS) + $(COMPILE_cpp) $(COMMON_VEC_FLAGS) @SSE_OPT_FLAGS@ -O2 -fsched-spec-load \ + $(VEC_FLAGS) -DBUILD_LIB $(COMMON_CPPFLAGS_cpp) $(@:.o=.cpp) -o $@ + $(SKEIN_BLOCK_OBJ): $(SKEIN_BLOCK_SRC) $(COMPILE) $(SKEIN_FLAGS) $(SKEIN_BLOCK_SRC) -o $@ diff --git a/archive/pc_arc_filter.c b/archive/pc_arc_filter.c new file mode 100644 index 0000000..dd7ed44 --- /dev/null +++ b/archive/pc_arc_filter.c @@ -0,0 +1,130 @@ +/* + * This file is a part of Pcompress, a chunked parallel multi- + * algorithm lossless compression and decompression program. + * + * Copyright (C) 2012-2013 Moinak Ghosh. All rights reserved. + * Use is subject to license terms. + * + * This program is free software; you can redistribute it and/or + * modify it 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. + * + * This program 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. + * If not, see . + * + * moinakg@belenix.org, http://moinakg.wordpress.com/ + * + */ + +/* + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pc_arc_filter.h" +#include "pc_archive.h" + +#define PACKJPG_DEF_BUFSIZ (512 * 1024) +#define JPG_SIZE_LIMIT (100 * 1024 * 1024) + +struct packjpg_filter_data { + uchar_t *buff; + size_t bufflen; +}; + +extern size_t packjpg_filter_process(uchar_t *in_buf, size_t len, uchar_t **out_buf); + +int packjpg_filter(struct filter_info *fi, void *filter_private); + +void +add_filters_by_ext() +{ + struct packjpg_filter_data *pjdat; + + pjdat = (struct packjpg_filter_data *)malloc(sizeof (struct packjpg_filter_data)); + pjdat->buff = (uchar_t *)malloc(PACKJPG_DEF_BUFSIZ); + pjdat->bufflen = PACKJPG_DEF_BUFSIZ; + if (insert_filter_data(packjpg_filter, pjdat, "pjg") != 0) { + free(pjdat->buff); + free(pjdat); + log_msg(LOG_WARN, 0, "Failed to add filter module for packJPG."); + } +} + +/* a short reminder about input/output stream types + for the pjglib_init_streams() function + + 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! */ + +int +packjpg_filter(struct filter_info *fi, void *filter_private) +{ + struct packjpg_filter_data *pjdat = (struct packjpg_filter_data *)filter_private; + uchar_t *mapbuf, *out; + size_t len; + + len = archive_entry_size(fi->entry); + if (len > JPG_SIZE_LIMIT) // Bork on massive JPEGs + return (-1); + + mapbuf = mmap(NULL, len, PROT_READ, MAP_SHARED, fi->fd, 0); + if (mapbuf == NULL) + return (-1); + + if (pjdat->bufflen < len) { + free(pjdat->buff); + pjdat->bufflen = len; + pjdat->buff = malloc(pjdat->bufflen); + if (pjdat->buff == NULL) { + log_msg(LOG_ERR, 1, "Out of memory."); + munmap(mapbuf, len); + return (-1); + } + } + + /* + * Helper routine to bridge to packJPG C++ lib, without changing packJPG itself. + */ + out = pjdat->buff; + if ((len = packjpg_filter_process(mapbuf, len, &out)) == 0) { + return (-1); + } + return (archive_write_data(fi->target_arc, out, len)); +} + diff --git a/archive/pc_arc_filter.h b/archive/pc_arc_filter.h new file mode 100644 index 0000000..40e9d9d --- /dev/null +++ b/archive/pc_arc_filter.h @@ -0,0 +1,53 @@ +/* + * This file is a part of Pcompress, a chunked parallel multi- + * algorithm lossless compression and decompression program. + * + * Copyright (C) 2012-2013 Moinak Ghosh. All rights reserved. + * Use is subject to license terms. + * + * This program is free software; you can redistribute it and/or + * modify it 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. + * + * This program 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. + * If not, see . + * + * moinakg@belenix.org, http://moinakg.wordpress.com/ + * + */ + +#ifndef _PC_ARCHIVE_FILTER_H +#define _PC_ARCHIVE_FILTER_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct filter_info { + struct archive *target_arc; + struct archive_entry *entry; + int fd; +}; + +typedef int (*filter_func_ptr)(struct filter_info *fi, void *filter_private); + +void add_filters_by_ext(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/archive/pc_archive.c b/archive/pc_archive.c index 333fa39..2be92c4 100644 --- a/archive/pc_archive.c +++ b/archive/pc_archive.c @@ -27,8 +27,8 @@ * This file includes all the archiving related functions. Pathnames are sorted * based on extension (or first 4 chars of name if no extension) and size. A simple * external merge sort is used. This sorting yields better compression ratio. - * - * Sorting is enabled for compression levels greater than 2. + * + * Sorting is enabled for compression levels greater than 6. */ #include #include @@ -45,10 +45,10 @@ #include #include #include -#include "pc_archive.h" #include #include #include +#include "pc_archive.h" #undef _FEATURES_H #define _XOPEN_SOURCE 700 @@ -60,6 +60,8 @@ pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER; static struct ext_hash_entry { uint64_t extnum; int type; + void *filter_private; + filter_func_ptr filter_func; } *exthtab = NULL; /* @@ -809,12 +811,11 @@ setup_extractor(pc_ctx_t *pctx) } /* - * Routines to archive members and write the archive to pipe. Most of the following - * code is adapted from some of the Libarchive bsdtar code. + * Routines to archive members and write the file data to the callback. Portions of + * the following code is adapted from some of the Libarchive bsdtar code. */ static int -copy_file_data(pc_ctx_t *pctx, struct archive *arc, - struct archive *in_arc, struct archive_entry *entry, int typ) +copy_file_data(pc_ctx_t *pctx, struct archive *arc, struct archive_entry *entry, int typ) { size_t sz, offset, len; ssize_t bytes_to_write; @@ -833,6 +834,10 @@ copy_file_data(pc_ctx_t *pctx, struct archive *arc, return (-1); } + /* + * Use mmap for copying file data. Not necessarily for performance, but it saves on + * resident memory use. + */ while (bytes_to_write > 0) { uchar_t *src; size_t wlen; @@ -843,6 +848,12 @@ copy_file_data(pc_ctx_t *pctx, struct archive *arc, else len = MMAP_SIZE; mapbuf = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, offset); + if (mapbuf == NULL) { + /* Mmap failed; this is bad. */ + log_msg(LOG_ERR, 1, "Mmap failed for %s.", fpath); + rv = -1; + break; + } offset += len; src = mapbuf; wlen = len; @@ -852,7 +863,7 @@ copy_file_data(pc_ctx_t *pctx, struct archive *arc, /* * Write the entire mmap-ed buffer. Since we are writing to the compressor - * stage pipe there is no need for blocking. + * stage there is no need for blocking. */ wrtn = archive_write_data(arc, src, wlen); if (wrtn < wlen) { @@ -870,8 +881,7 @@ copy_file_data(pc_ctx_t *pctx, struct archive *arc, } static int -write_entry(pc_ctx_t *pctx, struct archive *arc, struct archive *in_arc, - struct archive_entry *entry, int typ) +write_entry(pc_ctx_t *pctx, struct archive *arc, struct archive_entry *entry, int typ) { int rv; @@ -888,7 +898,7 @@ write_entry(pc_ctx_t *pctx, struct archive *arc, struct archive *in_arc, } if (archive_entry_size(entry) > 0) { - return (copy_file_data(pctx, arc, in_arc, entry, typ)); + return (copy_file_data(pctx, arc, entry, typ)); } return (0); @@ -999,7 +1009,7 @@ archiver_thread_func(void *dat) { archive_entry_linkify(resolver, &entry, &spare_entry); ent = entry; while (ent != NULL) { - if (write_entry(pctx, arc, ard, ent, typ) != 0) { + if (write_entry(pctx, arc, ent, typ) != 0) { goto done; } ent = spare_entry; @@ -1037,58 +1047,58 @@ start_archiver(pc_ctx_t *pctx) { static int copy_data_out(struct archive *ar, struct archive *aw) { - int64_t offset; - const void *buff; - size_t size; - int r; + int64_t offset; + const void *buff; + size_t size; + int r; - for (;;) { - r = archive_read_data_block(ar, &buff, &size, &offset); - if (r == ARCHIVE_EOF) - return (ARCHIVE_OK); - if (r != ARCHIVE_OK) - return (r); - r = (int)archive_write_data_block(aw, buff, size, offset); - if (r < ARCHIVE_WARN) - r = ARCHIVE_WARN; - if (r != ARCHIVE_OK) { - archive_set_error(ar, archive_errno(aw), - "%s", archive_error_string(aw)); - return (r); - } - } + for (;;) { + r = archive_read_data_block(ar, &buff, &size, &offset); + if (r == ARCHIVE_EOF) + return (ARCHIVE_OK); + if (r != ARCHIVE_OK) + return (r); + r = (int)archive_write_data_block(aw, buff, size, offset); + if (r < ARCHIVE_WARN) + r = ARCHIVE_WARN; + if (r != ARCHIVE_OK) { + archive_set_error(ar, archive_errno(aw), + "%s", archive_error_string(aw)); + return (r); + } + } } static int archive_extract_entry(struct archive *a, struct archive_entry *entry, struct archive *ad) { - int r, r2; - - r = archive_write_header(ad, entry); - if (r < ARCHIVE_WARN) - r = ARCHIVE_WARN; - if (r != ARCHIVE_OK) - /* If _write_header failed, copy the error. */ - archive_copy_error(a, ad); - else if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) > 0) - /* Otherwise, pour data into the entry. */ - r = copy_data_out(a, ad); - r2 = archive_write_finish_entry(ad); - if (r2 < ARCHIVE_WARN) - r2 = ARCHIVE_WARN; - /* Use the first message. */ - if (r2 != ARCHIVE_OK && r == ARCHIVE_OK) - archive_copy_error(a, ad); - /* Use the worst error return. */ - if (r2 < r) - r = r2; - return (r); + int r, r2; + + r = archive_write_header(ad, entry); + if (r < ARCHIVE_WARN) + r = ARCHIVE_WARN; + if (r != ARCHIVE_OK) + /* If _write_header failed, copy the error. */ + archive_copy_error(a, ad); + else if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) > 0) + /* Otherwise, pour data into the entry. */ + r = copy_data_out(a, ad); + r2 = archive_write_finish_entry(ad); + if (r2 < ARCHIVE_WARN) + r2 = ARCHIVE_WARN; + /* Use the first message. */ + if (r2 != ARCHIVE_OK && r == ARCHIVE_OK) + archive_copy_error(a, ad); + /* Use the worst error return. */ + if (r2 < r) + r = r2; + return (r); } /* - * Extract Thread function. Read an uncompressed archive from the pipe and extract - * members to disk. The decompressor writes to the other end of the pipe. + * Extract Thread function. Read an uncompressed archive from the decompressor stage + * and extract members to disk. */ static void * extractor_thread_func(void *dat) { @@ -1241,7 +1251,11 @@ init_archive_mod() { extnum = (extnum << 1) | extlist[i].ext[j]; exthtab[slot].extnum = extnum; exthtab[slot].type = extlist[i].type; + exthtab[slot].filter_func = NULL; + exthtab[slot].filter_private = NULL; } + + add_filters_by_ext(); inited = 1; } else { rv = 1; @@ -1270,7 +1284,7 @@ detect_type_by_ext(char *path, int pathlen) if (len == 0) goto out; // If extension is empty give up ext = &path[i+1]; slot = phash(ext, len); - if (slot > PHASHNKEYS) goto out; // Extension maps outside hash table range, give up + if (slot >= PHASHNKEYS) goto out; // Extension maps outside hash table range, give up extnum = 0; /* @@ -1326,3 +1340,16 @@ detect_type_by_data(uchar_t *buf, size_t len) return (TYPE_UNKNOWN); } + +int +insert_filter_data(filter_func_ptr func, void *filter_private, const char *ext) +{ + ub4 slot = phash(ext, strlen(ext)); + if (slot >= PHASHNKEYS || slot < 0) { + log_msg(LOG_WARN, 0, "Cannot add filter for unknown extension: %s", ext); + return (-1); + } + exthtab[slot].filter_func = func; + exthtab[slot].filter_private = filter_private; + return (0); +} diff --git a/archive/pc_archive.h b/archive/pc_archive.h index 1a71ca4..31d8753 100644 --- a/archive/pc_archive.h +++ b/archive/pc_archive.h @@ -23,13 +23,14 @@ * */ -#ifndef _ARCHIVE_H -#define _ARCHIVE_H +#ifndef _PC_ARCHIVE_H +#define _PC_ARCHIVE_H #include #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -52,6 +53,7 @@ int64_t archiver_read(void *ctx, void *buf, uint64_t count); int64_t archiver_write(void *ctx, void *buf, uint64_t count); int archiver_close(void *ctx); int init_archive_mod(); +int insert_filter_data(filter_func_ptr func, void *filter_private, const char *ext); #ifdef __cplusplus } diff --git a/archive/pjpg_helper.cpp b/archive/pjpg_helper.cpp new file mode 100644 index 0000000..10fa59c --- /dev/null +++ b/archive/pjpg_helper.cpp @@ -0,0 +1,58 @@ +/* + * This file is a part of Pcompress, a chunked parallel multi- + * algorithm lossless compression and decompression program. + * + * Copyright (C) 2012-2013 Moinak Ghosh. All rights reserved. + * Use is subject to license terms. + * + * This program is free software; you can redistribute it and/or + * modify it 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. + * + * This program 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. + * If not, see . + * + * moinakg@belenix.org, http://moinakg.wordpress.com/ + * + */ + +/* + */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned char uchar_t; + +size_t +packjpg_filter_process(uchar_t *in_buf, size_t len, uchar_t **out_buf) +{ + unsigned int len1; + + pjglib_init_streams(in_buf, 1, len, *out_buf, 1); + len1 = len; + if (!pjglib_convert_stream2mem(out_buf, &len1, NULL)) + return (0); + if (len1 == len) + return (0); + return (len1); +} + +#ifdef __cplusplus +} +#endif diff --git a/delta2/delta2.c b/filters/delta2/delta2.c similarity index 100% rename from delta2/delta2.c rename to filters/delta2/delta2.c diff --git a/delta2/delta2.h b/filters/delta2/delta2.h similarity index 100% rename from delta2/delta2.h rename to filters/delta2/delta2.h diff --git a/lzp/lzp.c b/filters/lzp/lzp.c similarity index 100% rename from lzp/lzp.c rename to filters/lzp/lzp.c diff --git a/lzp/lzp.h b/filters/lzp/lzp.h similarity index 100% rename from lzp/lzp.h rename to filters/lzp/lzp.h diff --git a/filters/packjpg/Readme.txt b/filters/packjpg/Readme.txt new file mode 100644 index 0000000..1e8f56e --- /dev/null +++ b/filters/packjpg/Readme.txt @@ -0,0 +1,256 @@ +packJPG v2.5g (09/14/2013) +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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...2013 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 + + +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 homepage of packJPG is currently maintained by Hochschule +Aalen staff. + +packJPG logo and icon are designed by Michael Kaufmann. + + +Contact +~~~~~~~ + +The official home of packJPG: + http://www.elektronik.htw-aalen.de/packjpg/ + +For questions and bug reports: + packjpg (at) htw-aalen.de + + +____________________________________ +packJPG by Matthias Stirner, 09/2013 diff --git a/filters/packjpg/aricoder.cpp b/filters/packjpg/aricoder.cpp new file mode 100644 index 0000000..64b9da2 --- /dev/null +++ b/filters/packjpg/aricoder.cpp @@ -0,0 +1,1044 @@ +#include +#include "bitops.h" +#include "aricoder.h" + +#define ERROR_EXIT { error = true; exit( 0 ); } + + +/* ----------------------------------------------- + constructor for aricoder class + ----------------------------------------------- */ + +aricoder::aricoder( iostream* stream, int iomode ) +{ + // iomode (i/o mode) + // 0 -> reading + // 1 -> writing + + int i; + + // set initial values + ccode = 0; + clow = 0; + chigh = CODER_LIMIT100 - 1; + cstep = 0; + bbyte = 0; + cbit = 0; + nrbits = 0; + + // store pointer to iostream for reading/writing + sptr = stream; + + // store i/o mode + mode = iomode; + + if ( mode == 0 ) { // mode is reading / decoding + // code buffer has to be filled before starting decoding + for ( i = 0; i < CODER_USE_BITS; i++ ) + ccode = ( ccode << 1 ) | read_bit(); + } // mode is writing / encoding otherwise +} + +/* ----------------------------------------------- + destructor for aricoder class + ----------------------------------------------- */ + +aricoder::~aricoder( void ) +{ + if ( mode == 1 ) { // mode is writing / encoding + // due to clow < CODER_LIMIT050, and chigh >= CODER_LIMIT050 + // there are only two possible cases + if ( clow < CODER_LIMIT025 ) { // case a.) + write_bit( 0 ); + // write remaining bits + write_bit( 1 ); + while ( nrbits-- > 0 ) + write_bit( 1 ); + } + else { // case b.), clow >= CODER_LIMIT025 + write_bit( 1 ); + } // done, zeroes are auto-read by the decoder + + // pad code with zeroes + while ( cbit > 0 ) write_bit( 0 ); + } +} + +/* ----------------------------------------------- + arithmetic encoder function + ----------------------------------------------- */ + +void aricoder::encode( symbol* s ) +{ + // update steps, low count, high count + cstep = ( ( chigh - clow ) + 1 ) / s->scale; + chigh = clow + ( cstep * s->high_count ) - 1; + clow = clow + ( cstep * s->low_count ); + + // e3 scaling is performed for speed and to avoid underflows + // if both, low and high are either in the lower half or in the higher half + // one bit can be safely shifted out + while ( ( clow >= CODER_LIMIT050 ) || ( chigh < CODER_LIMIT050 ) ) { + if ( chigh < CODER_LIMIT050 ) { // this means both, high and low are below, and 0 can be safely shifted out + // write 0 bit + write_bit( 0 ); + // shift out remaing e3 bits + for ( ; nrbits > 0; nrbits-- ) + write_bit( 1 ); + } + else { // if the first wasn't the case, it's clow >= CODER_LIMIT050 + // write 1 bit + write_bit( 1 ); + clow &= CODER_LIMIT050 - 1; + chigh &= CODER_LIMIT050 - 1; + // shift out remaing e3 bits + for ( ; nrbits > 0; nrbits-- ) + write_bit( 0 ); + } + clow <<= 1; + chigh <<= 1; + chigh++; + } + + // e3 scaling, to make sure that theres enough space between low and high + while ( ( clow >= CODER_LIMIT025 ) && ( chigh < CODER_LIMIT075 ) ) { + nrbits++; + clow &= CODER_LIMIT025 - 1; + chigh ^= CODER_LIMIT025 + CODER_LIMIT050; + // clow -= CODER_LIMIT025; + // chigh -= CODER_LIMIT025; + clow <<= 1; + chigh <<= 1; + chigh++; + } +} + +/* ----------------------------------------------- + arithmetic decoder get count function + ----------------------------------------------- */ + +unsigned int aricoder::decode_count( symbol* s ) +{ + // update cstep, which is needed to remove the symbol from the stream later + cstep = ( ( chigh - clow ) + 1 ) / s->scale; + + // return counts, needed to decode the symbol from the statistical model + return ( ccode - clow ) / cstep; +} + +/* ----------------------------------------------- + arithmetic decoder function + ----------------------------------------------- */ + +void aricoder::decode( symbol* s ) +{ + // no actual decoding takes place, as this has to happen in the statistical model + // the symbol has to be removed from the stream, though + + // alread have steps updated from decoder_count + // update low count and high count + chigh = clow + ( cstep * s->high_count ) - 1; + clow = clow + ( cstep * s->low_count ); + + // e3 scaling is performed for speed and to avoid underflows + // if both, low and high are either in the lower half or in the higher half + // one bit can be safely shifted out + while ( ( clow >= CODER_LIMIT050 ) || ( chigh < CODER_LIMIT050 ) ) { + if ( clow >= CODER_LIMIT050 ) { + clow &= CODER_LIMIT050 - 1; + chigh &= CODER_LIMIT050 - 1; + ccode &= CODER_LIMIT050 - 1; + } // if the first wasn't the case, it's chigh < CODER_LIMIT050 + clow <<= 1; + chigh <<= 1; + chigh++; + ccode <<= 1; + ccode |= read_bit(); + nrbits = 0; + } + + // e3 scaling, to make sure that theres enough space between low and high + while ( ( clow >= CODER_LIMIT025 ) && ( chigh < CODER_LIMIT075 ) ) { + nrbits++; + clow &= CODER_LIMIT025 - 1; + chigh ^= CODER_LIMIT025 + CODER_LIMIT050; + // clow -= CODER_LIMIT025; + // chigh -= CODER_LIMIT025; + ccode -= CODER_LIMIT025; + clow <<= 1; + chigh <<= 1; + chigh++; + ccode <<= 1; + ccode |= read_bit(); + } +} + +/* ----------------------------------------------- + bit writer function + ----------------------------------------------- */ + +void aricoder::write_bit( unsigned char bit ) +{ + // add bit at last position + bbyte = ( bbyte << 1 ) | bit; + // increment bit position + cbit++; + + // write bit if done + if ( cbit == 8 ) { + sptr->write( (void*) &bbyte, 1, 1 ); + cbit = 0; + } +} + +/* ----------------------------------------------- + bit reader function + ----------------------------------------------- */ + +unsigned char aricoder::read_bit( void ) +{ + // read in new byte if needed + if ( cbit == 0 ) { + if ( sptr->read( &bbyte, 1, 1 ) == 0 ) // read next byte if available + bbyte = 0; // if no more data is left in the stream + cbit = 8; + } + + // decrement current bit position + cbit--; + // return bit at cbit position + return BITN( bbyte, cbit ); +} + + +/* ----------------------------------------------- + universal statistical model for arithmetic coding + ----------------------------------------------- */ + +model_s::model_s( int max_s, int max_c, int max_o, int c_lim ) +{ + // boundaries of this model: + // max_s (maximum symbol) -> 1 <= max_s <= 1024 (???) + // max_c (maximum context) -> 1 <= max_c <= 1024 (???) + // max_o (maximum order) -> -1 <= max_o <= 4 + // c_lim (maximum count) -> 2 <= c_lim <= 4096 (???) + // WARNING: this can be memory intensive, so don't overdo it + // max_s == 256; max_c == 256; max_o == 4 would be way too much + + table_s* null_table; + table_s* start_table; + int i; + + + // set error false + error = false; + + // copy settings into model + max_symbol = max_s; + max_context = max_c; + max_order = max_o; + max_count = c_lim; + + + // alloc memory for totals table + // totals = ( unsigned short* ) calloc( max_symbol + 2, sizeof( short ) ); + totals = ( unsigned int* ) calloc( max_symbol + 2, sizeof( int ) ); + + // alloc memory for scoreboard, set sb0_count + scoreboard = ( char* ) calloc( max_symbol, sizeof( char ) ); + sb0_count = max_symbol; + + // set current order + current_order = max_order; + + + // set up null table + null_table = ( table_s* ) calloc( 1, sizeof( table_s ) ); + if ( null_table == NULL ) ERROR_EXIT; + null_table->counts = ( unsigned short* ) calloc( max_symbol, sizeof( short ) ); + if ( null_table->counts == NULL ) ERROR_EXIT; + for ( i = 0; i < max_symbol; i++ ) + null_table->counts[ i ] = 1; // set all probabilities + // set up internal counts + null_table->max_count = 1; + null_table->max_symbol = max_symbol; + + // set up start table + start_table = ( table_s* ) calloc( 1, sizeof( table_s ) ); + if ( start_table == NULL ) ERROR_EXIT; + start_table->links = ( table_s** ) calloc( max_context, sizeof( table_s* ) ); + if ( start_table->links == NULL ) ERROR_EXIT; + // set up internal counts + start_table->max_count = 0; + start_table->max_symbol = 0; + + // build links for start table & null table + start_table->lesser = null_table; + null_table->links = ( table_s** ) calloc( max_context, sizeof( table_s* ) ); + if ( null_table->links == NULL ) ERROR_EXIT; + for ( i = 0; i < max_context; i++ ) + null_table->links[ i ] = start_table; + + // alloc memory for storage & contexts + storage = ( table_s** ) calloc( max_order + 2, sizeof( table_s* ) ); + if ( storage == NULL ) ERROR_EXIT; + contexts = storage + 1; + + // integrate tables into contexts + contexts[ -1 ] = null_table; + contexts[ 0 ] = start_table; + + // build initial 'normal' tables + for ( i = 1; i <= max_order; i++ ) { + // set up current order table + contexts[ i ] = ( table_s* ) calloc( 1, sizeof( table_s ) ); + if ( contexts[ i ] == NULL ) ERROR_EXIT; + contexts[ i ]->max_count = 0; + contexts[ i ]->max_symbol = 0; + // build forward and backward links + contexts[ i ]->lesser = contexts[ i - 1 ]; + if ( i < max_order ) { + contexts[ i ]->links = ( table_s** ) calloc( max_context, sizeof( table_s* ) ); + if ( contexts[ i ]->links == NULL ) ERROR_EXIT; + } + else { + contexts[ i ]->links = NULL; + } + contexts[ i - 1 ]->links[ 0 ] = contexts[ i ]; + } +} + + +/* ----------------------------------------------- + model class destructor - recursive cleanup of memory is done here + ----------------------------------------------- */ + +model_s::~model_s( void ) +{ + table_s* context; + + + // clean up each 'normal' table + context = contexts[ 0 ]; + recursive_cleanup ( context ); + + // clean up null table + context = contexts[ -1 ]; + if ( context->links != NULL ) + free( context->links ); + if ( context->counts != NULL ) free( context->counts ); + free ( context ); + + // free everything else + free( storage ); + free( totals ); + free( scoreboard ); +} + + +/* ----------------------------------------------- + updates statistics for a specific symbol / resets to highest order + ----------------------------------------------- */ + +void model_s::update_model( int symbol ) +{ + // use -1 if you just want to reset without updating statistics + + table_s* context; + unsigned short* counts; + int local_order; + int i; + + + // only contexts, that were actually used to encode + // the symbol get their counts updated + if ( symbol >= 0 ) { + for ( local_order = ( current_order < 0 ) ? 0 : current_order; + local_order <= max_order; local_order++ ) { + context = contexts[ local_order ]; + counts = context->counts + symbol; + // update count for specific symbol & scale + (*counts)++; + // store side information for totalize_table + if ( (*counts) > context->max_count ) context->max_count = (*counts); + if ( symbol >= context->max_symbol ) context->max_symbol = symbol+1; + // if counts for that symbol have gone above the maximum count + // the table has to be resized (scale factor 2) + if ( (*counts) >= max_count ) + rescale_table( context, 1 ); + } + } + + // reset scoreboard and current order + current_order = max_order; + for ( i = 0; i < max_symbol; i++ ) + scoreboard[ i ] = 0; + sb0_count = max_symbol; +} + + +/* ----------------------------------------------- + shift in one context (max no of contexts is max_c) + ----------------------------------------------- */ + +void model_s::shift_context( int c ) +{ + table_s* context; + int i; + + // shifting is not possible if max_order is below 1 + // or context index is negative + if ( ( max_order < 1 ) || ( c < 0 ) ) return; + + // shift each orders' context + for ( i = max_order; i > 0; i-- ) { + // this is the new current order context + context = contexts[ i - 1 ]->links[ c ]; + + // check if context exists, build if needed + if ( context == NULL ) { + // reserve memory for next table_s + context = ( table_s* ) calloc( 1, sizeof( table_s ) ); + if ( context == NULL ) ERROR_EXIT; + // set counts NULL + context->counts = NULL; + // setup internal counts + context->max_count = 0; + context->max_symbol = 0; + // link lesser context later if not existing, this is done below + context->lesser = contexts[ i - 2 ]->links[ c ]; + // finished here if this is a max order context + if ( i == max_order ) + context->links = NULL; + else { + // build links to higher order tables otherwise + context->links = ( table_s** ) calloc( max_context, sizeof( table_s* ) ); + if ( context->links == NULL ) ERROR_EXIT; + // add lesser link for higher context (see above) + contexts[ i + 1 ]->lesser = context; + } + // put context to its right place + contexts[ i - 1 ]->links[ c ] = context; + } + + // switch context + contexts[ i ] = context; + } +} + + +/* ----------------------------------------------- + flushes the whole model by diviging through a specific scale factor + ----------------------------------------------- */ + +void model_s::flush_model( int scale_factor ) +{ + recursive_flush( contexts[ 0 ], scale_factor ); +} + + +/* ----------------------------------------------- + exclude specific symbols using this function + ----------------------------------------------- */ + +void model_s::exclude_symbols( char rule, int c ) +{ + // exclusions are back to normal after update_model is used + // modify scoreboard according to rule and value + switch ( rule ) + { + case 'a': + // above rule + // every symbol above c is excluded + for ( c = c + 1; c < max_symbol; c++ ) { + if ( scoreboard[ c ] == 0 ) { + scoreboard[ c ] = 1; + sb0_count--; + } + } + break; + + case 'b': + // below rule + // every symbol below c is excluded + for ( c = c - 1; c >= 0; c-- ) { + if ( scoreboard[ c ] == 0 ) { + scoreboard[ c ] = 1; + sb0_count--; + } + } + break; + + case 'e': + // equal rule + // only c is excluded + if ( scoreboard[ c ] == 0 ) { + scoreboard[ c ] = 1; + sb0_count--; + } + break; + + default: + // unknown rule + // do nothing + break; + } +} + + +/* ----------------------------------------------- + converts an int to a symbol, needed only when encoding + ----------------------------------------------- */ + +int model_s::convert_int_to_symbol( int c, symbol *s ) +{ + // search the symbol c in the current context table_s, + // return scale, low- and high counts + + table_s* context; + + + // totalize table for the current context + context = contexts[ current_order ]; + totalize_table( context ); + + // finding the scale is easy + s->scale = totals[ 0 ]; + + // check if that symbol exists in the current table. send escape otherwise + if ( c >= 0 ) { + if ( context->counts[ c ] > 0 ) { + // return high and low count for the current symbol + s->low_count = totals[ c + 2 ]; + s->high_count = totals[ c + 1 ]; + return 0; + } + } + + // return high and low count for the escape symbol + s->low_count = totals[ 1 ]; + s->high_count = totals[ 0 ]; + current_order--; + return 1; +} + + +/* ----------------------------------------------- + returns the current context scale needed only when decoding + ----------------------------------------------- */ + +void model_s::get_symbol_scale( symbol *s ) +{ + // getting the scale is easy: totalize the table_s, use accumulated count -> done + totalize_table( contexts[ current_order ] ); + s->scale = totals[ 0 ]; +} + + +/* ----------------------------------------------- + converts a count to an int, called after get_symbol_scale + ----------------------------------------------- */ + +int model_s::convert_symbol_to_int( int count, symbol *s ) +{ + // seek the symbol that matches the count, + // also, set low- and high count for the symbol - it has to be removed from the stream + + int c; + + // go through the totals table, search the symbol that matches the count + for ( c = 1; count < (signed) totals[ c ]; c++ ); + // set up the current symbol + s->low_count = totals[ c ]; + s->high_count = totals[ c - 1 ]; + // send escape if escape symbol encountered + if ( c == 1 ) { + current_order--; + return ESCAPE_SYMBOL; + } + + // return symbol value + return ( c - 2 ); +} + + +/* ----------------------------------------------- + totals are calculated by accumulating counts in the current table_s + ----------------------------------------------- */ + +void model_s::totalize_table( table_s *context ) +{ + // update exclusion is used, so this has to be done each time + // escape probability calculation also takes place here + + // accumulated counts must never exceed CODER_MAXSCALE + // as CODER_MAXSCALE is big enough, though, (2^29), this shouldn't happen and is not checked + + unsigned short* counts; + signed int local_symb; + unsigned int curr_total; + unsigned int curr_count; + unsigned int esc_prob; + int i; + + // make a local copy of the pointer + counts = context->counts; + + // check counts + if ( counts != NULL ) { // if counts are already set + // locally store current fill/symbol count + local_symb = sb0_count; + + // set the last symbol of the totals table_s zero + i = context->max_symbol - 1; + totals[ i + 2 ] = 0; + // (re)set current total + curr_total = 0; + + // go reverse though the whole counts table and accumulate counts + // leave space at the beginning of the table for the escape symbol + for ( ; i >= 0; i-- ) { + // only count probability if the current symbol is not 'scoreboard - excluded' + if ( scoreboard[ i ] == 0 ) { + curr_count = counts[ i ]; + if ( curr_count > 0 ) { + // add counts for the current symbol + curr_total = curr_total + curr_count; + // exclude symbol from scoreboard + scoreboard[ i ] = 1; + sb0_count--; + } + } + totals[ i + 1 ] = curr_total; + } + // here the escape calculation needs to take place + if ( local_symb == sb0_count ) + esc_prob = 1; + else if ( sb0_count == 0 ) + esc_prob = 0; + else { + // esc_prob = 1; + esc_prob = sb0_count * ( local_symb - sb0_count ); + esc_prob /= ( local_symb * context->max_count ); + esc_prob++; + } + // include escape probability in totals table + totals[ 0 ] = totals[ 1 ] + esc_prob; + } + else { // if counts are not already set + // setup counts for current table + context->counts = ( unsigned short* ) calloc( max_symbol, sizeof( short ) ); + if ( context->counts == NULL ) ERROR_EXIT; + // set totals table -> only escape probability included + totals[ 0 ] = 1; + totals[ 1 ] = 0; + } +} + + +/* ----------------------------------------------- + resizes one table by bitshifting each count using a specific value + ----------------------------------------------- */ + +inline void model_s::rescale_table( table_s* context, int scale_factor ) +{ + unsigned short* counts = context->counts; + int lst_symbol = context->max_symbol; + int i; + + // return now if counts not set + if ( counts == NULL ) return; + + // now scale the table by bitshifting each count + for ( i = 0; i < lst_symbol; i++ ) { + if ( counts[ i ] > 0 ) + counts[ i ] >>= scale_factor; + } + + // also rescale tables max count + context->max_count >>= scale_factor; + + // seek for new last symbol + for ( i = lst_symbol - 1; i >= 0; i-- ) + if ( counts[ i ] > 0 ) break; + context->max_symbol = i + 1; +} + + +/* ----------------------------------------------- + a recursive function to go through each context and rescale the counts + ----------------------------------------------- */ + +inline void model_s::recursive_flush( table_s* context, int scale_factor ) +{ + int i; + + // go through each link != NULL + if ( context->links != NULL ) + for ( i = 0; i < max_context; i++ ) + if ( context->links[ i ] != NULL ) + recursive_flush( context->links[ i ], scale_factor ); + + // rescale specific table + rescale_table( context, scale_factor ); +} + + +/* ----------------------------------------------- + frees all memory for all contexts starting at a given table_s + ----------------------------------------------- */ + +inline void model_s::recursive_cleanup( table_s *context ) +{ + // be careful not to cut any link too early! + + int i; + + // go through each link != NULL + if ( context->links != NULL ) { + for ( i = 0; i < max_context; i++ ) + if ( context->links[ i ] != NULL ) + recursive_cleanup( context->links[ i ] ); + free ( context->links ); + } + + // clean up table + if ( context->counts != NULL ) free ( context->counts ); + free( context ); +} + + +/* ----------------------------------------------- + special version of model_s for binary coding + ----------------------------------------------- */ + +model_b::model_b( int max_c, int max_o, int c_lim ) +{ + // boundaries of this model: + // ... (maximum symbol) -> 2 (0 or 1 ) + // max_c (maximum context) -> 1 <= max_c <= 1024 (???) + // max_o (maximum order) -> -1 <= max_o <= 4 + + table* null_table; + table* start_table; + int i; + + + // set error false + error = false; + + // copy settings into model + max_context = max_c; + max_order = max_o; + max_count = c_lim; + + + // set up null table + null_table = ( table* ) calloc( 1, sizeof( table ) ); + if ( null_table == NULL ) ERROR_EXIT; + + null_table->counts = ( unsigned short* ) calloc( 2, sizeof( short ) ); + if ( null_table->counts == NULL ) ERROR_EXIT; + null_table->counts[ 0 ] = 1; + null_table->counts[ 1 ] = 1; + null_table->scale = 2; + + // set up start table + start_table = ( table* ) calloc( 1, sizeof( table ) ); + if ( start_table == NULL ) ERROR_EXIT; + start_table->links = ( table** ) calloc( max_context, sizeof( table* ) ); + if ( start_table->links == NULL ) ERROR_EXIT; + start_table->scale = 0; + + // build links for start table & null table + start_table->lesser = null_table; + null_table->links = ( table** ) calloc( max_context, sizeof( table* ) ); + if ( null_table->links == NULL ) ERROR_EXIT; + for ( i = 0; i < max_context; i++ ) + null_table->links[ i ] = start_table; + + // alloc memory for storage & contexts + storage = ( table** ) calloc( max_order + 2, sizeof( table* ) ); + if ( storage == NULL ) ERROR_EXIT; + contexts = storage + 1; + + // integrate tables into contexts + contexts[ -1 ] = null_table; + contexts[ 0 ] = start_table; + + // build initial 'normal' tables + for ( i = 1; i <= max_order; i++ ) { + // set up current order table + contexts[ i ] = ( table* ) calloc( 1, sizeof( table ) ); + if ( contexts[ i ] == NULL ) ERROR_EXIT; + contexts[ i ]->scale = 0; + // build forward and backward links + contexts[ i ]->lesser = contexts[ i - 1 ]; + if ( i < max_order ) { + contexts[ i ]->links = ( table** ) calloc( max_context, sizeof( table* ) ); + if ( contexts[ i ]->links == NULL ) ERROR_EXIT; + } + else { + contexts[ i ]->links = NULL; + } + contexts[ i - 1 ]->links[ 0 ] = contexts[ i ]; + } +} + + +/* ----------------------------------------------- + model class destructor - recursive cleanup of memory is done here + ----------------------------------------------- */ + +model_b::~model_b( void ) +{ + table* context; + + + // clean up each 'normal' table + context = contexts[ 0 ]; + recursive_cleanup ( context ); + + // clean up null table + context = contexts[ -1 ]; + if ( context->links != NULL ) + free( context->links ); + if ( context->counts != NULL ) free( context->counts ); + free ( context ); + + // free everything else + free( storage ); +} + + +/* ----------------------------------------------- + updates statistics for a specific symbol / resets to highest order + ----------------------------------------------- */ + +void model_b::update_model( int symbol ) +{ + // use -1 if you just want to reset without updating statistics + + table* context = contexts[ max_order ]; + + // only contexts, that were actually used to encode + // the symbol get their counts updated + if ( ( symbol >= 0 ) && ( max_order >= 0 ) ) { + // update count for specific symbol & scale + context->counts[ symbol ]++; + context->scale++; + // if counts for that symbol have gone above the maximum count + // the table has to be resized (scale factor 2) + if ( context->counts[ symbol ] >= max_count ) + rescale_table( context, 1 ); + } +} + + +/* ----------------------------------------------- + shift in one context (max no of contexts is max_c) + ----------------------------------------------- */ + +void model_b::shift_context( int c ) +{ + table* context; + int i; + + // shifting is not possible if max_order is below 1 + // or context index is negative + if ( ( max_order < 1 ) || ( c < 0 ) ) return; + + // shift each orders' context + for ( i = max_order; i > 0; i-- ) { + // this is the new current order context + context = contexts[ i - 1 ]->links[ c ]; + + // check if context exists, build if needed + if ( context == NULL ) { + // reserve memory for next table + context = ( table* ) calloc( 1, sizeof( table ) ); + if ( context == NULL ) ERROR_EXIT; + // set internal counts NULL + context->counts = NULL; + context->scale = 0; + // link lesser context later if not existing, this is done below + context->lesser = contexts[ i - 2 ]->links[ c ]; + // finished here if this is a max order context + if ( i == max_order ) { + context->links = NULL; + } + else { + // build links to higher order tables otherwise + context->links = ( table** ) calloc( max_context, sizeof( table* ) ); + if ( context->links == NULL ) ERROR_EXIT; + // add lesser link for higher context (see above) + contexts[ i + 1 ]->lesser = context; + } + // put context to its right place + contexts[ i - 1 ]->links[ c ] = context; + } + + // switch context + contexts[ i ] = context; + } +} + + +/* ----------------------------------------------- + flushes the whole model by dividing through a specific scale factor + ----------------------------------------------- */ + +void model_b::flush_model( int scale_factor ) +{ + recursive_flush( contexts[ 0 ], scale_factor ); +} + + +/* ----------------------------------------------- + converts an int to a symbol, needed only when encoding + ----------------------------------------------- */ + +int model_b::convert_int_to_symbol( int c, symbol *s ) +{ + table* context = contexts[ max_order ]; + + // check if counts are available + check_counts( context ); + + // finding the scale is easy + s->scale = context->scale; + + // return high and low count for current symbol + if ( c == 0 ) { // if 0 is to be encoded + s->low_count = 0; + s->high_count = context->counts[ 0 ]; + } + else { // if 1 is to be encoded + s->low_count = context->counts[ 0 ]; + s->high_count = context->scale; + } + + return 1; +} + + +/* ----------------------------------------------- + returns the current context scale needed only when decoding + ----------------------------------------------- */ + +void model_b::get_symbol_scale( symbol *s ) +{ + table* context = contexts[ max_order ]; + + // check if counts are available + check_counts( context ); + + // getting the scale is easy + s->scale = context->scale; +} + + +/* ----------------------------------------------- + converts a count to an int, called after get_symbol_scale + ----------------------------------------------- */ + +int model_b::convert_symbol_to_int( int count, symbol *s ) +{ + table* context = contexts[ max_order ]; + unsigned short counts0 = context->counts[ 0 ]; + + // set up the current symbol + if ( count < counts0 ) { + s->low_count = 0; + s->high_count = counts0; + return 0; + } + else { + s->low_count = counts0; + s->high_count = s->scale; + return 1; + } +} + + +/* ----------------------------------------------- + this function checks if counts exist, and, if they exist and are below max + ----------------------------------------------- */ + +inline void model_b::check_counts( table *context ) +{ + unsigned short* counts = context->counts; + + // check if counts are available + if ( counts == NULL ) { + // setup counts for current table + counts = ( unsigned short* ) calloc( 2, sizeof( short ) ); + if ( counts == NULL ) ERROR_EXIT; + counts[ 0 ] = 1; + counts[ 1 ] = 1; + // set scale + context->counts = counts; + context->scale = 2; + } +} + + +/* ----------------------------------------------- + resizes one table by bitshifting each count using a specific value + ----------------------------------------------- */ + +inline void model_b::rescale_table( table* context, int scale_factor ) +{ + unsigned short* counts = context->counts; + + // return now if counts not set + if ( counts == NULL ) return; + + // now scale the table by bitshifting each count, be careful not to set any count zero + counts[ 0 ] >>= scale_factor; + counts[ 1 ] >>= scale_factor; + if ( counts[ 0 ] == 0 ) counts[ 0 ] = 1; + if ( counts[ 1 ] == 0 ) counts[ 1 ] = 1; + context->scale = counts[ 0 ] + counts[ 1 ]; +} + + +/* ----------------------------------------------- + a recursive function to go through each context and rescale the counts + ----------------------------------------------- */ + +inline void model_b::recursive_flush( table* context, int scale_factor ) +{ + int i; + + // go through each link != NULL + if ( context->links != NULL ) + for ( i = 0; i < max_context; i++ ) + if ( context->links[ i ] != NULL ) + recursive_flush( context->links[ i ], scale_factor ); + + // rescale specific table + rescale_table( context, scale_factor ); +} + + +/* ----------------------------------------------- + frees all memory for all contexts starting at a given table + ----------------------------------------------- */ + +inline void model_b::recursive_cleanup( table *context ) +{ + int i; + + // go through each link != NULL + if ( context->links != NULL ) { + for ( i = 0; i < max_context; i++ ) + if ( context->links[ i ] != NULL ) + recursive_cleanup( context->links[ i ] ); + free ( context->links ); + } + + // clean up table + if ( context->counts != NULL ) free ( context->counts ); + free( context ); +} diff --git a/filters/packjpg/aricoder.h b/filters/packjpg/aricoder.h new file mode 100644 index 0000000..97c6271 --- /dev/null +++ b/filters/packjpg/aricoder.h @@ -0,0 +1,268 @@ +// defines for coder +#define CODER_USE_BITS 31 // must never be above 31 +#define CODER_LIMIT100 ( (unsigned int) ( 1 << CODER_USE_BITS ) ) +#define CODER_LIMIT025 ( ( CODER_LIMIT100 / 4 ) * 1 ) +#define CODER_LIMIT050 ( ( CODER_LIMIT100 / 4 ) * 2 ) +#define CODER_LIMIT075 ( ( CODER_LIMIT100 / 4 ) * 3 ) +#define CODER_MAXSCALE CODER_LIMIT025 - 1 +#define ESCAPE_SYMBOL CODER_LIMIT025 + + +// symbol struct, used in arithmetic coding +struct symbol { + unsigned int low_count; + unsigned int high_count; + unsigned int scale; +}; + +// table struct, used in in statistical models, +// holding all info needed for one context +struct table { + // counts for each symbol contained in the table + unsigned short* counts; + // links to higher order contexts + struct table** links; + // link to lower order context + struct table* lesser; + // accumulated counts + unsigned int scale; +}; + +// special table struct, used in in model_s, +// holding additional info for a speedier 'totalize_table' +struct table_s { + // counts for each symbol contained in the table + unsigned short* counts; + // links to higher order contexts + struct table_s** links; + // link to lower order context + struct table_s* lesser; + // speedup info + unsigned short max_count; + unsigned short max_symbol; + // unsigned short esc_prob; +}; + + +/* ----------------------------------------------- + class for arithmetic coding of data to/from iostream + ----------------------------------------------- */ + +class aricoder +{ + public: + aricoder( iostream* stream, int iomode ); + ~aricoder( void ); + void encode( symbol* s ); + unsigned int decode_count( symbol* s ); + void decode( symbol* s ); + + private: + // bitwise operations + void write_bit( unsigned char bit ); + unsigned char read_bit( void ); + + // i/o variables + iostream* sptr; + int mode; + unsigned char bbyte; + unsigned char cbit; + + // arithmetic coding variables + unsigned int ccode; + unsigned int clow; + unsigned int chigh; + unsigned int cstep; + unsigned int nrbits; +}; + + +/* ----------------------------------------------- + universal statistical model for arithmetic coding + ----------------------------------------------- */ + +class model_s +{ + public: + + model_s( int max_s, int max_c, int max_o, int c_lim ); + ~model_s( void ); + + void update_model( int symbol ); + void shift_context( int c ); + void flush_model( int scale_factor ); + void exclude_symbols( char rule, int c ); + + int convert_int_to_symbol( int c, symbol *s ); + void get_symbol_scale( symbol *s ); + int convert_symbol_to_int( int count, symbol *s ); + + bool error; + + + private: + + // unsigned short* totals; + unsigned int* totals; + char* scoreboard; + int sb0_count; + table_s **contexts; + table_s **storage; + + int max_symbol; + int max_context; + int current_order; + int max_order; + int max_count; + + inline void totalize_table(table_s* context ); + inline void rescale_table(table_s* context, int scale_factor ); + inline void recursive_flush(table_s* context, int scale_factor ); + inline void recursive_cleanup(table_s* context ); +}; + + +/* ----------------------------------------------- + binary statistical model for arithmetic coding + ----------------------------------------------- */ + +class model_b +{ + public: + + model_b( int max_c, int max_o, int c_lim ); + ~model_b( void ); + + void update_model( int symbol ); + void shift_context( int c ); + void flush_model( int scale_factor ); + + int convert_int_to_symbol( int c, symbol *s ); + void get_symbol_scale( symbol *s ); + int convert_symbol_to_int( int count, symbol *s ); + + bool error; + + + private: + + table **contexts; + table **storage; + + int max_context; + int max_order; + int max_count; + + inline void check_counts( table *context ); + inline void rescale_table( table* context, int scale_factor ); + inline void recursive_flush( table* context, int scale_factor ); + inline void recursive_cleanup( table *context ); +}; + + +/* ----------------------------------------------- + shift context x2 model_s function + ----------------------------------------------- */ +static inline void shift_model( model_s* model, int ctx1, int ctx2 ) +{ + model->shift_context( ctx1 ); + model->shift_context( ctx2 ); +} + + +/* ----------------------------------------------- + shift context x3 model_s function + ----------------------------------------------- */ +static inline void shift_model( model_s* model, int ctx1, int ctx2, int ctx3 ) +{ + model->shift_context( ctx1 ); + model->shift_context( ctx2 ); + model->shift_context( ctx3 ); +} + + +/* ----------------------------------------------- + shift context x2 model_b function + ----------------------------------------------- */ +static inline void shift_model( model_b* model, int ctx1, int ctx2 ) +{ + model->shift_context( ctx1 ); + model->shift_context( ctx2 ); +} + + +/* ----------------------------------------------- + shift context x3 model_b function + ----------------------------------------------- */ +static inline void shift_model( model_b* model, int ctx1, int ctx2, int ctx3 ) +{ + model->shift_context( ctx1 ); + model->shift_context( ctx2 ); + model->shift_context( ctx3 ); +} + + +/* ----------------------------------------------- + generic model_s encoder function + ----------------------------------------------- */ +static inline void encode_ari( aricoder* encoder, model_s* model, int c ) +{ + static symbol s; + static int esc; + + do { + esc = model->convert_int_to_symbol( c, &s ); + encoder->encode( &s ); + } while ( esc ); + model->update_model( c ); +} + +/* ----------------------------------------------- + generic model_s decoder function + ----------------------------------------------- */ +static inline int decode_ari( aricoder* decoder, model_s* model ) +{ + static symbol s; + static unsigned int count; + static int c; + + do{ + model->get_symbol_scale( &s ); + count = decoder->decode_count( &s ); + c = model->convert_symbol_to_int( count, &s ); + decoder->decode( &s ); + } while ( c == ESCAPE_SYMBOL ); + model->update_model( c ); + + return c; +} + +/* ----------------------------------------------- + generic model_b encoder function + ----------------------------------------------- */ +static inline void encode_ari( aricoder* encoder, model_b* model, int c ) +{ + static symbol s; + + model->convert_int_to_symbol( c, &s ); + encoder->encode( &s ); + model->update_model( c ); +} + +/* ----------------------------------------------- + generic model_b decoder function + ----------------------------------------------- */ +static inline int decode_ari( aricoder* decoder, model_b* model ) +{ + static symbol s; + static unsigned int count; + static int c; + + model->get_symbol_scale( &s ); + count = decoder->decode_count( &s ); + c = model->convert_symbol_to_int( count, &s ); + decoder->decode( &s ); + model->update_model( c ); + + return c; +} diff --git a/filters/packjpg/bitops.cpp b/filters/packjpg/bitops.cpp new file mode 100644 index 0000000..b86585e --- /dev/null +++ b/filters/packjpg/bitops.cpp @@ -0,0 +1,910 @@ +/* +This file contains special classes for bitwise +reading and writing of arrays +*/ + +#include +#include +#include +#include "bitops.h" + +#define BUFFER_SIZE 1024 * 1024 + + +/* ----------------------------------------------- + constructor for abitreader class + ----------------------------------------------- */ + +abitreader::abitreader( unsigned char* array, int size ) +{ + cbyte = 0; + cbit = 8; + peof = 0; + eof = false; + + data = array; + lbyte = size; +} + +/* ----------------------------------------------- + destructor for abitreader class + ----------------------------------------------- */ + +abitreader::~abitreader( void ) +{ +} + +/* ----------------------------------------------- + reads n bits from abitreader + ----------------------------------------------- */ + +unsigned int abitreader::read( int nbits ) +{ + unsigned int retval = 0; + + // safety check for eof + if ( eof ) { + peof += nbits; + return 0; + } + + while ( nbits >= cbit ) { + nbits -= cbit; + retval |= ( RBITS( data[cbyte], cbit ) << nbits ); + cbit = 8; + if ( ++cbyte >= lbyte ) { + peof = nbits; + eof = true; + return retval; + } + } + + if ( nbits > 0 ) { + retval |= ( MBITS( data[cbyte], cbit, (cbit-nbits) ) ); + cbit -= nbits; + } + + return retval; +} + +/* ----------------------------------------------- + reads one bit from abitreader + ----------------------------------------------- */ + +unsigned char abitreader::read_bit( void ) +{ + unsigned char bit; + + // safety check for eof + if (eof) { + peof++; + return 0; + } + + // read one bit + bit = BITN( data[cbyte], --cbit ); + if ( cbit == 0 ) { + if ( ++cbyte == lbyte ) eof = true; + cbit = 8; + } + + return bit; +} + +/* ----------------------------------------------- + to skip padding from current byte + ----------------------------------------------- */ + +unsigned char abitreader::unpad( unsigned char fillbit ) +{ + if ( ( cbit == 8 ) || eof ) return fillbit; + else { + fillbit = read( 1 ); + while ( cbit != 8 ) read( 1 ); + } + + return fillbit; +} + +/* ----------------------------------------------- + get current position in array + ----------------------------------------------- */ + +int abitreader::getpos( void ) +{ + return cbyte; +} + +/* ----------------------------------------------- + get current bit position + ----------------------------------------------- */ + +int abitreader::getbitp( void ) +{ + return cbit; +} + +/* ----------------------------------------------- + set byte and bit position + ----------------------------------------------- */ + +void abitreader::setpos( int pbyte, int pbit ) +{ + if ( pbyte < lbyte ) { + // reset eof + eof = false; + // set positions + cbyte = pbyte; + cbit = pbit; + } else { + // set eof + eof = true; + // set positions + cbyte = lbyte; + cbit = 8; + peof = ( ( pbyte - lbyte ) * 8 ) + 8 - pbit; + } +} + +/* ----------------------------------------------- + rewind n bits + ----------------------------------------------- */ + +void abitreader::rewind_bits( int nbits ) +{ + if ( eof ) { + if ( nbits > peof ) nbits -= peof; + else { + peof -= nbits; + return; + } + eof = false; + } + for ( cbit += nbits; cbit > 8; cbyte--, cbit -= 8 ); + if ( cbyte < 0 ) { + cbyte = 0; + cbit = 8; + } +} + + +/* ----------------------------------------------- + constructor for abitwriter class + ----------------------------------------------- */ + +abitwriter::abitwriter( int size ) +{ + fillbit = 1; + adds = 65536; + cbyte = 0; + cbit = 8; + + error = false; + fmem = true; + + dsize = ( size > 0 ) ? size : adds; + data = ( unsigned char* ) malloc ( dsize ); + if ( data == NULL ) { + error = true; + return; + } + + // fill buffer with zeroes + memset( data, 0, dsize * sizeof( char ) ); + // for ( int i = 0; i < dsize; i++ ) data[i] = 0; +} + +/* ----------------------------------------------- + destructor for abitwriter class + ----------------------------------------------- */ + +abitwriter::~abitwriter( void ) +{ + // free memory if pointer was not given out + if ( fmem ) free( data ); +} + +/* ----------------------------------------------- + writes n bits to abitwriter + ----------------------------------------------- */ + +void abitwriter::write( unsigned int val, int nbits ) +{ + // safety check for error + if ( error ) return; + + // test if pointer beyond flush treshold + if ( cbyte > ( dsize - 5 ) ) { + dsize += adds; + data = (unsigned char*) realloc( data, dsize ); + if ( data == NULL ) { + error = true; + return; + } + memset( ( data + cbyte + 1 ), 0, ( dsize - ( cbyte + 1 ) ) * sizeof( char ) ); + } + + // write data + while ( nbits >= cbit ) { + data[cbyte] |= ( MBITS32(val, nbits, (nbits-cbit)) ); + nbits -= cbit; + cbyte++; + cbit = 8; + } + + if ( nbits > 0 ) { + data[cbyte] |= ( (RBITS32(val, nbits)) << (cbit - nbits) ); + cbit -= nbits; + } +} + +/* ----------------------------------------------- + writes one bit to abitwriter + ----------------------------------------------- */ + +void abitwriter::write_bit( unsigned char bit ) +{ + // safety check for error + if ( error ) return; + + // write data + if ( bit ) data[cbyte] |= 0x1 << (--cbit); + else --cbit; + if ( cbit == 0 ) { + // test if pointer beyond flush treshold + if ( ++cbyte > ( dsize - 5 ) ) { + dsize += adds; + data = (unsigned char*) realloc( data, dsize ); + if ( data == NULL ) { + error = true; + return; + } + memset( ( data + cbyte + 1 ), 0, ( dsize - ( cbyte + 1 ) ) * sizeof( char ) ); + } + cbit = 8; + } +} + +/* ----------------------------------------------- + pads data using fillbit + ----------------------------------------------- */ + +void abitwriter::pad( unsigned char fillbit ) +{ + while ( cbit < 8 ) + write( fillbit, 1 ); +} + +/* ----------------------------------------------- + gets data array from abitwriter + ----------------------------------------------- */ + +unsigned char* abitwriter::getptr( void ) +{ + // data is padded here + pad( fillbit ); + // forbid freeing memory + fmem = false; + // realloc data + data = (unsigned char*) realloc( data, cbyte ); + + return data; +} + +/* ----------------------------------------------- + gets size of data array from abitwriter + ----------------------------------------------- */ + +int abitwriter::getpos( void ) +{ + return cbyte; +} + +/* ----------------------------------------------- + get current bit position + ----------------------------------------------- */ + +int abitwriter::getbitp( void ) +{ + return cbit; +} + + +/* ----------------------------------------------- + constructor for abytewriter class + ----------------------------------------------- */ + +abytereader::abytereader( unsigned char* array, int size ) +{ + cbyte = 0; + eof = false; + + data = array; + lbyte = size; + + if ( ( data == NULL ) || ( lbyte == 0 ) ) + eof = true; +} + +/* ----------------------------------------------- + destructor for abytewriter class + ----------------------------------------------- */ + +abytereader::~abytereader( void ) +{ +} + +/* ----------------------------------------------- + reads 1 byte from abytereader + ----------------------------------------------- */ + +int abytereader::read( unsigned char* byte ) +{ + if ( cbyte >= lbyte ) { + cbyte = lbyte; + eof = true; + return 0; + } + else { + *byte = data[ cbyte++ ]; + return 1; + } +} + +/* ----------------------------------------------- + reads n bytes from abytereader + ----------------------------------------------- */ + +int abytereader::read_n( unsigned char* byte, int n ) +{ + int nl = lbyte - cbyte; + int i; + + if ( nl < n ) { + for ( i = 0; i < nl; i++ ) + byte[ i ] = data[ cbyte + i ]; + cbyte = lbyte; + eof = true; + return nl; + } + else { + for ( i = 0; i < n; i++ ) + byte[ i ] = data[ cbyte + i ]; + cbyte += n; + return n; + } +} + +/* ----------------------------------------------- + go to position in data + ----------------------------------------------- */ + +void abytereader::seek( int pos ) +{ + if ( pos >= lbyte ) { + cbyte = lbyte; + eof = true; + } + else { + cbyte = pos; + eof = false; + } +} + +/* ----------------------------------------------- + gets size of current data + ----------------------------------------------- */ + +int abytereader::getsize( void ) +{ + return lbyte; +} + +/* ----------------------------------------------- + gets current position from abytereader + ----------------------------------------------- */ + +int abytereader::getpos( void ) +{ + return cbyte; +} + + +/* ----------------------------------------------- + constructor for abytewriter class + ----------------------------------------------- */ + +abytewriter::abytewriter( int size ) +{ + adds = 65536; + cbyte = 0; + + error = false; + fmem = true; + + dsize = ( size > 0 ) ? size : adds; + data = (unsigned char*) malloc( dsize ); + if ( data == NULL ) { + error = true; + return; + } +} + +/* ----------------------------------------------- + destructor for abytewriter class + ----------------------------------------------- */ + +abytewriter::~abytewriter( void ) +{ + // free data if pointer is not read + if ( fmem ) free( data ); +} + +/* ----------------------------------------------- + writes 1 byte to abytewriter + ----------------------------------------------- */ + +void abytewriter::write( unsigned char byte ) +{ + // safety check for error + if ( error ) return; + + // test if pointer beyond flush threshold + if ( cbyte >= ( dsize - 2 ) ) { + dsize += adds; + data = (unsigned char*) realloc( data, dsize ); + if ( data == NULL ) { + error = true; + return; + } + } + + // write data + data[ cbyte++ ] = byte; +} + +/* ----------------------------------------------- + writes n byte to abytewriter + ----------------------------------------------- */ + +void abytewriter::write_n( unsigned char* byte, int n ) +{ + // safety check for error + if ( error ) return; + + // make sure that pointer doesn't get beyond flush threshold + while ( ( cbyte + n ) >= ( dsize - 2 ) ) { + dsize += adds; + data = (unsigned char*) realloc( data, dsize ); + if ( data == NULL ) { + error = true; + return; + } + } + + // copy data from array + while ( n-- > 0 ) + data[ cbyte++ ] = *(byte++); +} + +/* ----------------------------------------------- + gets data array from abytewriter + ----------------------------------------------- */ + +unsigned char* abytewriter::getptr( void ) +{ + // safety check for error + if ( error ) return NULL; + // forbid freeing memory + fmem = false; + // realloc data + data = (unsigned char*) realloc( data, cbyte ); + + return data; +} + +/* ----------------------------------------------- + peeks into data array from abytewriter + ----------------------------------------------- */ + +unsigned char* abytewriter::peekptr( void ) +{ + return data; +} + +/* ----------------------------------------------- + gets size of data array from abytewriter + ----------------------------------------------- */ + +int abytewriter::getpos( void ) +{ + return cbyte; +} + +/* ----------------------------------------------- + reset without realloc + ----------------------------------------------- */ + +void abytewriter::reset( void ) +{ + // set position of current byte + cbyte = 0; +} + + +/* ----------------------------------------------- + constructor for iostream class + ----------------------------------------------- */ + +iostream::iostream( void* src, int srctype, int srcsize, int iomode ) +{ + // locally copy source, source type # and io mode # + source = src; + srct = srctype; + srcs = srcsize; + mode = iomode; + + // don't free memory when reading - this will be useful if switching occurs + free_mem_sw = false; + + // set binary mode for streams + #if defined( _WIN32 ) + setmode( fileno( stdin ), O_BINARY ); + setmode( fileno( stdout ), O_BINARY ); + #endif + + // open file/mem/stream + switch ( srct ) + { + case 0: + open_file(); + break; + + case 1: + open_mem(); + break; + + case 2: + open_stream(); + break; + + default: + break; + } +} + +/* ----------------------------------------------- + destructor for iostream class + ----------------------------------------------- */ + +iostream::~iostream( void ) +{ + // if needed, write memory to stream or free memory from buffered stream + if ( srct == 2 ) { + if ( mode == 1 ) { + if ( !(mwrt->error) ) { + srcs = mwrt->getpos(); + source = mwrt->getptr(); + fwrite( source, sizeof( char ), srcs, stdout ); + } + } + } + + // free all buffers + if ( srct == 0 ) { + if ( fptr != NULL ) + fclose( fptr ); + } + else if ( mode == 0 ) { + if ( free_mem_sw ) + free( source ); + delete( mrdr ); + } + else + delete( mwrt ); +} + +/* ----------------------------------------------- + switches mode from reading to writing and vice versa + ----------------------------------------------- */ + +void iostream::switch_mode( void ) +{ + // return immediately if there's an error + if ( chkerr() ) return; + + + if ( mode == 0 ) { + // WARNING: when switching from reading to writing, information might be lost forever + switch ( srct ) { + case 0: + fclose( fptr ); + fptr = fopen( ( char* ) source, "wb" ); + break; + case 1: + case 2: + delete( mrdr ); + if ( free_mem_sw ) + free( source ); // see? I've told you so :-) + mwrt = new abytewriter( srcs ); + break; + default: + break; + } + mode = 1; + } + else { + // switching from writing to reading is a bit more complicated + switch ( srct ) { + case 0: + fclose( fptr ); + fptr = fopen( ( char* ) source, "rb" ); + break; + case 1: + case 2: + source = mwrt->getptr(); + srcs = mwrt->getpos(); + delete( mwrt ); + mrdr = new abytereader( ( unsigned char* ) source, srcs ); + free_mem_sw = true; + break; + default: + break; + } + mode = 0; + } +} + +/* ----------------------------------------------- + generic read function + ----------------------------------------------- */ + +int iostream::read( void* to, int tpsize, int dtsize ) +{ + return ( srct == 0 ) ? read_file( to, tpsize, dtsize ) : read_mem( to, tpsize, dtsize ); +} + +/* ----------------------------------------------- + generic write function + ----------------------------------------------- */ + +int iostream::write( void* from, int tpsize, int dtsize ) +{ + return ( srct == 0 ) ? write_file( from, tpsize, dtsize ) : write_mem( from, tpsize, dtsize ); +} + +/* ----------------------------------------------- + flush function + ----------------------------------------------- */ + +int iostream::flush( void ) +{ + if ( srct == 0 ) + fflush( fptr ); + + return getpos(); +} + +/* ----------------------------------------------- + rewind to beginning of stream + ----------------------------------------------- */ + +int iostream::rewind( void ) +{ + // WARNING: when writing, rewind might lose all your data + if ( srct == 0 ) + fseek( fptr, 0, SEEK_SET ); + else if ( mode == 0 ) + mrdr->seek( 0 ); + else + mwrt->reset(); + + return getpos(); +} + +/* ----------------------------------------------- + get current position in stream + ----------------------------------------------- */ + +int iostream::getpos( void ) +{ + int pos; + + if ( srct == 0 ) + pos = ftell( fptr ); + else if ( mode == 0 ) + pos = mrdr->getpos(); + else + pos = mwrt->getpos(); + + return pos; +} + +/* ----------------------------------------------- + get size of file + ----------------------------------------------- */ + +int iostream::getsize( void ) +{ + int pos; + int siz; + + if ( mode == 0 ) { + if ( srct == 0 ) { + pos = ftell( fptr ); + fseek( fptr, 0, SEEK_END ); + siz = ftell( fptr ); + fseek( fptr, pos, SEEK_SET ); + } + else { + siz = mrdr->getsize(); + } + } + else { + siz = getpos(); + } + + return siz; +} + +/* ----------------------------------------------- + get data pointer (for mem io only) + ----------------------------------------------- */ + +unsigned char* iostream::getptr( void ) +{ + if ( srct == 1 ) + return ( mode == 0 ) ? ( unsigned char* ) source : mwrt->getptr(); + else + return NULL; +} + +/* ----------------------------------------------- + check for errors + ----------------------------------------------- */ + +bool iostream::chkerr( void ) +{ + bool error = false; + + // check for user input errors + if ( ( mode != 0 ) && ( mode != 1 ) ) + error = true; + if ( ( srct != 0 ) && ( srct != 1 ) && ( srct != 2 ) ) + error = true; + + // check for io errors + if ( srct == 0 ) { + if ( fptr == NULL ) + error = true; + else if ( ferror( fptr ) ) + error = true; + } + else if ( mode == 0 ) { + if ( mrdr == NULL ) + error = true; + } + else { + if ( mwrt == NULL ) + error = true; + else if ( mwrt->error ) + error = true; + } + + return error; +} + +/* ----------------------------------------------- + check for eof (read only) + ----------------------------------------------- */ + +bool iostream::chkeof( void ) +{ + if ( mode == 0 ) + return ( srct == 0 ) ? feof( fptr ) : mrdr->eof; + else + return false; +} + +/* ----------------------------------------------- + open function for files + ----------------------------------------------- */ + +void iostream::open_file( void ) +{ + char* fn = (char*) source; + + // open file for reading / writing + fptr = fopen( fn, ( mode == 0 ) ? "rb" : "wb" ); +} + +/* ----------------------------------------------- + open function for memory + ----------------------------------------------- */ + +void iostream::open_mem( void ) +{ + if ( mode == 0 ) + mrdr = new abytereader( ( unsigned char* ) source, srcs ); + else + mwrt = new abytewriter( srcs ); +} + +/* ----------------------------------------------- + open function for streams + ----------------------------------------------- */ + +void iostream::open_stream( void ) +{ + abytewriter* strwrt; + unsigned char* buffer; + int i; + + if ( mode == 0 ) { + // read whole stream into memory buffer + strwrt = new abytewriter( 0 ); + buffer = ( unsigned char* ) calloc( BUFFER_SIZE, sizeof( char ) ); + if ( buffer != NULL ) { + while ( ( i = fread( buffer, sizeof( char ), BUFFER_SIZE, stdin ) ) > 0 ) + strwrt->write_n( buffer, i ); + } + if ( strwrt->error ) { + source = NULL; + srcs = 0; + } + else { + source = strwrt->getptr(); + srcs = strwrt->getpos(); + } + delete ( strwrt ); + free( buffer ); + // free memory after done + free_mem_sw = true; + } + + // for writing: simply open new stream in mem writer + // writing to stream will be done later + open_mem(); +} + +/* ----------------------------------------------- + write function for files + ----------------------------------------------- */ + +int iostream::write_file( void* from, int tpsize, int dtsize ) +{ + return fwrite( from, tpsize, dtsize, fptr ); +} + +/* ----------------------------------------------- + read function for files + ----------------------------------------------- */ + +int iostream::read_file( void* to, int tpsize, int dtsize ) +{ + return fread( to, tpsize, dtsize, fptr ); +} + +/* ----------------------------------------------- + write function for memory + ----------------------------------------------- */ + +int iostream::write_mem( void* from, int tpsize, int dtsize ) +{ + int n = tpsize * dtsize; + + mwrt->write_n( ( unsigned char* ) from, n ); + + return ( mwrt->error ) ? 0 : n; +} + +/* ----------------------------------------------- + read function for memory + ----------------------------------------------- */ + +int iostream::read_mem( void* to, int tpsize, int dtsize ) +{ + int n = tpsize * dtsize; + + return ( mrdr->read_n( ( unsigned char* ) to, n ) ) / tpsize; +} diff --git a/filters/packjpg/bitops.h b/filters/packjpg/bitops.h new file mode 100644 index 0000000..4a2b079 --- /dev/null +++ b/filters/packjpg/bitops.h @@ -0,0 +1,169 @@ +#define RBITS( c, n ) ( c & ( 0xFF >> (8 - n) ) ) +#define LBITS( c, n ) ( c >> (8 - n) ) +#define MBITS( c, l, r ) ( RBITS( c,l ) >> r ) +#define RBITS16( c, n ) ( c & ( 0xFFFFFFFF >> (16 - n) ) ) +#define LBITS16( c, n ) ( c >> (16 - n) ) +#define MBITS16( c, l, r ) ( RBITS16( c,l ) >> r ) +#define RBITS32( c, n ) ( c & ( 0xFFFFFFFF >> (32 - n) ) ) +#define LBITS32( c, n ) ( c >> (32 - n) ) +#define MBITS32( c, l, r ) ( RBITS32( c,l ) >> r ) +#define BITN( c, n ) ( (c >> n) & 0x1 ) +#define BITLEN( l, v ) for ( l = 0; ( v >> l ) > 0; l++ ) +#define FDIV2( v, p ) ( ( v < 0 ) ? -( (-v) >> p ) : ( v >> p ) ) + +#define TYPE_FILE 0 +#define TYPE_MEMORY 1 +#define TYPE_STREAM 2 +#define MODE_READ 0 +#define MODE_WRITE 1 + +#define BTST_BUFF 1024 * 1024 + +#include + +/* ----------------------------------------------- + class to read arrays bitwise + ----------------------------------------------- */ + +class abitreader +{ +public: + abitreader( unsigned char* array, int size ); + ~abitreader( void ); + unsigned int read( int nbits ); + unsigned char read_bit( void ); + unsigned char unpad( unsigned char fillbit ); + int getpos( void ); + int getbitp( void ); + void setpos( int pbyte, int pbit ); + void rewind_bits( int nbits ); + bool eof; + int peof; + +private: + unsigned char* data; + int lbyte; + int cbyte; + int cbit; +}; + + +/* ----------------------------------------------- + class to write arrays bitwise + ----------------------------------------------- */ + +class abitwriter +{ +public: + abitwriter( int size ); + ~abitwriter( void ); + void write( unsigned int val, int nbits ); + void write_bit( unsigned char bit ); + void pad ( unsigned char fillbit ); + unsigned char* getptr( void ); + int getpos( void ); + int getbitp( void ); + bool error; + unsigned char fillbit; + +private: + unsigned char* data; + int dsize; + int adds; + int lbyte; + int cbyte; + int cbit; + bool fmem; +}; + + +/* ----------------------------------------------- + class to read arrays bytewise + ----------------------------------------------- */ + +class abytereader +{ +public: + abytereader( unsigned char* array, int size ); + ~abytereader( void ); + int read( unsigned char* byte ); + int read_n( unsigned char* byte, int n ); + void seek( int pos ); + int getsize( void ); + int getpos( void ); + bool eof; + +private: + unsigned char* data; + int lbyte; + int cbyte; +}; + + +/* ----------------------------------------------- + class to write arrays bytewise + ----------------------------------------------- */ + +class abytewriter +{ +public: + abytewriter( int size ); + ~abytewriter( void ); + void write( unsigned char byte ); + void write_n( unsigned char* byte, int n ); + unsigned char* getptr( void ); + unsigned char* peekptr( void ); + int getpos( void ); + void reset( void ); + bool error; + +private: + unsigned char* data; + int dsize; + int adds; + int lbyte; + int cbyte; + bool fmem; +}; + + +/* ----------------------------------------------- + class for input and output from file or memory + ----------------------------------------------- */ + +class iostream +{ +public: + iostream( void* src, int srctype, int srcsize, int iomode ); + ~iostream( void ); + void switch_mode( void ); + int read( void* to, int tpsize, int dtsize ); + int write( void* from, int tpsize, int dtsize ); + int flush( void ); + int rewind( void ); + int getpos( void ); + int getsize( void ); + unsigned char* getptr( void ); + bool chkerr( void ); + bool chkeof( void ); + +private: + void open_file( void ); + void open_mem( void ); + void open_stream( void ); + + int write_file( void* from, int tpsize, int dtsize ); + int read_file( void* to, int tpsize, int dtsize ); + int write_mem( void* from, int tpsize, int dtsize ); + int read_mem( void* to, int tpsize, int dtsize ); + + FILE* fptr; + abytewriter* mwrt; + abytereader* mrdr; + + bool free_mem_sw; + void* source; + int mode; + int srct; + int srcs; +}; diff --git a/filters/packjpg/dct8x8.h b/filters/packjpg/dct8x8.h new file mode 100644 index 0000000..25fcead --- /dev/null +++ b/filters/packjpg/dct8x8.h @@ -0,0 +1,1166 @@ +#define DCT_RSC_FACTOR 8192 +#define DCT_RESCALE( v ) ( ( ( v > 0 ) ? ( v + (DCT_RSC_FACTOR/2) ) : ( v - (DCT_RSC_FACTOR/2) ) ) / DCT_RSC_FACTOR ) + + +// precalculated int values for 8x8 IDCT, multplied by 8192 +const int icos_idct_8x8[ 4096 ] = +{ + 1024, 1420, 1338, 1204, 1024, 805, 554, 283, + 1420, 1970, 1856, 1670, 1420, 1116, 769, 392, + 1338, 1856, 1748, 1573, 1338, 1051, 724, 369, + 1204, 1670, 1573, 1416, 1204, 946, 652, 332, + 1024, 1420, 1338, 1204, 1024, 805, 554, 283, + 805, 1116, 1051, 946, 805, 632, 435, 222, + 554, 769, 724, 652, 554, 435, 300, 153, + 283, 392, 369, 332, 283, 222, 153, 78, + 1024, 1204, 554, -283, -1024, -1420, -1338, -805, + 1420, 1670, 769, -392, -1420, -1970, -1856, -1116, + 1338, 1573, 724, -369, -1338, -1856, -1748, -1051, + 1204, 1416, 652, -332, -1204, -1670, -1573, -946, + 1024, 1204, 554, -283, -1024, -1420, -1338, -805, + 805, 946, 435, -222, -805, -1116, -1051, -632, + 554, 652, 300, -153, -554, -769, -724, -435, + 283, 332, 153, -78, -283, -392, -369, -222, + 1024, 805, -554, -1420, -1024, 283, 1338, 1204, + 1420, 1116, -769, -1970, -1420, 392, 1856, 1670, + 1338, 1051, -724, -1856, -1338, 369, 1748, 1573, + 1204, 946, -652, -1670, -1204, 332, 1573, 1416, + 1024, 805, -554, -1420, -1024, 283, 1338, 1204, + 805, 632, -435, -1116, -805, 222, 1051, 946, + 554, 435, -300, -769, -554, 153, 724, 652, + 283, 222, -153, -392, -283, 78, 369, 332, + 1024, 283, -1338, -805, 1024, 1204, -554, -1420, + 1420, 392, -1856, -1116, 1420, 1670, -769, -1970, + 1338, 369, -1748, -1051, 1338, 1573, -724, -1856, + 1204, 332, -1573, -946, 1204, 1416, -652, -1670, + 1024, 283, -1338, -805, 1024, 1204, -554, -1420, + 805, 222, -1051, -632, 805, 946, -435, -1116, + 554, 153, -724, -435, 554, 652, -300, -769, + 283, 78, -369, -222, 283, 332, -153, -392, + 1024, -283, -1338, 805, 1024, -1204, -554, 1420, + 1420, -392, -1856, 1116, 1420, -1670, -769, 1970, + 1338, -369, -1748, 1051, 1338, -1573, -724, 1856, + 1204, -332, -1573, 946, 1204, -1416, -652, 1670, + 1024, -283, -1338, 805, 1024, -1204, -554, 1420, + 805, -222, -1051, 632, 805, -946, -435, 1116, + 554, -153, -724, 435, 554, -652, -300, 769, + 283, -78, -369, 222, 283, -332, -153, 392, + 1024, -805, -554, 1420, -1024, -283, 1338, -1204, + 1420, -1116, -769, 1970, -1420, -392, 1856, -1670, + 1338, -1051, -724, 1856, -1338, -369, 1748, -1573, + 1204, -946, -652, 1670, -1204, -332, 1573, -1416, + 1024, -805, -554, 1420, -1024, -283, 1338, -1204, + 805, -632, -435, 1116, -805, -222, 1051, -946, + 554, -435, -300, 769, -554, -153, 724, -652, + 283, -222, -153, 392, -283, -78, 369, -332, + 1024, -1204, 554, 283, -1024, 1420, -1338, 805, + 1420, -1670, 769, 392, -1420, 1970, -1856, 1116, + 1338, -1573, 724, 369, -1338, 1856, -1748, 1051, + 1204, -1416, 652, 332, -1204, 1670, -1573, 946, + 1024, -1204, 554, 283, -1024, 1420, -1338, 805, + 805, -946, 435, 222, -805, 1116, -1051, 632, + 554, -652, 300, 153, -554, 769, -724, 435, + 283, -332, 153, 78, -283, 392, -369, 222, + 1024, -1420, 1338, -1204, 1024, -805, 554, -283, + 1420, -1970, 1856, -1670, 1420, -1116, 769, -392, + 1338, -1856, 1748, -1573, 1338, -1051, 724, -369, + 1204, -1670, 1573, -1416, 1204, -946, 652, -332, + 1024, -1420, 1338, -1204, 1024, -805, 554, -283, + 805, -1116, 1051, -946, 805, -632, 435, -222, + 554, -769, 724, -652, 554, -435, 300, -153, + 283, -392, 369, -332, 283, -222, 153, -78, + 1024, 1420, 1338, 1204, 1024, 805, 554, 283, + 1204, 1670, 1573, 1416, 1204, 946, 652, 332, + 554, 769, 724, 652, 554, 435, 300, 153, + -283, -392, -369, -332, -283, -222, -153, -78, + -1024, -1420, -1338, -1204, -1024, -805, -554, -283, + -1420, -1970, -1856, -1670, -1420, -1116, -769, -392, + -1338, -1856, -1748, -1573, -1338, -1051, -724, -369, + -805, -1116, -1051, -946, -805, -632, -435, -222, + 1024, 1204, 554, -283, -1024, -1420, -1338, -805, + 1204, 1416, 652, -332, -1204, -1670, -1573, -946, + 554, 652, 300, -153, -554, -769, -724, -435, + -283, -332, -153, 78, 283, 392, 369, 222, + -1024, -1204, -554, 283, 1024, 1420, 1338, 805, + -1420, -1670, -769, 392, 1420, 1970, 1856, 1116, + -1338, -1573, -724, 369, 1338, 1856, 1748, 1051, + -805, -946, -435, 222, 805, 1116, 1051, 632, + 1024, 805, -554, -1420, -1024, 283, 1338, 1204, + 1204, 946, -652, -1670, -1204, 332, 1573, 1416, + 554, 435, -300, -769, -554, 153, 724, 652, + -283, -222, 153, 392, 283, -78, -369, -332, + -1024, -805, 554, 1420, 1024, -283, -1338, -1204, + -1420, -1116, 769, 1970, 1420, -392, -1856, -1670, + -1338, -1051, 724, 1856, 1338, -369, -1748, -1573, + -805, -632, 435, 1116, 805, -222, -1051, -946, + 1024, 283, -1338, -805, 1024, 1204, -554, -1420, + 1204, 332, -1573, -946, 1204, 1416, -652, -1670, + 554, 153, -724, -435, 554, 652, -300, -769, + -283, -78, 369, 222, -283, -332, 153, 392, + -1024, -283, 1338, 805, -1024, -1204, 554, 1420, + -1420, -392, 1856, 1116, -1420, -1670, 769, 1970, + -1338, -369, 1748, 1051, -1338, -1573, 724, 1856, + -805, -222, 1051, 632, -805, -946, 435, 1116, + 1024, -283, -1338, 805, 1024, -1204, -554, 1420, + 1204, -332, -1573, 946, 1204, -1416, -652, 1670, + 554, -153, -724, 435, 554, -652, -300, 769, + -283, 78, 369, -222, -283, 332, 153, -392, + -1024, 283, 1338, -805, -1024, 1204, 554, -1420, + -1420, 392, 1856, -1116, -1420, 1670, 769, -1970, + -1338, 369, 1748, -1051, -1338, 1573, 724, -1856, + -805, 222, 1051, -632, -805, 946, 435, -1116, + 1024, -805, -554, 1420, -1024, -283, 1338, -1204, + 1204, -946, -652, 1670, -1204, -332, 1573, -1416, + 554, -435, -300, 769, -554, -153, 724, -652, + -283, 222, 153, -392, 283, 78, -369, 332, + -1024, 805, 554, -1420, 1024, 283, -1338, 1204, + -1420, 1116, 769, -1970, 1420, 392, -1856, 1670, + -1338, 1051, 724, -1856, 1338, 369, -1748, 1573, + -805, 632, 435, -1116, 805, 222, -1051, 946, + 1024, -1204, 554, 283, -1024, 1420, -1338, 805, + 1204, -1416, 652, 332, -1204, 1670, -1573, 946, + 554, -652, 300, 153, -554, 769, -724, 435, + -283, 332, -153, -78, 283, -392, 369, -222, + -1024, 1204, -554, -283, 1024, -1420, 1338, -805, + -1420, 1670, -769, -392, 1420, -1970, 1856, -1116, + -1338, 1573, -724, -369, 1338, -1856, 1748, -1051, + -805, 946, -435, -222, 805, -1116, 1051, -632, + 1024, -1420, 1338, -1204, 1024, -805, 554, -283, + 1204, -1670, 1573, -1416, 1204, -946, 652, -332, + 554, -769, 724, -652, 554, -435, 300, -153, + -283, 392, -369, 332, -283, 222, -153, 78, + -1024, 1420, -1338, 1204, -1024, 805, -554, 283, + -1420, 1970, -1856, 1670, -1420, 1116, -769, 392, + -1338, 1856, -1748, 1573, -1338, 1051, -724, 369, + -805, 1116, -1051, 946, -805, 632, -435, 222, + 1024, 1420, 1338, 1204, 1024, 805, 554, 283, + 805, 1116, 1051, 946, 805, 632, 435, 222, + -554, -769, -724, -652, -554, -435, -300, -153, + -1420, -1970, -1856, -1670, -1420, -1116, -769, -392, + -1024, -1420, -1338, -1204, -1024, -805, -554, -283, + 283, 392, 369, 332, 283, 222, 153, 78, + 1338, 1856, 1748, 1573, 1338, 1051, 724, 369, + 1204, 1670, 1573, 1416, 1204, 946, 652, 332, + 1024, 1204, 554, -283, -1024, -1420, -1338, -805, + 805, 946, 435, -222, -805, -1116, -1051, -632, + -554, -652, -300, 153, 554, 769, 724, 435, + -1420, -1670, -769, 392, 1420, 1970, 1856, 1116, + -1024, -1204, -554, 283, 1024, 1420, 1338, 805, + 283, 332, 153, -78, -283, -392, -369, -222, + 1338, 1573, 724, -369, -1338, -1856, -1748, -1051, + 1204, 1416, 652, -332, -1204, -1670, -1573, -946, + 1024, 805, -554, -1420, -1024, 283, 1338, 1204, + 805, 632, -435, -1116, -805, 222, 1051, 946, + -554, -435, 300, 769, 554, -153, -724, -652, + -1420, -1116, 769, 1970, 1420, -392, -1856, -1670, + -1024, -805, 554, 1420, 1024, -283, -1338, -1204, + 283, 222, -153, -392, -283, 78, 369, 332, + 1338, 1051, -724, -1856, -1338, 369, 1748, 1573, + 1204, 946, -652, -1670, -1204, 332, 1573, 1416, + 1024, 283, -1338, -805, 1024, 1204, -554, -1420, + 805, 222, -1051, -632, 805, 946, -435, -1116, + -554, -153, 724, 435, -554, -652, 300, 769, + -1420, -392, 1856, 1116, -1420, -1670, 769, 1970, + -1024, -283, 1338, 805, -1024, -1204, 554, 1420, + 283, 78, -369, -222, 283, 332, -153, -392, + 1338, 369, -1748, -1051, 1338, 1573, -724, -1856, + 1204, 332, -1573, -946, 1204, 1416, -652, -1670, + 1024, -283, -1338, 805, 1024, -1204, -554, 1420, + 805, -222, -1051, 632, 805, -946, -435, 1116, + -554, 153, 724, -435, -554, 652, 300, -769, + -1420, 392, 1856, -1116, -1420, 1670, 769, -1970, + -1024, 283, 1338, -805, -1024, 1204, 554, -1420, + 283, -78, -369, 222, 283, -332, -153, 392, + 1338, -369, -1748, 1051, 1338, -1573, -724, 1856, + 1204, -332, -1573, 946, 1204, -1416, -652, 1670, + 1024, -805, -554, 1420, -1024, -283, 1338, -1204, + 805, -632, -435, 1116, -805, -222, 1051, -946, + -554, 435, 300, -769, 554, 153, -724, 652, + -1420, 1116, 769, -1970, 1420, 392, -1856, 1670, + -1024, 805, 554, -1420, 1024, 283, -1338, 1204, + 283, -222, -153, 392, -283, -78, 369, -332, + 1338, -1051, -724, 1856, -1338, -369, 1748, -1573, + 1204, -946, -652, 1670, -1204, -332, 1573, -1416, + 1024, -1204, 554, 283, -1024, 1420, -1338, 805, + 805, -946, 435, 222, -805, 1116, -1051, 632, + -554, 652, -300, -153, 554, -769, 724, -435, + -1420, 1670, -769, -392, 1420, -1970, 1856, -1116, + -1024, 1204, -554, -283, 1024, -1420, 1338, -805, + 283, -332, 153, 78, -283, 392, -369, 222, + 1338, -1573, 724, 369, -1338, 1856, -1748, 1051, + 1204, -1416, 652, 332, -1204, 1670, -1573, 946, + 1024, -1420, 1338, -1204, 1024, -805, 554, -283, + 805, -1116, 1051, -946, 805, -632, 435, -222, + -554, 769, -724, 652, -554, 435, -300, 153, + -1420, 1970, -1856, 1670, -1420, 1116, -769, 392, + -1024, 1420, -1338, 1204, -1024, 805, -554, 283, + 283, -392, 369, -332, 283, -222, 153, -78, + 1338, -1856, 1748, -1573, 1338, -1051, 724, -369, + 1204, -1670, 1573, -1416, 1204, -946, 652, -332, + 1024, 1420, 1338, 1204, 1024, 805, 554, 283, + 283, 392, 369, 332, 283, 222, 153, 78, + -1338, -1856, -1748, -1573, -1338, -1051, -724, -369, + -805, -1116, -1051, -946, -805, -632, -435, -222, + 1024, 1420, 1338, 1204, 1024, 805, 554, 283, + 1204, 1670, 1573, 1416, 1204, 946, 652, 332, + -554, -769, -724, -652, -554, -435, -300, -153, + -1420, -1970, -1856, -1670, -1420, -1116, -769, -392, + 1024, 1204, 554, -283, -1024, -1420, -1338, -805, + 283, 332, 153, -78, -283, -392, -369, -222, + -1338, -1573, -724, 369, 1338, 1856, 1748, 1051, + -805, -946, -435, 222, 805, 1116, 1051, 632, + 1024, 1204, 554, -283, -1024, -1420, -1338, -805, + 1204, 1416, 652, -332, -1204, -1670, -1573, -946, + -554, -652, -300, 153, 554, 769, 724, 435, + -1420, -1670, -769, 392, 1420, 1970, 1856, 1116, + 1024, 805, -554, -1420, -1024, 283, 1338, 1204, + 283, 222, -153, -392, -283, 78, 369, 332, + -1338, -1051, 724, 1856, 1338, -369, -1748, -1573, + -805, -632, 435, 1116, 805, -222, -1051, -946, + 1024, 805, -554, -1420, -1024, 283, 1338, 1204, + 1204, 946, -652, -1670, -1204, 332, 1573, 1416, + -554, -435, 300, 769, 554, -153, -724, -652, + -1420, -1116, 769, 1970, 1420, -392, -1856, -1670, + 1024, 283, -1338, -805, 1024, 1204, -554, -1420, + 283, 78, -369, -222, 283, 332, -153, -392, + -1338, -369, 1748, 1051, -1338, -1573, 724, 1856, + -805, -222, 1051, 632, -805, -946, 435, 1116, + 1024, 283, -1338, -805, 1024, 1204, -554, -1420, + 1204, 332, -1573, -946, 1204, 1416, -652, -1670, + -554, -153, 724, 435, -554, -652, 300, 769, + -1420, -392, 1856, 1116, -1420, -1670, 769, 1970, + 1024, -283, -1338, 805, 1024, -1204, -554, 1420, + 283, -78, -369, 222, 283, -332, -153, 392, + -1338, 369, 1748, -1051, -1338, 1573, 724, -1856, + -805, 222, 1051, -632, -805, 946, 435, -1116, + 1024, -283, -1338, 805, 1024, -1204, -554, 1420, + 1204, -332, -1573, 946, 1204, -1416, -652, 1670, + -554, 153, 724, -435, -554, 652, 300, -769, + -1420, 392, 1856, -1116, -1420, 1670, 769, -1970, + 1024, -805, -554, 1420, -1024, -283, 1338, -1204, + 283, -222, -153, 392, -283, -78, 369, -332, + -1338, 1051, 724, -1856, 1338, 369, -1748, 1573, + -805, 632, 435, -1116, 805, 222, -1051, 946, + 1024, -805, -554, 1420, -1024, -283, 1338, -1204, + 1204, -946, -652, 1670, -1204, -332, 1573, -1416, + -554, 435, 300, -769, 554, 153, -724, 652, + -1420, 1116, 769, -1970, 1420, 392, -1856, 1670, + 1024, -1204, 554, 283, -1024, 1420, -1338, 805, + 283, -332, 153, 78, -283, 392, -369, 222, + -1338, 1573, -724, -369, 1338, -1856, 1748, -1051, + -805, 946, -435, -222, 805, -1116, 1051, -632, + 1024, -1204, 554, 283, -1024, 1420, -1338, 805, + 1204, -1416, 652, 332, -1204, 1670, -1573, 946, + -554, 652, -300, -153, 554, -769, 724, -435, + -1420, 1670, -769, -392, 1420, -1970, 1856, -1116, + 1024, -1420, 1338, -1204, 1024, -805, 554, -283, + 283, -392, 369, -332, 283, -222, 153, -78, + -1338, 1856, -1748, 1573, -1338, 1051, -724, 369, + -805, 1116, -1051, 946, -805, 632, -435, 222, + 1024, -1420, 1338, -1204, 1024, -805, 554, -283, + 1204, -1670, 1573, -1416, 1204, -946, 652, -332, + -554, 769, -724, 652, -554, 435, -300, 153, + -1420, 1970, -1856, 1670, -1420, 1116, -769, 392, + 1024, 1420, 1338, 1204, 1024, 805, 554, 283, + -283, -392, -369, -332, -283, -222, -153, -78, + -1338, -1856, -1748, -1573, -1338, -1051, -724, -369, + 805, 1116, 1051, 946, 805, 632, 435, 222, + 1024, 1420, 1338, 1204, 1024, 805, 554, 283, + -1204, -1670, -1573, -1416, -1204, -946, -652, -332, + -554, -769, -724, -652, -554, -435, -300, -153, + 1420, 1970, 1856, 1670, 1420, 1116, 769, 392, + 1024, 1204, 554, -283, -1024, -1420, -1338, -805, + -283, -332, -153, 78, 283, 392, 369, 222, + -1338, -1573, -724, 369, 1338, 1856, 1748, 1051, + 805, 946, 435, -222, -805, -1116, -1051, -632, + 1024, 1204, 554, -283, -1024, -1420, -1338, -805, + -1204, -1416, -652, 332, 1204, 1670, 1573, 946, + -554, -652, -300, 153, 554, 769, 724, 435, + 1420, 1670, 769, -392, -1420, -1970, -1856, -1116, + 1024, 805, -554, -1420, -1024, 283, 1338, 1204, + -283, -222, 153, 392, 283, -78, -369, -332, + -1338, -1051, 724, 1856, 1338, -369, -1748, -1573, + 805, 632, -435, -1116, -805, 222, 1051, 946, + 1024, 805, -554, -1420, -1024, 283, 1338, 1204, + -1204, -946, 652, 1670, 1204, -332, -1573, -1416, + -554, -435, 300, 769, 554, -153, -724, -652, + 1420, 1116, -769, -1970, -1420, 392, 1856, 1670, + 1024, 283, -1338, -805, 1024, 1204, -554, -1420, + -283, -78, 369, 222, -283, -332, 153, 392, + -1338, -369, 1748, 1051, -1338, -1573, 724, 1856, + 805, 222, -1051, -632, 805, 946, -435, -1116, + 1024, 283, -1338, -805, 1024, 1204, -554, -1420, + -1204, -332, 1573, 946, -1204, -1416, 652, 1670, + -554, -153, 724, 435, -554, -652, 300, 769, + 1420, 392, -1856, -1116, 1420, 1670, -769, -1970, + 1024, -283, -1338, 805, 1024, -1204, -554, 1420, + -283, 78, 369, -222, -283, 332, 153, -392, + -1338, 369, 1748, -1051, -1338, 1573, 724, -1856, + 805, -222, -1051, 632, 805, -946, -435, 1116, + 1024, -283, -1338, 805, 1024, -1204, -554, 1420, + -1204, 332, 1573, -946, -1204, 1416, 652, -1670, + -554, 153, 724, -435, -554, 652, 300, -769, + 1420, -392, -1856, 1116, 1420, -1670, -769, 1970, + 1024, -805, -554, 1420, -1024, -283, 1338, -1204, + -283, 222, 153, -392, 283, 78, -369, 332, + -1338, 1051, 724, -1856, 1338, 369, -1748, 1573, + 805, -632, -435, 1116, -805, -222, 1051, -946, + 1024, -805, -554, 1420, -1024, -283, 1338, -1204, + -1204, 946, 652, -1670, 1204, 332, -1573, 1416, + -554, 435, 300, -769, 554, 153, -724, 652, + 1420, -1116, -769, 1970, -1420, -392, 1856, -1670, + 1024, -1204, 554, 283, -1024, 1420, -1338, 805, + -283, 332, -153, -78, 283, -392, 369, -222, + -1338, 1573, -724, -369, 1338, -1856, 1748, -1051, + 805, -946, 435, 222, -805, 1116, -1051, 632, + 1024, -1204, 554, 283, -1024, 1420, -1338, 805, + -1204, 1416, -652, -332, 1204, -1670, 1573, -946, + -554, 652, -300, -153, 554, -769, 724, -435, + 1420, -1670, 769, 392, -1420, 1970, -1856, 1116, + 1024, -1420, 1338, -1204, 1024, -805, 554, -283, + -283, 392, -369, 332, -283, 222, -153, 78, + -1338, 1856, -1748, 1573, -1338, 1051, -724, 369, + 805, -1116, 1051, -946, 805, -632, 435, -222, + 1024, -1420, 1338, -1204, 1024, -805, 554, -283, + -1204, 1670, -1573, 1416, -1204, 946, -652, 332, + -554, 769, -724, 652, -554, 435, -300, 153, + 1420, -1970, 1856, -1670, 1420, -1116, 769, -392, + 1024, 1420, 1338, 1204, 1024, 805, 554, 283, + -805, -1116, -1051, -946, -805, -632, -435, -222, + -554, -769, -724, -652, -554, -435, -300, -153, + 1420, 1970, 1856, 1670, 1420, 1116, 769, 392, + -1024, -1420, -1338, -1204, -1024, -805, -554, -283, + -283, -392, -369, -332, -283, -222, -153, -78, + 1338, 1856, 1748, 1573, 1338, 1051, 724, 369, + -1204, -1670, -1573, -1416, -1204, -946, -652, -332, + 1024, 1204, 554, -283, -1024, -1420, -1338, -805, + -805, -946, -435, 222, 805, 1116, 1051, 632, + -554, -652, -300, 153, 554, 769, 724, 435, + 1420, 1670, 769, -392, -1420, -1970, -1856, -1116, + -1024, -1204, -554, 283, 1024, 1420, 1338, 805, + -283, -332, -153, 78, 283, 392, 369, 222, + 1338, 1573, 724, -369, -1338, -1856, -1748, -1051, + -1204, -1416, -652, 332, 1204, 1670, 1573, 946, + 1024, 805, -554, -1420, -1024, 283, 1338, 1204, + -805, -632, 435, 1116, 805, -222, -1051, -946, + -554, -435, 300, 769, 554, -153, -724, -652, + 1420, 1116, -769, -1970, -1420, 392, 1856, 1670, + -1024, -805, 554, 1420, 1024, -283, -1338, -1204, + -283, -222, 153, 392, 283, -78, -369, -332, + 1338, 1051, -724, -1856, -1338, 369, 1748, 1573, + -1204, -946, 652, 1670, 1204, -332, -1573, -1416, + 1024, 283, -1338, -805, 1024, 1204, -554, -1420, + -805, -222, 1051, 632, -805, -946, 435, 1116, + -554, -153, 724, 435, -554, -652, 300, 769, + 1420, 392, -1856, -1116, 1420, 1670, -769, -1970, + -1024, -283, 1338, 805, -1024, -1204, 554, 1420, + -283, -78, 369, 222, -283, -332, 153, 392, + 1338, 369, -1748, -1051, 1338, 1573, -724, -1856, + -1204, -332, 1573, 946, -1204, -1416, 652, 1670, + 1024, -283, -1338, 805, 1024, -1204, -554, 1420, + -805, 222, 1051, -632, -805, 946, 435, -1116, + -554, 153, 724, -435, -554, 652, 300, -769, + 1420, -392, -1856, 1116, 1420, -1670, -769, 1970, + -1024, 283, 1338, -805, -1024, 1204, 554, -1420, + -283, 78, 369, -222, -283, 332, 153, -392, + 1338, -369, -1748, 1051, 1338, -1573, -724, 1856, + -1204, 332, 1573, -946, -1204, 1416, 652, -1670, + 1024, -805, -554, 1420, -1024, -283, 1338, -1204, + -805, 632, 435, -1116, 805, 222, -1051, 946, + -554, 435, 300, -769, 554, 153, -724, 652, + 1420, -1116, -769, 1970, -1420, -392, 1856, -1670, + -1024, 805, 554, -1420, 1024, 283, -1338, 1204, + -283, 222, 153, -392, 283, 78, -369, 332, + 1338, -1051, -724, 1856, -1338, -369, 1748, -1573, + -1204, 946, 652, -1670, 1204, 332, -1573, 1416, + 1024, -1204, 554, 283, -1024, 1420, -1338, 805, + -805, 946, -435, -222, 805, -1116, 1051, -632, + -554, 652, -300, -153, 554, -769, 724, -435, + 1420, -1670, 769, 392, -1420, 1970, -1856, 1116, + -1024, 1204, -554, -283, 1024, -1420, 1338, -805, + -283, 332, -153, -78, 283, -392, 369, -222, + 1338, -1573, 724, 369, -1338, 1856, -1748, 1051, + -1204, 1416, -652, -332, 1204, -1670, 1573, -946, + 1024, -1420, 1338, -1204, 1024, -805, 554, -283, + -805, 1116, -1051, 946, -805, 632, -435, 222, + -554, 769, -724, 652, -554, 435, -300, 153, + 1420, -1970, 1856, -1670, 1420, -1116, 769, -392, + -1024, 1420, -1338, 1204, -1024, 805, -554, 283, + -283, 392, -369, 332, -283, 222, -153, 78, + 1338, -1856, 1748, -1573, 1338, -1051, 724, -369, + -1204, 1670, -1573, 1416, -1204, 946, -652, 332, + 1024, 1420, 1338, 1204, 1024, 805, 554, 283, + -1204, -1670, -1573, -1416, -1204, -946, -652, -332, + 554, 769, 724, 652, 554, 435, 300, 153, + 283, 392, 369, 332, 283, 222, 153, 78, + -1024, -1420, -1338, -1204, -1024, -805, -554, -283, + 1420, 1970, 1856, 1670, 1420, 1116, 769, 392, + -1338, -1856, -1748, -1573, -1338, -1051, -724, -369, + 805, 1116, 1051, 946, 805, 632, 435, 222, + 1024, 1204, 554, -283, -1024, -1420, -1338, -805, + -1204, -1416, -652, 332, 1204, 1670, 1573, 946, + 554, 652, 300, -153, -554, -769, -724, -435, + 283, 332, 153, -78, -283, -392, -369, -222, + -1024, -1204, -554, 283, 1024, 1420, 1338, 805, + 1420, 1670, 769, -392, -1420, -1970, -1856, -1116, + -1338, -1573, -724, 369, 1338, 1856, 1748, 1051, + 805, 946, 435, -222, -805, -1116, -1051, -632, + 1024, 805, -554, -1420, -1024, 283, 1338, 1204, + -1204, -946, 652, 1670, 1204, -332, -1573, -1416, + 554, 435, -300, -769, -554, 153, 724, 652, + 283, 222, -153, -392, -283, 78, 369, 332, + -1024, -805, 554, 1420, 1024, -283, -1338, -1204, + 1420, 1116, -769, -1970, -1420, 392, 1856, 1670, + -1338, -1051, 724, 1856, 1338, -369, -1748, -1573, + 805, 632, -435, -1116, -805, 222, 1051, 946, + 1024, 283, -1338, -805, 1024, 1204, -554, -1420, + -1204, -332, 1573, 946, -1204, -1416, 652, 1670, + 554, 153, -724, -435, 554, 652, -300, -769, + 283, 78, -369, -222, 283, 332, -153, -392, + -1024, -283, 1338, 805, -1024, -1204, 554, 1420, + 1420, 392, -1856, -1116, 1420, 1670, -769, -1970, + -1338, -369, 1748, 1051, -1338, -1573, 724, 1856, + 805, 222, -1051, -632, 805, 946, -435, -1116, + 1024, -283, -1338, 805, 1024, -1204, -554, 1420, + -1204, 332, 1573, -946, -1204, 1416, 652, -1670, + 554, -153, -724, 435, 554, -652, -300, 769, + 283, -78, -369, 222, 283, -332, -153, 392, + -1024, 283, 1338, -805, -1024, 1204, 554, -1420, + 1420, -392, -1856, 1116, 1420, -1670, -769, 1970, + -1338, 369, 1748, -1051, -1338, 1573, 724, -1856, + 805, -222, -1051, 632, 805, -946, -435, 1116, + 1024, -805, -554, 1420, -1024, -283, 1338, -1204, + -1204, 946, 652, -1670, 1204, 332, -1573, 1416, + 554, -435, -300, 769, -554, -153, 724, -652, + 283, -222, -153, 392, -283, -78, 369, -332, + -1024, 805, 554, -1420, 1024, 283, -1338, 1204, + 1420, -1116, -769, 1970, -1420, -392, 1856, -1670, + -1338, 1051, 724, -1856, 1338, 369, -1748, 1573, + 805, -632, -435, 1116, -805, -222, 1051, -946, + 1024, -1204, 554, 283, -1024, 1420, -1338, 805, + -1204, 1416, -652, -332, 1204, -1670, 1573, -946, + 554, -652, 300, 153, -554, 769, -724, 435, + 283, -332, 153, 78, -283, 392, -369, 222, + -1024, 1204, -554, -283, 1024, -1420, 1338, -805, + 1420, -1670, 769, 392, -1420, 1970, -1856, 1116, + -1338, 1573, -724, -369, 1338, -1856, 1748, -1051, + 805, -946, 435, 222, -805, 1116, -1051, 632, + 1024, -1420, 1338, -1204, 1024, -805, 554, -283, + -1204, 1670, -1573, 1416, -1204, 946, -652, 332, + 554, -769, 724, -652, 554, -435, 300, -153, + 283, -392, 369, -332, 283, -222, 153, -78, + -1024, 1420, -1338, 1204, -1024, 805, -554, 283, + 1420, -1970, 1856, -1670, 1420, -1116, 769, -392, + -1338, 1856, -1748, 1573, -1338, 1051, -724, 369, + 805, -1116, 1051, -946, 805, -632, 435, -222, + 1024, 1420, 1338, 1204, 1024, 805, 554, 283, + -1420, -1970, -1856, -1670, -1420, -1116, -769, -392, + 1338, 1856, 1748, 1573, 1338, 1051, 724, 369, + -1204, -1670, -1573, -1416, -1204, -946, -652, -332, + 1024, 1420, 1338, 1204, 1024, 805, 554, 283, + -805, -1116, -1051, -946, -805, -632, -435, -222, + 554, 769, 724, 652, 554, 435, 300, 153, + -283, -392, -369, -332, -283, -222, -153, -78, + 1024, 1204, 554, -283, -1024, -1420, -1338, -805, + -1420, -1670, -769, 392, 1420, 1970, 1856, 1116, + 1338, 1573, 724, -369, -1338, -1856, -1748, -1051, + -1204, -1416, -652, 332, 1204, 1670, 1573, 946, + 1024, 1204, 554, -283, -1024, -1420, -1338, -805, + -805, -946, -435, 222, 805, 1116, 1051, 632, + 554, 652, 300, -153, -554, -769, -724, -435, + -283, -332, -153, 78, 283, 392, 369, 222, + 1024, 805, -554, -1420, -1024, 283, 1338, 1204, + -1420, -1116, 769, 1970, 1420, -392, -1856, -1670, + 1338, 1051, -724, -1856, -1338, 369, 1748, 1573, + -1204, -946, 652, 1670, 1204, -332, -1573, -1416, + 1024, 805, -554, -1420, -1024, 283, 1338, 1204, + -805, -632, 435, 1116, 805, -222, -1051, -946, + 554, 435, -300, -769, -554, 153, 724, 652, + -283, -222, 153, 392, 283, -78, -369, -332, + 1024, 283, -1338, -805, 1024, 1204, -554, -1420, + -1420, -392, 1856, 1116, -1420, -1670, 769, 1970, + 1338, 369, -1748, -1051, 1338, 1573, -724, -1856, + -1204, -332, 1573, 946, -1204, -1416, 652, 1670, + 1024, 283, -1338, -805, 1024, 1204, -554, -1420, + -805, -222, 1051, 632, -805, -946, 435, 1116, + 554, 153, -724, -435, 554, 652, -300, -769, + -283, -78, 369, 222, -283, -332, 153, 392, + 1024, -283, -1338, 805, 1024, -1204, -554, 1420, + -1420, 392, 1856, -1116, -1420, 1670, 769, -1970, + 1338, -369, -1748, 1051, 1338, -1573, -724, 1856, + -1204, 332, 1573, -946, -1204, 1416, 652, -1670, + 1024, -283, -1338, 805, 1024, -1204, -554, 1420, + -805, 222, 1051, -632, -805, 946, 435, -1116, + 554, -153, -724, 435, 554, -652, -300, 769, + -283, 78, 369, -222, -283, 332, 153, -392, + 1024, -805, -554, 1420, -1024, -283, 1338, -1204, + -1420, 1116, 769, -1970, 1420, 392, -1856, 1670, + 1338, -1051, -724, 1856, -1338, -369, 1748, -1573, + -1204, 946, 652, -1670, 1204, 332, -1573, 1416, + 1024, -805, -554, 1420, -1024, -283, 1338, -1204, + -805, 632, 435, -1116, 805, 222, -1051, 946, + 554, -435, -300, 769, -554, -153, 724, -652, + -283, 222, 153, -392, 283, 78, -369, 332, + 1024, -1204, 554, 283, -1024, 1420, -1338, 805, + -1420, 1670, -769, -392, 1420, -1970, 1856, -1116, + 1338, -1573, 724, 369, -1338, 1856, -1748, 1051, + -1204, 1416, -652, -332, 1204, -1670, 1573, -946, + 1024, -1204, 554, 283, -1024, 1420, -1338, 805, + -805, 946, -435, -222, 805, -1116, 1051, -632, + 554, -652, 300, 153, -554, 769, -724, 435, + -283, 332, -153, -78, 283, -392, 369, -222, + 1024, -1420, 1338, -1204, 1024, -805, 554, -283, + -1420, 1970, -1856, 1670, -1420, 1116, -769, 392, + 1338, -1856, 1748, -1573, 1338, -1051, 724, -369, + -1204, 1670, -1573, 1416, -1204, 946, -652, 332, + 1024, -1420, 1338, -1204, 1024, -805, 554, -283, + -805, 1116, -1051, 946, -805, 632, -435, 222, + 554, -769, 724, -652, 554, -435, 300, -153, + -283, 392, -369, 332, -283, 222, -153, 78, +}; + +// precalculated int values for 8x8 FDCT, multplied by 8192 +const int icos_fdct_8x8[ 4096 ] = +{ + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1420, 1204, 805, 283, -283, -805, -1204, -1420, + 1420, 1204, 805, 283, -283, -805, -1204, -1420, + 1420, 1204, 805, 283, -283, -805, -1204, -1420, + 1420, 1204, 805, 283, -283, -805, -1204, -1420, + 1420, 1204, 805, 283, -283, -805, -1204, -1420, + 1420, 1204, 805, 283, -283, -805, -1204, -1420, + 1420, 1204, 805, 283, -283, -805, -1204, -1420, + 1420, 1204, 805, 283, -283, -805, -1204, -1420, + 1338, 554, -554, -1338, -1338, -554, 554, 1338, + 1338, 554, -554, -1338, -1338, -554, 554, 1338, + 1338, 554, -554, -1338, -1338, -554, 554, 1338, + 1338, 554, -554, -1338, -1338, -554, 554, 1338, + 1338, 554, -554, -1338, -1338, -554, 554, 1338, + 1338, 554, -554, -1338, -1338, -554, 554, 1338, + 1338, 554, -554, -1338, -1338, -554, 554, 1338, + 1338, 554, -554, -1338, -1338, -554, 554, 1338, + 1204, -283, -1420, -805, 805, 1420, 283, -1204, + 1204, -283, -1420, -805, 805, 1420, 283, -1204, + 1204, -283, -1420, -805, 805, 1420, 283, -1204, + 1204, -283, -1420, -805, 805, 1420, 283, -1204, + 1204, -283, -1420, -805, 805, 1420, 283, -1204, + 1204, -283, -1420, -805, 805, 1420, 283, -1204, + 1204, -283, -1420, -805, 805, 1420, 283, -1204, + 1204, -283, -1420, -805, 805, 1420, 283, -1204, + 1024, -1024, -1024, 1024, 1024, -1024, -1024, 1024, + 1024, -1024, -1024, 1024, 1024, -1024, -1024, 1024, + 1024, -1024, -1024, 1024, 1024, -1024, -1024, 1024, + 1024, -1024, -1024, 1024, 1024, -1024, -1024, 1024, + 1024, -1024, -1024, 1024, 1024, -1024, -1024, 1024, + 1024, -1024, -1024, 1024, 1024, -1024, -1024, 1024, + 1024, -1024, -1024, 1024, 1024, -1024, -1024, 1024, + 1024, -1024, -1024, 1024, 1024, -1024, -1024, 1024, + 805, -1420, 283, 1204, -1204, -283, 1420, -805, + 805, -1420, 283, 1204, -1204, -283, 1420, -805, + 805, -1420, 283, 1204, -1204, -283, 1420, -805, + 805, -1420, 283, 1204, -1204, -283, 1420, -805, + 805, -1420, 283, 1204, -1204, -283, 1420, -805, + 805, -1420, 283, 1204, -1204, -283, 1420, -805, + 805, -1420, 283, 1204, -1204, -283, 1420, -805, + 805, -1420, 283, 1204, -1204, -283, 1420, -805, + 554, -1338, 1338, -554, -554, 1338, -1338, 554, + 554, -1338, 1338, -554, -554, 1338, -1338, 554, + 554, -1338, 1338, -554, -554, 1338, -1338, 554, + 554, -1338, 1338, -554, -554, 1338, -1338, 554, + 554, -1338, 1338, -554, -554, 1338, -1338, 554, + 554, -1338, 1338, -554, -554, 1338, -1338, 554, + 554, -1338, 1338, -554, -554, 1338, -1338, 554, + 554, -1338, 1338, -554, -554, 1338, -1338, 554, + 283, -805, 1204, -1420, 1420, -1204, 805, -283, + 283, -805, 1204, -1420, 1420, -1204, 805, -283, + 283, -805, 1204, -1420, 1420, -1204, 805, -283, + 283, -805, 1204, -1420, 1420, -1204, 805, -283, + 283, -805, 1204, -1420, 1420, -1204, 805, -283, + 283, -805, 1204, -1420, 1420, -1204, 805, -283, + 283, -805, 1204, -1420, 1420, -1204, 805, -283, + 283, -805, 1204, -1420, 1420, -1204, 805, -283, + 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, + 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, + 805, 805, 805, 805, 805, 805, 805, 805, + 283, 283, 283, 283, 283, 283, 283, 283, + -283, -283, -283, -283, -283, -283, -283, -283, + -805, -805, -805, -805, -805, -805, -805, -805, + -1204, -1204, -1204, -1204, -1204, -1204, -1204, -1204, + -1420, -1420, -1420, -1420, -1420, -1420, -1420, -1420, + 1970, 1670, 1116, 392, -392, -1116, -1670, -1970, + 1670, 1416, 946, 332, -332, -946, -1416, -1670, + 1116, 946, 632, 222, -222, -632, -946, -1116, + 392, 332, 222, 78, -78, -222, -332, -392, + -392, -332, -222, -78, 78, 222, 332, 392, + -1116, -946, -632, -222, 222, 632, 946, 1116, + -1670, -1416, -946, -332, 332, 946, 1416, 1670, + -1970, -1670, -1116, -392, 392, 1116, 1670, 1970, + 1856, 769, -769, -1856, -1856, -769, 769, 1856, + 1573, 652, -652, -1573, -1573, -652, 652, 1573, + 1051, 435, -435, -1051, -1051, -435, 435, 1051, + 369, 153, -153, -369, -369, -153, 153, 369, + -369, -153, 153, 369, 369, 153, -153, -369, + -1051, -435, 435, 1051, 1051, 435, -435, -1051, + -1573, -652, 652, 1573, 1573, 652, -652, -1573, + -1856, -769, 769, 1856, 1856, 769, -769, -1856, + 1670, -392, -1970, -1116, 1116, 1970, 392, -1670, + 1416, -332, -1670, -946, 946, 1670, 332, -1416, + 946, -222, -1116, -632, 632, 1116, 222, -946, + 332, -78, -392, -222, 222, 392, 78, -332, + -332, 78, 392, 222, -222, -392, -78, 332, + -946, 222, 1116, 632, -632, -1116, -222, 946, + -1416, 332, 1670, 946, -946, -1670, -332, 1416, + -1670, 392, 1970, 1116, -1116, -1970, -392, 1670, + 1420, -1420, -1420, 1420, 1420, -1420, -1420, 1420, + 1204, -1204, -1204, 1204, 1204, -1204, -1204, 1204, + 805, -805, -805, 805, 805, -805, -805, 805, + 283, -283, -283, 283, 283, -283, -283, 283, + -283, 283, 283, -283, -283, 283, 283, -283, + -805, 805, 805, -805, -805, 805, 805, -805, + -1204, 1204, 1204, -1204, -1204, 1204, 1204, -1204, + -1420, 1420, 1420, -1420, -1420, 1420, 1420, -1420, + 1116, -1970, 392, 1670, -1670, -392, 1970, -1116, + 946, -1670, 332, 1416, -1416, -332, 1670, -946, + 632, -1116, 222, 946, -946, -222, 1116, -632, + 222, -392, 78, 332, -332, -78, 392, -222, + -222, 392, -78, -332, 332, 78, -392, 222, + -632, 1116, -222, -946, 946, 222, -1116, 632, + -946, 1670, -332, -1416, 1416, 332, -1670, 946, + -1116, 1970, -392, -1670, 1670, 392, -1970, 1116, + 769, -1856, 1856, -769, -769, 1856, -1856, 769, + 652, -1573, 1573, -652, -652, 1573, -1573, 652, + 435, -1051, 1051, -435, -435, 1051, -1051, 435, + 153, -369, 369, -153, -153, 369, -369, 153, + -153, 369, -369, 153, 153, -369, 369, -153, + -435, 1051, -1051, 435, 435, -1051, 1051, -435, + -652, 1573, -1573, 652, 652, -1573, 1573, -652, + -769, 1856, -1856, 769, 769, -1856, 1856, -769, + 392, -1116, 1670, -1970, 1970, -1670, 1116, -392, + 332, -946, 1416, -1670, 1670, -1416, 946, -332, + 222, -632, 946, -1116, 1116, -946, 632, -222, + 78, -222, 332, -392, 392, -332, 222, -78, + -78, 222, -332, 392, -392, 332, -222, 78, + -222, 632, -946, 1116, -1116, 946, -632, 222, + -332, 946, -1416, 1670, -1670, 1416, -946, 332, + -392, 1116, -1670, 1970, -1970, 1670, -1116, 392, + 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, + 554, 554, 554, 554, 554, 554, 554, 554, + -554, -554, -554, -554, -554, -554, -554, -554, + -1338, -1338, -1338, -1338, -1338, -1338, -1338, -1338, + -1338, -1338, -1338, -1338, -1338, -1338, -1338, -1338, + -554, -554, -554, -554, -554, -554, -554, -554, + 554, 554, 554, 554, 554, 554, 554, 554, + 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, + 1856, 1573, 1051, 369, -369, -1051, -1573, -1856, + 769, 652, 435, 153, -153, -435, -652, -769, + -769, -652, -435, -153, 153, 435, 652, 769, + -1856, -1573, -1051, -369, 369, 1051, 1573, 1856, + -1856, -1573, -1051, -369, 369, 1051, 1573, 1856, + -769, -652, -435, -153, 153, 435, 652, 769, + 769, 652, 435, 153, -153, -435, -652, -769, + 1856, 1573, 1051, 369, -369, -1051, -1573, -1856, + 1748, 724, -724, -1748, -1748, -724, 724, 1748, + 724, 300, -300, -724, -724, -300, 300, 724, + -724, -300, 300, 724, 724, 300, -300, -724, + -1748, -724, 724, 1748, 1748, 724, -724, -1748, + -1748, -724, 724, 1748, 1748, 724, -724, -1748, + -724, -300, 300, 724, 724, 300, -300, -724, + 724, 300, -300, -724, -724, -300, 300, 724, + 1748, 724, -724, -1748, -1748, -724, 724, 1748, + 1573, -369, -1856, -1051, 1051, 1856, 369, -1573, + 652, -153, -769, -435, 435, 769, 153, -652, + -652, 153, 769, 435, -435, -769, -153, 652, + -1573, 369, 1856, 1051, -1051, -1856, -369, 1573, + -1573, 369, 1856, 1051, -1051, -1856, -369, 1573, + -652, 153, 769, 435, -435, -769, -153, 652, + 652, -153, -769, -435, 435, 769, 153, -652, + 1573, -369, -1856, -1051, 1051, 1856, 369, -1573, + 1338, -1338, -1338, 1338, 1338, -1338, -1338, 1338, + 554, -554, -554, 554, 554, -554, -554, 554, + -554, 554, 554, -554, -554, 554, 554, -554, + -1338, 1338, 1338, -1338, -1338, 1338, 1338, -1338, + -1338, 1338, 1338, -1338, -1338, 1338, 1338, -1338, + -554, 554, 554, -554, -554, 554, 554, -554, + 554, -554, -554, 554, 554, -554, -554, 554, + 1338, -1338, -1338, 1338, 1338, -1338, -1338, 1338, + 1051, -1856, 369, 1573, -1573, -369, 1856, -1051, + 435, -769, 153, 652, -652, -153, 769, -435, + -435, 769, -153, -652, 652, 153, -769, 435, + -1051, 1856, -369, -1573, 1573, 369, -1856, 1051, + -1051, 1856, -369, -1573, 1573, 369, -1856, 1051, + -435, 769, -153, -652, 652, 153, -769, 435, + 435, -769, 153, 652, -652, -153, 769, -435, + 1051, -1856, 369, 1573, -1573, -369, 1856, -1051, + 724, -1748, 1748, -724, -724, 1748, -1748, 724, + 300, -724, 724, -300, -300, 724, -724, 300, + -300, 724, -724, 300, 300, -724, 724, -300, + -724, 1748, -1748, 724, 724, -1748, 1748, -724, + -724, 1748, -1748, 724, 724, -1748, 1748, -724, + -300, 724, -724, 300, 300, -724, 724, -300, + 300, -724, 724, -300, -300, 724, -724, 300, + 724, -1748, 1748, -724, -724, 1748, -1748, 724, + 369, -1051, 1573, -1856, 1856, -1573, 1051, -369, + 153, -435, 652, -769, 769, -652, 435, -153, + -153, 435, -652, 769, -769, 652, -435, 153, + -369, 1051, -1573, 1856, -1856, 1573, -1051, 369, + -369, 1051, -1573, 1856, -1856, 1573, -1051, 369, + -153, 435, -652, 769, -769, 652, -435, 153, + 153, -435, 652, -769, 769, -652, 435, -153, + 369, -1051, 1573, -1856, 1856, -1573, 1051, -369, + 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, + -283, -283, -283, -283, -283, -283, -283, -283, + -1420, -1420, -1420, -1420, -1420, -1420, -1420, -1420, + -805, -805, -805, -805, -805, -805, -805, -805, + 805, 805, 805, 805, 805, 805, 805, 805, + 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, + 283, 283, 283, 283, 283, 283, 283, 283, + -1204, -1204, -1204, -1204, -1204, -1204, -1204, -1204, + 1670, 1416, 946, 332, -332, -946, -1416, -1670, + -392, -332, -222, -78, 78, 222, 332, 392, + -1970, -1670, -1116, -392, 392, 1116, 1670, 1970, + -1116, -946, -632, -222, 222, 632, 946, 1116, + 1116, 946, 632, 222, -222, -632, -946, -1116, + 1970, 1670, 1116, 392, -392, -1116, -1670, -1970, + 392, 332, 222, 78, -78, -222, -332, -392, + -1670, -1416, -946, -332, 332, 946, 1416, 1670, + 1573, 652, -652, -1573, -1573, -652, 652, 1573, + -369, -153, 153, 369, 369, 153, -153, -369, + -1856, -769, 769, 1856, 1856, 769, -769, -1856, + -1051, -435, 435, 1051, 1051, 435, -435, -1051, + 1051, 435, -435, -1051, -1051, -435, 435, 1051, + 1856, 769, -769, -1856, -1856, -769, 769, 1856, + 369, 153, -153, -369, -369, -153, 153, 369, + -1573, -652, 652, 1573, 1573, 652, -652, -1573, + 1416, -332, -1670, -946, 946, 1670, 332, -1416, + -332, 78, 392, 222, -222, -392, -78, 332, + -1670, 392, 1970, 1116, -1116, -1970, -392, 1670, + -946, 222, 1116, 632, -632, -1116, -222, 946, + 946, -222, -1116, -632, 632, 1116, 222, -946, + 1670, -392, -1970, -1116, 1116, 1970, 392, -1670, + 332, -78, -392, -222, 222, 392, 78, -332, + -1416, 332, 1670, 946, -946, -1670, -332, 1416, + 1204, -1204, -1204, 1204, 1204, -1204, -1204, 1204, + -283, 283, 283, -283, -283, 283, 283, -283, + -1420, 1420, 1420, -1420, -1420, 1420, 1420, -1420, + -805, 805, 805, -805, -805, 805, 805, -805, + 805, -805, -805, 805, 805, -805, -805, 805, + 1420, -1420, -1420, 1420, 1420, -1420, -1420, 1420, + 283, -283, -283, 283, 283, -283, -283, 283, + -1204, 1204, 1204, -1204, -1204, 1204, 1204, -1204, + 946, -1670, 332, 1416, -1416, -332, 1670, -946, + -222, 392, -78, -332, 332, 78, -392, 222, + -1116, 1970, -392, -1670, 1670, 392, -1970, 1116, + -632, 1116, -222, -946, 946, 222, -1116, 632, + 632, -1116, 222, 946, -946, -222, 1116, -632, + 1116, -1970, 392, 1670, -1670, -392, 1970, -1116, + 222, -392, 78, 332, -332, -78, 392, -222, + -946, 1670, -332, -1416, 1416, 332, -1670, 946, + 652, -1573, 1573, -652, -652, 1573, -1573, 652, + -153, 369, -369, 153, 153, -369, 369, -153, + -769, 1856, -1856, 769, 769, -1856, 1856, -769, + -435, 1051, -1051, 435, 435, -1051, 1051, -435, + 435, -1051, 1051, -435, -435, 1051, -1051, 435, + 769, -1856, 1856, -769, -769, 1856, -1856, 769, + 153, -369, 369, -153, -153, 369, -369, 153, + -652, 1573, -1573, 652, 652, -1573, 1573, -652, + 332, -946, 1416, -1670, 1670, -1416, 946, -332, + -78, 222, -332, 392, -392, 332, -222, 78, + -392, 1116, -1670, 1970, -1970, 1670, -1116, 392, + -222, 632, -946, 1116, -1116, 946, -632, 222, + 222, -632, 946, -1116, 1116, -946, 632, -222, + 392, -1116, 1670, -1970, 1970, -1670, 1116, -392, + 78, -222, 332, -392, 392, -332, 222, -78, + -332, 946, -1416, 1670, -1670, 1416, -946, 332, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + -1024, -1024, -1024, -1024, -1024, -1024, -1024, -1024, + -1024, -1024, -1024, -1024, -1024, -1024, -1024, -1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + -1024, -1024, -1024, -1024, -1024, -1024, -1024, -1024, + -1024, -1024, -1024, -1024, -1024, -1024, -1024, -1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1420, 1204, 805, 283, -283, -805, -1204, -1420, + -1420, -1204, -805, -283, 283, 805, 1204, 1420, + -1420, -1204, -805, -283, 283, 805, 1204, 1420, + 1420, 1204, 805, 283, -283, -805, -1204, -1420, + 1420, 1204, 805, 283, -283, -805, -1204, -1420, + -1420, -1204, -805, -283, 283, 805, 1204, 1420, + -1420, -1204, -805, -283, 283, 805, 1204, 1420, + 1420, 1204, 805, 283, -283, -805, -1204, -1420, + 1338, 554, -554, -1338, -1338, -554, 554, 1338, + -1338, -554, 554, 1338, 1338, 554, -554, -1338, + -1338, -554, 554, 1338, 1338, 554, -554, -1338, + 1338, 554, -554, -1338, -1338, -554, 554, 1338, + 1338, 554, -554, -1338, -1338, -554, 554, 1338, + -1338, -554, 554, 1338, 1338, 554, -554, -1338, + -1338, -554, 554, 1338, 1338, 554, -554, -1338, + 1338, 554, -554, -1338, -1338, -554, 554, 1338, + 1204, -283, -1420, -805, 805, 1420, 283, -1204, + -1204, 283, 1420, 805, -805, -1420, -283, 1204, + -1204, 283, 1420, 805, -805, -1420, -283, 1204, + 1204, -283, -1420, -805, 805, 1420, 283, -1204, + 1204, -283, -1420, -805, 805, 1420, 283, -1204, + -1204, 283, 1420, 805, -805, -1420, -283, 1204, + -1204, 283, 1420, 805, -805, -1420, -283, 1204, + 1204, -283, -1420, -805, 805, 1420, 283, -1204, + 1024, -1024, -1024, 1024, 1024, -1024, -1024, 1024, + -1024, 1024, 1024, -1024, -1024, 1024, 1024, -1024, + -1024, 1024, 1024, -1024, -1024, 1024, 1024, -1024, + 1024, -1024, -1024, 1024, 1024, -1024, -1024, 1024, + 1024, -1024, -1024, 1024, 1024, -1024, -1024, 1024, + -1024, 1024, 1024, -1024, -1024, 1024, 1024, -1024, + -1024, 1024, 1024, -1024, -1024, 1024, 1024, -1024, + 1024, -1024, -1024, 1024, 1024, -1024, -1024, 1024, + 805, -1420, 283, 1204, -1204, -283, 1420, -805, + -805, 1420, -283, -1204, 1204, 283, -1420, 805, + -805, 1420, -283, -1204, 1204, 283, -1420, 805, + 805, -1420, 283, 1204, -1204, -283, 1420, -805, + 805, -1420, 283, 1204, -1204, -283, 1420, -805, + -805, 1420, -283, -1204, 1204, 283, -1420, 805, + -805, 1420, -283, -1204, 1204, 283, -1420, 805, + 805, -1420, 283, 1204, -1204, -283, 1420, -805, + 554, -1338, 1338, -554, -554, 1338, -1338, 554, + -554, 1338, -1338, 554, 554, -1338, 1338, -554, + -554, 1338, -1338, 554, 554, -1338, 1338, -554, + 554, -1338, 1338, -554, -554, 1338, -1338, 554, + 554, -1338, 1338, -554, -554, 1338, -1338, 554, + -554, 1338, -1338, 554, 554, -1338, 1338, -554, + -554, 1338, -1338, 554, 554, -1338, 1338, -554, + 554, -1338, 1338, -554, -554, 1338, -1338, 554, + 283, -805, 1204, -1420, 1420, -1204, 805, -283, + -283, 805, -1204, 1420, -1420, 1204, -805, 283, + -283, 805, -1204, 1420, -1420, 1204, -805, 283, + 283, -805, 1204, -1420, 1420, -1204, 805, -283, + 283, -805, 1204, -1420, 1420, -1204, 805, -283, + -283, 805, -1204, 1420, -1420, 1204, -805, 283, + -283, 805, -1204, 1420, -1420, 1204, -805, 283, + 283, -805, 1204, -1420, 1420, -1204, 805, -283, + 805, 805, 805, 805, 805, 805, 805, 805, + -1420, -1420, -1420, -1420, -1420, -1420, -1420, -1420, + 283, 283, 283, 283, 283, 283, 283, 283, + 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, + -1204, -1204, -1204, -1204, -1204, -1204, -1204, -1204, + -283, -283, -283, -283, -283, -283, -283, -283, + 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, + -805, -805, -805, -805, -805, -805, -805, -805, + 1116, 946, 632, 222, -222, -632, -946, -1116, + -1970, -1670, -1116, -392, 392, 1116, 1670, 1970, + 392, 332, 222, 78, -78, -222, -332, -392, + 1670, 1416, 946, 332, -332, -946, -1416, -1670, + -1670, -1416, -946, -332, 332, 946, 1416, 1670, + -392, -332, -222, -78, 78, 222, 332, 392, + 1970, 1670, 1116, 392, -392, -1116, -1670, -1970, + -1116, -946, -632, -222, 222, 632, 946, 1116, + 1051, 435, -435, -1051, -1051, -435, 435, 1051, + -1856, -769, 769, 1856, 1856, 769, -769, -1856, + 369, 153, -153, -369, -369, -153, 153, 369, + 1573, 652, -652, -1573, -1573, -652, 652, 1573, + -1573, -652, 652, 1573, 1573, 652, -652, -1573, + -369, -153, 153, 369, 369, 153, -153, -369, + 1856, 769, -769, -1856, -1856, -769, 769, 1856, + -1051, -435, 435, 1051, 1051, 435, -435, -1051, + 946, -222, -1116, -632, 632, 1116, 222, -946, + -1670, 392, 1970, 1116, -1116, -1970, -392, 1670, + 332, -78, -392, -222, 222, 392, 78, -332, + 1416, -332, -1670, -946, 946, 1670, 332, -1416, + -1416, 332, 1670, 946, -946, -1670, -332, 1416, + -332, 78, 392, 222, -222, -392, -78, 332, + 1670, -392, -1970, -1116, 1116, 1970, 392, -1670, + -946, 222, 1116, 632, -632, -1116, -222, 946, + 805, -805, -805, 805, 805, -805, -805, 805, + -1420, 1420, 1420, -1420, -1420, 1420, 1420, -1420, + 283, -283, -283, 283, 283, -283, -283, 283, + 1204, -1204, -1204, 1204, 1204, -1204, -1204, 1204, + -1204, 1204, 1204, -1204, -1204, 1204, 1204, -1204, + -283, 283, 283, -283, -283, 283, 283, -283, + 1420, -1420, -1420, 1420, 1420, -1420, -1420, 1420, + -805, 805, 805, -805, -805, 805, 805, -805, + 632, -1116, 222, 946, -946, -222, 1116, -632, + -1116, 1970, -392, -1670, 1670, 392, -1970, 1116, + 222, -392, 78, 332, -332, -78, 392, -222, + 946, -1670, 332, 1416, -1416, -332, 1670, -946, + -946, 1670, -332, -1416, 1416, 332, -1670, 946, + -222, 392, -78, -332, 332, 78, -392, 222, + 1116, -1970, 392, 1670, -1670, -392, 1970, -1116, + -632, 1116, -222, -946, 946, 222, -1116, 632, + 435, -1051, 1051, -435, -435, 1051, -1051, 435, + -769, 1856, -1856, 769, 769, -1856, 1856, -769, + 153, -369, 369, -153, -153, 369, -369, 153, + 652, -1573, 1573, -652, -652, 1573, -1573, 652, + -652, 1573, -1573, 652, 652, -1573, 1573, -652, + -153, 369, -369, 153, 153, -369, 369, -153, + 769, -1856, 1856, -769, -769, 1856, -1856, 769, + -435, 1051, -1051, 435, 435, -1051, 1051, -435, + 222, -632, 946, -1116, 1116, -946, 632, -222, + -392, 1116, -1670, 1970, -1970, 1670, -1116, 392, + 78, -222, 332, -392, 392, -332, 222, -78, + 332, -946, 1416, -1670, 1670, -1416, 946, -332, + -332, 946, -1416, 1670, -1670, 1416, -946, 332, + -78, 222, -332, 392, -392, 332, -222, 78, + 392, -1116, 1670, -1970, 1970, -1670, 1116, -392, + -222, 632, -946, 1116, -1116, 946, -632, 222, + 554, 554, 554, 554, 554, 554, 554, 554, + -1338, -1338, -1338, -1338, -1338, -1338, -1338, -1338, + 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, + -554, -554, -554, -554, -554, -554, -554, -554, + -554, -554, -554, -554, -554, -554, -554, -554, + 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, + -1338, -1338, -1338, -1338, -1338, -1338, -1338, -1338, + 554, 554, 554, 554, 554, 554, 554, 554, + 769, 652, 435, 153, -153, -435, -652, -769, + -1856, -1573, -1051, -369, 369, 1051, 1573, 1856, + 1856, 1573, 1051, 369, -369, -1051, -1573, -1856, + -769, -652, -435, -153, 153, 435, 652, 769, + -769, -652, -435, -153, 153, 435, 652, 769, + 1856, 1573, 1051, 369, -369, -1051, -1573, -1856, + -1856, -1573, -1051, -369, 369, 1051, 1573, 1856, + 769, 652, 435, 153, -153, -435, -652, -769, + 724, 300, -300, -724, -724, -300, 300, 724, + -1748, -724, 724, 1748, 1748, 724, -724, -1748, + 1748, 724, -724, -1748, -1748, -724, 724, 1748, + -724, -300, 300, 724, 724, 300, -300, -724, + -724, -300, 300, 724, 724, 300, -300, -724, + 1748, 724, -724, -1748, -1748, -724, 724, 1748, + -1748, -724, 724, 1748, 1748, 724, -724, -1748, + 724, 300, -300, -724, -724, -300, 300, 724, + 652, -153, -769, -435, 435, 769, 153, -652, + -1573, 369, 1856, 1051, -1051, -1856, -369, 1573, + 1573, -369, -1856, -1051, 1051, 1856, 369, -1573, + -652, 153, 769, 435, -435, -769, -153, 652, + -652, 153, 769, 435, -435, -769, -153, 652, + 1573, -369, -1856, -1051, 1051, 1856, 369, -1573, + -1573, 369, 1856, 1051, -1051, -1856, -369, 1573, + 652, -153, -769, -435, 435, 769, 153, -652, + 554, -554, -554, 554, 554, -554, -554, 554, + -1338, 1338, 1338, -1338, -1338, 1338, 1338, -1338, + 1338, -1338, -1338, 1338, 1338, -1338, -1338, 1338, + -554, 554, 554, -554, -554, 554, 554, -554, + -554, 554, 554, -554, -554, 554, 554, -554, + 1338, -1338, -1338, 1338, 1338, -1338, -1338, 1338, + -1338, 1338, 1338, -1338, -1338, 1338, 1338, -1338, + 554, -554, -554, 554, 554, -554, -554, 554, + 435, -769, 153, 652, -652, -153, 769, -435, + -1051, 1856, -369, -1573, 1573, 369, -1856, 1051, + 1051, -1856, 369, 1573, -1573, -369, 1856, -1051, + -435, 769, -153, -652, 652, 153, -769, 435, + -435, 769, -153, -652, 652, 153, -769, 435, + 1051, -1856, 369, 1573, -1573, -369, 1856, -1051, + -1051, 1856, -369, -1573, 1573, 369, -1856, 1051, + 435, -769, 153, 652, -652, -153, 769, -435, + 300, -724, 724, -300, -300, 724, -724, 300, + -724, 1748, -1748, 724, 724, -1748, 1748, -724, + 724, -1748, 1748, -724, -724, 1748, -1748, 724, + -300, 724, -724, 300, 300, -724, 724, -300, + -300, 724, -724, 300, 300, -724, 724, -300, + 724, -1748, 1748, -724, -724, 1748, -1748, 724, + -724, 1748, -1748, 724, 724, -1748, 1748, -724, + 300, -724, 724, -300, -300, 724, -724, 300, + 153, -435, 652, -769, 769, -652, 435, -153, + -369, 1051, -1573, 1856, -1856, 1573, -1051, 369, + 369, -1051, 1573, -1856, 1856, -1573, 1051, -369, + -153, 435, -652, 769, -769, 652, -435, 153, + -153, 435, -652, 769, -769, 652, -435, 153, + 369, -1051, 1573, -1856, 1856, -1573, 1051, -369, + -369, 1051, -1573, 1856, -1856, 1573, -1051, 369, + 153, -435, 652, -769, 769, -652, 435, -153, + 283, 283, 283, 283, 283, 283, 283, 283, + -805, -805, -805, -805, -805, -805, -805, -805, + 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, + -1420, -1420, -1420, -1420, -1420, -1420, -1420, -1420, + 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, + -1204, -1204, -1204, -1204, -1204, -1204, -1204, -1204, + 805, 805, 805, 805, 805, 805, 805, 805, + -283, -283, -283, -283, -283, -283, -283, -283, + 392, 332, 222, 78, -78, -222, -332, -392, + -1116, -946, -632, -222, 222, 632, 946, 1116, + 1670, 1416, 946, 332, -332, -946, -1416, -1670, + -1970, -1670, -1116, -392, 392, 1116, 1670, 1970, + 1970, 1670, 1116, 392, -392, -1116, -1670, -1970, + -1670, -1416, -946, -332, 332, 946, 1416, 1670, + 1116, 946, 632, 222, -222, -632, -946, -1116, + -392, -332, -222, -78, 78, 222, 332, 392, + 369, 153, -153, -369, -369, -153, 153, 369, + -1051, -435, 435, 1051, 1051, 435, -435, -1051, + 1573, 652, -652, -1573, -1573, -652, 652, 1573, + -1856, -769, 769, 1856, 1856, 769, -769, -1856, + 1856, 769, -769, -1856, -1856, -769, 769, 1856, + -1573, -652, 652, 1573, 1573, 652, -652, -1573, + 1051, 435, -435, -1051, -1051, -435, 435, 1051, + -369, -153, 153, 369, 369, 153, -153, -369, + 332, -78, -392, -222, 222, 392, 78, -332, + -946, 222, 1116, 632, -632, -1116, -222, 946, + 1416, -332, -1670, -946, 946, 1670, 332, -1416, + -1670, 392, 1970, 1116, -1116, -1970, -392, 1670, + 1670, -392, -1970, -1116, 1116, 1970, 392, -1670, + -1416, 332, 1670, 946, -946, -1670, -332, 1416, + 946, -222, -1116, -632, 632, 1116, 222, -946, + -332, 78, 392, 222, -222, -392, -78, 332, + 283, -283, -283, 283, 283, -283, -283, 283, + -805, 805, 805, -805, -805, 805, 805, -805, + 1204, -1204, -1204, 1204, 1204, -1204, -1204, 1204, + -1420, 1420, 1420, -1420, -1420, 1420, 1420, -1420, + 1420, -1420, -1420, 1420, 1420, -1420, -1420, 1420, + -1204, 1204, 1204, -1204, -1204, 1204, 1204, -1204, + 805, -805, -805, 805, 805, -805, -805, 805, + -283, 283, 283, -283, -283, 283, 283, -283, + 222, -392, 78, 332, -332, -78, 392, -222, + -632, 1116, -222, -946, 946, 222, -1116, 632, + 946, -1670, 332, 1416, -1416, -332, 1670, -946, + -1116, 1970, -392, -1670, 1670, 392, -1970, 1116, + 1116, -1970, 392, 1670, -1670, -392, 1970, -1116, + -946, 1670, -332, -1416, 1416, 332, -1670, 946, + 632, -1116, 222, 946, -946, -222, 1116, -632, + -222, 392, -78, -332, 332, 78, -392, 222, + 153, -369, 369, -153, -153, 369, -369, 153, + -435, 1051, -1051, 435, 435, -1051, 1051, -435, + 652, -1573, 1573, -652, -652, 1573, -1573, 652, + -769, 1856, -1856, 769, 769, -1856, 1856, -769, + 769, -1856, 1856, -769, -769, 1856, -1856, 769, + -652, 1573, -1573, 652, 652, -1573, 1573, -652, + 435, -1051, 1051, -435, -435, 1051, -1051, 435, + -153, 369, -369, 153, 153, -369, 369, -153, + 78, -222, 332, -392, 392, -332, 222, -78, + -222, 632, -946, 1116, -1116, 946, -632, 222, + 332, -946, 1416, -1670, 1670, -1416, 946, -332, + -392, 1116, -1670, 1970, -1970, 1670, -1116, 392, + 392, -1116, 1670, -1970, 1970, -1670, 1116, -392, + -332, 946, -1416, 1670, -1670, 1416, -946, 332, + 222, -632, 946, -1116, 1116, -946, 632, -222, + -78, 222, -332, 392, -392, 332, -222, 78, +}; + +// precalculated int base values for 8x8 DCT, multplied by 8192 +const int icos_base_8x8[ 64 ] = +{ + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 11363, 9633, 6436, 2260, -2260, -6436, -9633, -11363, + 10703, 4433, -4433, -10703, -10703, -4433, 4433, 10703, + 9633, -2260, -11363, -6436, 6436, 11363, 2260, -9633, + 8192, -8192, -8192, 8192, 8192, -8192, -8192, 8192, + 6436, -11363, 2260, 9633, -9633, -2260, 11363, -6436, + 4433, -10703, 10703, -4433, -4433, 10703, -10703, 4433, + 2260, -6436, 9633, -11363, 11363, -9633, 6436, -2260, +}; + +// precalculated int values for 1x8 IDCT, multplied by 8192 +const int icos_idct_1x8[ 64 ] = +{ + 1024, 1420, 1338, 1204, 1024, 805, 554, 283, + 1024, 1204, 554, -283, -1024, -1420, -1338, -805, + 1024, 805, -554, -1420, -1024, 283, 1338, 1204, + 1024, 283, -1338, -805, 1024, 1204, -554, -1420, + 1024, -283, -1338, 805, 1024, -1204, -554, 1420, + 1024, -805, -554, 1420, -1024, -283, 1338, -1204, + 1024, -1204, 554, 283, -1024, 1420, -1338, 805, + 1024, -1420, 1338, -1204, 1024, -805, 554, -283, +}; + +// precalculated int values for 1x8 FDCT, multplied by 8192 +const int icos_fdct_1x8[ 64 ] = +{ + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 11363, 9633, 6436, 2260, -2260, -6436, -9633, -11363, + 10703, 4433, -4433, -10703, -10703, -4433, 4433, 10703, + 9633, -2260, -11363, -6436, 6436, 11363, 2260, -9633, + 8192, -8192, -8192, 8192, 8192, -8192, -8192, 8192, + 6436, -11363, 2260, 9633, -9633, -2260, 11363, -6436, + 4433, -10703, 10703, -4433, -4433, 10703, -10703, 4433, + 2260, -6436, 9633, -11363, 11363, -9633, 6436, -2260, +}; + + +// dct functions follow, you need to rescale the results using DCT_RESCALE + +/* ----------------------------------------------- + inverse 8x8 DCT transform + ----------------------------------------------- */ +inline int idct_2d_fst_8x8( signed short* F, int ix, int iy ) +{ + int idct; + int ixy; + int i; + + + // calculate start index + ixy = ( ( iy * 8 ) + ix ) * 64; + + // begin transform + idct = 0; + for ( i = 0; i < 64; i++ ) + idct += F[ i ] * icos_idct_8x8[ ixy++ ]; + + + return idct; +} + +/* ----------------------------------------------- + forward 8x8 DCT transform + ----------------------------------------------- */ +inline int fdct_2d_fst_8x8( unsigned char* f, int iu, int iv ) +{ + int fdct; + int iuv; + int i; + + + // calculate start index + iuv = ( ( iv * 8 ) + iu ) * 64; + + // begin transform + fdct = 0; + for ( i = 0; i < 64; i++ ) + fdct += f[ i ] * icos_fdct_8x8[ iuv++ ]; + + + return fdct; +} + +/* ----------------------------------------------- + inverse 1D-8 DCT transform + ----------------------------------------------- */ +inline int idct_1d_fst_8( signed short* F, int ix ) +{ + int idct; + int i; + + + // calculate start index + ix *= 8; + + // begin transform + idct = 0; + for ( i = 0; i < 8; i++ ) + idct += F[ i ] * icos_idct_1x8[ ix++ ]; + + + return idct; +} + +/* ----------------------------------------------- + forward 1D-8 DCT transform + ----------------------------------------------- */ +inline int fdct_1d_fst_8( unsigned char* f, int iu ) +{ + int fdct; + int i; + + + // calculate start index + iu *= 8; + + // begin transform + fdct = 0; + for ( i = 0; i < 8; i++ ) + fdct += f[ i ] * icos_fdct_1x8[ iu++ ]; + + + return fdct; +} + diff --git a/filters/packjpg/lgpl-3.0.txt b/filters/packjpg/lgpl-3.0.txt new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/filters/packjpg/lgpl-3.0.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/filters/packjpg/packjpg.cpp b/filters/packjpg/packjpg.cpp new file mode 100644 index 0000000..f30da99 --- /dev/null +++ b/filters/packjpg/packjpg.cpp @@ -0,0 +1,7213 @@ +/* +packJPG v2.5g (09/14/2013) +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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...2013 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 + + +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 homepage of packJPG is currently maintained by Hochschule +Aalen staff. + +packJPG logo and icon are designed by Michael Kaufmann. + + +Contact +~~~~~~~ + +The official home of packJPG: + http://www.elektronik.htw-aalen.de/packjpg/ + +For questions and bug reports: + packjpg (at) htw-aalen.de + + +____________________________________ +packJPG by Matthias Stirner, 09/2013 +*/ + +#include +#include +#include +#include +#include + +#include "bitops.h" +#include "aricoder.h" +#include "pjpgtbl.h" +#include "dct8x8.h" + +#if defined BUILD_DLL // define BUILD_LIB from the compiler options if you want to compile a DLL! + #define BUILD_LIB +#endif + +#if defined BUILD_LIB // define BUILD_LIB as compiler option if you want to compile a library! + #include "packjpglib.h" +#endif + +#define INTERN static + +#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 ) + +#define MEM_ERRMSG "out of memory error" +#define FRD_ERRMSG "could not read file / file not found: %s" +#define FWR_ERRMSG "could not write file / file write-protected: %s" +#define MSG_SIZE 128 +#define BARLEN 36 + + +/* ----------------------------------------------- + struct declarations + ----------------------------------------------- */ + +struct componentInfo { + unsigned short* qtable; // quantization table + int huffdc; // no of huffman table (DC) + int huffac; // no of huffman table (AC) + int sfv; // sample factor vertical + int sfh; // sample factor horizontal + int mbs; // blocks in mcu + int bcv; // block count vertical (interleaved) + int bch; // block count horizontal (interleaved) + int bc; // block count (all) (interleaved) + int ncv; // block count vertical (non interleaved) + int nch; // block count horizontal (non interleaved) + int nc; // block count (all) (non interleaved) + int sid; // statistical identity + int jid; // jpeg internal id +}; + +struct huffCodes { + unsigned short cval[ 256 ]; + unsigned short clen[ 256 ]; + unsigned short max_eobrun; +}; + +struct huffTree { + unsigned short l[ 256 ]; + unsigned short r[ 256 ]; +}; + + +/* ----------------------------------------------- + function declarations: main interface + ----------------------------------------------- */ +#if !defined( BUILD_LIB ) +INTERN void initialize_options( int argc, char** argv ); +INTERN void process_ui( void ); +INTERN inline const char* get_status( bool (*function)() ); +INTERN void show_help( void ); +#endif +INTERN void process_file( void ); +INTERN void execute( bool (*function)() ); + + +/* ----------------------------------------------- + function declarations: main functions + ----------------------------------------------- */ +#if !defined( BUILD_LIB ) +INTERN bool check_file( void ); +INTERN bool swap_streams( void ); +INTERN bool compare_output( void ); +#endif +INTERN bool reset_buffers( void ); +INTERN bool read_jpeg( void ); +INTERN bool merge_jpeg( void ); +INTERN bool decode_jpeg( void ); +INTERN bool recode_jpeg( void ); +INTERN bool adapt_icos( void ); +INTERN bool predict_dc( void ); +INTERN bool unpredict_dc( void ); +INTERN bool check_value_range( void ); +INTERN bool calc_zdst_lists( void ); +INTERN bool pack_pjg( void ); +INTERN bool unpack_pjg( void ); + + +/* ----------------------------------------------- + function declarations: jpeg-specific + ----------------------------------------------- */ + +INTERN bool jpg_setup_imginfo( void ); +INTERN bool jpg_parse_jfif( unsigned char type, unsigned int len, unsigned char* segment ); +INTERN bool jpg_rebuild_header( void ); + +INTERN int jpg_decode_block_seq( abitreader* huffr, huffTree* dctree, huffTree* actree, short* block ); +INTERN int jpg_encode_block_seq( abitwriter* huffw, huffCodes* dctbl, huffCodes* actbl, short* block ); + +INTERN int jpg_decode_dc_prg_fs( abitreader* huffr, huffTree* dctree, short* block ); +INTERN int jpg_encode_dc_prg_fs( abitwriter* huffw, huffCodes* dctbl, short* block ); +INTERN int jpg_decode_ac_prg_fs( abitreader* huffr, huffTree* actree, short* block, + int* eobrun, int from, int to ); +INTERN int jpg_encode_ac_prg_fs( abitwriter* huffw, huffCodes* actbl, short* block, + int* eobrun, int from, int to ); + +INTERN int jpg_decode_dc_prg_sa( abitreader* huffr, short* block ); +INTERN int jpg_encode_dc_prg_sa( abitwriter* huffw, short* block ); +INTERN int jpg_decode_ac_prg_sa( abitreader* huffr, huffTree* actree, short* block, + int* eobrun, int from, int to ); +INTERN int jpg_encode_ac_prg_sa( abitwriter* huffw, abytewriter* storw, huffCodes* actbl, + short* block, int* eobrun, int from, int to ); + +INTERN int jpg_decode_eobrun_sa( abitreader* huffr, short* block, int* eobrun, int from, int to ); +INTERN int jpg_encode_eobrun( abitwriter* huffw, huffCodes* actbl, int* eobrun ); +INTERN int jpg_encode_crbits( abitwriter* huffw, abytewriter* storw ); + +INTERN int jpg_next_huffcode( abitreader *huffw, huffTree *ctree ); +INTERN int jpg_next_mcupos( int* mcu, int* cmp, int* csc, int* sub, int* dpos, int* rstw ); +INTERN int jpg_next_mcuposn( int* cmp, int* dpos, int* rstw ); +INTERN int jpg_skip_eobrun( int* cmp, int* dpos, int* rstw, int* eobrun ); + +INTERN void jpg_build_huffcodes( unsigned char *clen, unsigned char *cval, + huffCodes *hc, huffTree *ht ); + +/* ----------------------------------------------- + function declarations: pjg-specific + ----------------------------------------------- */ + +INTERN bool pjg_encode_zstscan( aricoder* enc, int cmp ); +INTERN bool pjg_encode_zdst_high( aricoder* enc, int cmp ); +INTERN bool pjg_encode_zdst_low( aricoder* enc, int cmp ); +INTERN bool pjg_encode_dc( aricoder* enc, int cmp ); +INTERN bool pjg_encode_ac_high( aricoder* enc, int cmp ); +INTERN bool pjg_encode_ac_low( aricoder* enc, int cmp ); +INTERN bool pjg_encode_generic( aricoder* enc, unsigned char* data, int len ); +INTERN bool pjg_encode_bit( aricoder* enc, unsigned char bit ); + +INTERN bool pjg_decode_zstscan( aricoder* dec, int cmp ); +INTERN bool pjg_decode_zdst_high( aricoder* dec, int cmp ); +INTERN bool pjg_decode_zdst_low( aricoder* dec, int cmp ); +INTERN bool pjg_decode_dc( aricoder* dec, int cmp ); +INTERN bool pjg_decode_ac_high( aricoder* dec, int cmp ); +INTERN bool pjg_decode_ac_low( aricoder* dec, int cmp ); +INTERN bool pjg_decode_generic( aricoder* dec, unsigned char** data, int* len ); +INTERN bool pjg_decode_bit( aricoder* dec, unsigned char* bit ); + +INTERN void pjg_get_zerosort_scan( unsigned char* sv, int cmp ); +INTERN bool pjg_optimize_header( void ); +INTERN bool pjg_unoptimize_header( void ); + +INTERN void pjg_aavrg_prepare( unsigned short** abs_coeffs, int* weights, unsigned short* abs_store, int cmp ); +INTERN int pjg_aavrg_context( unsigned short** abs_coeffs, int* weights, int pos, int p_y, int p_x, int r_x ); +INTERN int pjg_lakh_context( signed short** coeffs_x, signed short** coeffs_a, int* pred_cf, int pos ); +INTERN void get_context_nnb( int pos, int w, int *a, int *b ); + + +/* ----------------------------------------------- + function declarations: DCT + ----------------------------------------------- */ + +#if !defined(BUILD_LIB) && defined(DEV_BUILD) +INTERN int idct_2d_fst_8x8( int cmp, int dpos, int ix, int iy ); +#endif +INTERN int idct_2d_fst_1x8( int cmp, int dpos, int ix, int iy ); +INTERN int idct_2d_fst_8x1( int cmp, int dpos, int ix, int iy ); + + +/* ----------------------------------------------- + function declarations: prediction + ----------------------------------------------- */ + +#if defined( USE_PLOCOI ) +INTERN int dc_coll_predictor( int cmp, int dpos ); +#else +INTERN int dc_1ddct_predictor( int cmp, int dpos ); +#endif +INTERN inline int plocoi( int a, int b, int c ); +INTERN inline int median_int( int* values, int size ); +INTERN inline float median_float( float* values, int size ); + + +/* ----------------------------------------------- + function declarations: miscelaneous helpers + ----------------------------------------------- */ +#if !defined( BUILD_LIB ) +INTERN inline void progress_bar( int current, int last ); +INTERN inline char* create_filename( const char* base, const char* extension ); +INTERN inline char* unique_filename( const char* base, const char* extension ); +INTERN inline void set_extension( char* filename, const char* extension ); +INTERN inline void add_underscore( char* filename ); +#endif +INTERN inline bool file_exists( const char* filename ); + + +/* ----------------------------------------------- + function declarations: developers functions + ----------------------------------------------- */ + +// these are developers functions, they are not needed +// in any way to compress jpg or decompress pjg +#if !defined(BUILD_LIB) && defined(DEV_BUILD) +INTERN int collmode = 0; // write mode for collections: 0 -> std, 1 -> dhf, 2 -> squ, 3 -> unc +INTERN bool dump_hdr( void ); +INTERN bool dump_huf( void ); +INTERN bool dump_coll( void ); +INTERN bool dump_zdst( void ); +INTERN bool dump_file( const char* base, const char* ext, void* data, int bpv, int size ); +INTERN bool dump_errfile( void ); +INTERN bool dump_info( void ); +INTERN bool dump_dist( void ); +INTERN bool dump_pgm( void ); +#endif + + +/* ----------------------------------------------- + global variables: library only variables + ----------------------------------------------- */ +#if defined(BUILD_LIB) +INTERN int lib_in_type = -1; +INTERN int lib_out_type = -1; +#endif + + +/* ----------------------------------------------- + global variables: data storage + ----------------------------------------------- */ + +INTERN unsigned short qtables[4][64]; // quantization tables +INTERN huffCodes hcodes[2][4]; // huffman codes +INTERN huffTree htrees[2][4]; // huffman decoding trees +INTERN unsigned char htset[2][4]; // 1 if huffman table is set + +INTERN unsigned char* grbgdata = NULL; // garbage data +INTERN unsigned char* hdrdata = NULL; // header data +INTERN unsigned char* huffdata = NULL; // huffman coded data +INTERN int hufs = 0 ; // size of huffman data +INTERN int hdrs = 0 ; // size of header +INTERN int grbs = 0 ; // size of garbage + +INTERN unsigned int* rstp = NULL; // restart markers positions in huffdata +INTERN unsigned int* scnp = NULL; // scan start positions in huffdata +INTERN int rstc = 0 ; // count of restart markers +INTERN int scnc = 0 ; // count of scans +INTERN int rsti = 0 ; // restart interval +INTERN char padbit = -1 ; // padbit (for huffman coding) +INTERN unsigned char* rst_err = NULL; // number of wrong-set RST markers per scan + +INTERN unsigned char* zdstdata[4] = { NULL }; // zero distribution (# of non-zeroes) lists (for higher 7x7 block) +INTERN unsigned char* eobxhigh[4] = { NULL }; // eob in x direction (for higher 7x7 block) +INTERN unsigned char* eobyhigh[4] = { NULL }; // eob in y direction (for higher 7x7 block) +INTERN unsigned char* zdstxlow[4] = { NULL }; // # of non zeroes for first row +INTERN unsigned char* zdstylow[4] = { NULL }; // # of non zeroes for first collumn +INTERN signed short* colldata[4][64] = {{NULL}}; // collection sorted DCT coefficients + +INTERN unsigned char* freqscan[4] = { NULL }; // optimized order for frequency scans (only pointers to scans) +INTERN unsigned char zsrtscan[4][64]; // zero optimized frequency scan + +INTERN int adpt_idct_8x8[ 4 ][ 8 * 8 * 8 * 8 ]; // precalculated/adapted values for idct (8x8) +INTERN int adpt_idct_1x8[ 4 ][ 1 * 1 * 8 * 8 ]; // precalculated/adapted values for idct (1x8) +INTERN int adpt_idct_8x1[ 4 ][ 8 * 8 * 1 * 1 ]; // precalculated/adapted values for idct (8x1) + + +/* ----------------------------------------------- + global variables: info about image + ----------------------------------------------- */ + +// seperate info for each color component +INTERN componentInfo cmpnfo[ 4 ]; + +INTERN int cmpc = 0; // component count +INTERN int imgwidth = 0; // width of image +INTERN int imgheight = 0; // height of image + +INTERN int sfhm = 0; // max horizontal sample factor +INTERN int sfvm = 0; // max verical sample factor +INTERN int mcuv = 0; // mcus per line +INTERN int mcuh = 0; // mcus per collumn +INTERN int mcuc = 0; // count of mcus + + +/* ----------------------------------------------- + global variables: info about current scan + ----------------------------------------------- */ + +INTERN int cs_cmpc = 0 ; // component count in current scan +INTERN int cs_cmp[ 4 ] = { 0 }; // component numbers in current scan +INTERN int cs_from = 0 ; // begin - band of current scan ( inclusive ) +INTERN int cs_to = 0 ; // end - band of current scan ( inclusive ) +INTERN int cs_sah = 0 ; // successive approximation bit pos high +INTERN int cs_sal = 0 ; // successive approximation bit pos low + + +/* ----------------------------------------------- + global variables: info about files + ----------------------------------------------- */ + +INTERN char* jpgfilename = NULL; // name of JPEG file +INTERN char* pjgfilename = NULL; // name of PJG file +INTERN int jpgfilesize; // size of JPEG file +INTERN int pjgfilesize; // size of PJG file +INTERN int jpegtype = 0; // type of JPEG coding: 0->unknown, 1->sequential, 2->progressive +INTERN int filetype; // type of current file +INTERN iostream* str_in = NULL; // input stream +INTERN iostream* str_out = NULL; // output stream + +#if !defined(BUILD_LIB) +INTERN iostream* str_str = NULL; // storage stream + +INTERN char** filelist = NULL; // list of files to process +INTERN int file_cnt = 0; // count of files in list +INTERN int file_no = 0; // number of current file + +INTERN char** err_list = NULL; // list of error messages +INTERN int* err_tp = NULL; // list of error types +#endif + +#if defined(DEV_INFOS) +INTERN int dev_size_hdr = 0; +INTERN int dev_size_cmp[ 4 ] = { 0 }; +INTERN int dev_size_zsr[ 4 ] = { 0 }; +INTERN int dev_size_dc[ 4 ] = { 0 }; +INTERN int dev_size_ach[ 4 ] = { 0 }; +INTERN int dev_size_acl[ 4 ] = { 0 }; +INTERN int dev_size_zdh[ 4 ] = { 0 }; +INTERN int dev_size_zdl[ 4 ] = { 0 }; +#endif + + +/* ----------------------------------------------- + global variables: messages + ----------------------------------------------- */ + +INTERN char errormessage [ MSG_SIZE ]; +INTERN bool (*errorfunction)(); +INTERN int errorlevel; +// meaning of errorlevel: +// -1 -> wrong input +// 0 -> no error +// 1 -> warning +// 2 -> fatal error + + +/* ----------------------------------------------- + global variables: settings + ----------------------------------------------- */ + +#if !defined( BUILD_LIB ) +INTERN int verbosity = -1; // level of verbosity +INTERN bool overwrite = false; // overwrite files yes / no +INTERN bool wait_exit = true; // pause after finished yes / no +INTERN int verify_lv = 0; // verification level ( none (0), simple (1), detailed output (2) ) +INTERN int err_tol = 1; // error threshold ( proceed on warnings yes (2) / no (1) ) +INTERN bool disc_meta = false; // discard meta-info yes / no + +INTERN bool developer = false; // allow developers functions yes/no +INTERN bool auto_set = true; // automatic find best settings yes/no +INTERN int action = A_COMPRESS;// what to do with JPEG/PJG files + +INTERN FILE* msgout = stdout;// stream for output of messages +INTERN bool pipe_on = false; // use stdin/stdout instead of filelist +#else +INTERN int err_tol = 1; // error threshold ( proceed on warnings yes (2) / no (1) ) +INTERN bool disc_meta = false; // discard meta-info yes / no +INTERN bool auto_set = true; // automatic find best settings yes/no +INTERN int action = A_COMPRESS;// what to do with JPEG/PJG files +#endif + +INTERN unsigned char nois_trs[ 4 ] = {6,6,6,6}; // bit pattern noise threshold +INTERN unsigned char segm_cnt[ 4 ] = {10,10,10,10}; // number of segments +#if !defined( BUILD_LIB ) +INTERN unsigned char orig_set[ 8 ] = { 0 }; // store array for settings +#endif + + +/* ----------------------------------------------- + global variables: info about program + ----------------------------------------------- */ + +INTERN const unsigned char appversion = 25; +INTERN const char* subversion = "g"; +INTERN const char* apptitle = "packJPG"; +INTERN const char* appname = "packjpg"; +INTERN const char* versiondate = "09/14/2013"; +INTERN const char* author = "Matthias Stirner / Se"; +#if !defined(BUILD_LIB) +INTERN const char* website = "http://www.elektronik.htw-aalen.de/packjpg/"; +INTERN const char* copyright = "2006-2013 HTW Aalen University & Matthias Stirner"; +INTERN const char* email = "packjpg (at) htw-aalen.de"; +INTERN const char* pjg_ext = "pjg"; +INTERN const char* jpg_ext = "jpg"; +#endif +INTERN const char pjg_magic[] = { 'J', 'S' }; + + +/* ----------------------------------------------- + main-function + ----------------------------------------------- */ + +#if !defined(BUILD_LIB) +int main( int argc, char** argv ) +{ + sprintf( errormessage, "no errormessage specified" ); + + clock_t begin, end; + + int error_cnt = 0; + int warn_cnt = 0; + + double acc_jpgsize = 0; + double acc_pjgsize = 0; + + int kbps; + double cr; + double total; + + errorlevel = 0; + + + // read options from command line + initialize_options( argc, argv ); + + // write program info to screen + fprintf( msgout, "\n--> %s v%i.%i%s (%s) by %s <--\n", + apptitle, appversion / 10, appversion % 10, subversion, versiondate, author ); + fprintf( msgout, "Copyright %s\nAll rights reserved\n\n", copyright ); + + // check if user input is wrong, show help screen if it is + if ( ( file_cnt == 0 ) || + ( ( !developer ) && ( (action != A_COMPRESS) || (!auto_set) || (verify_lv > 1) ) ) ) { + show_help(); + return -1; + } + + // display warning if not using automatic settings + if ( !auto_set ) { + fprintf( msgout, " custom compression settings: \n" ); + fprintf( msgout, " -------------------------------------------------\n" ); + fprintf( msgout, " no of segments -> %3i[0] %3i[1] %3i[2] %3i[3]\n", + segm_cnt[0], segm_cnt[1], segm_cnt[2], segm_cnt[3] ); + fprintf( msgout, " noise threshold -> %3i[0] %3i[1] %3i[2] %3i[3]\n", + nois_trs[0], nois_trs[1], nois_trs[2], nois_trs[3] ); + fprintf( msgout, " -------------------------------------------------\n\n" ); + } + + // (re)set program has to be done first + reset_buffers(); + + // process file(s) - this is the main function routine + begin = clock(); + for ( file_no = 0; file_no < file_cnt; file_no++ ) { + // process current file + process_ui(); + // store error message and type if any + if ( errorlevel > 0 ) { + err_list[ file_no ] = (char*) calloc( MSG_SIZE, sizeof( char ) ); + err_tp[ file_no ] = errorlevel; + if ( err_list[ file_no ] != NULL ) + strcpy( err_list[ file_no ], errormessage ); + } + // count errors / warnings / file sizes + if ( errorlevel >= err_tol ) error_cnt++; + else { + if ( errorlevel == 1 ) warn_cnt++; + acc_jpgsize += jpgfilesize; + acc_pjgsize += pjgfilesize; + } + } + end = clock(); + + // errors summary: only needed for -v2 or progress bar + if ( ( verbosity == -1 ) || ( verbosity == 2 ) ) { + // print summary of errors to screen + if ( error_cnt > 0 ) { + fprintf( stderr, "\n\nfiles with errors:\n" ); + fprintf( stderr, "------------------\n" ); + for ( file_no = 0; file_no < file_cnt; file_no++ ) { + if ( err_tp[ file_no ] >= err_tol ) { + fprintf( stderr, "%s (%s)\n", filelist[ file_no ], err_list[ file_no ] ); + } + } + } + // print summary of warnings to screen + if ( warn_cnt > 0 ) { + fprintf( stderr, "\n\nfiles with warnings:\n" ); + fprintf( stderr, "------------------\n" ); + for ( file_no = 0; file_no < file_cnt; file_no++ ) { + if ( err_tp[ file_no ] == 1 ) { + fprintf( stderr, "%s (%s)\n", filelist[ file_no ], err_list[ file_no ] ); + } + } + } + } + + // show statistics + fprintf( msgout, "\n\n-> %i file(s) processed, %i error(s), %i warning(s)\n", + file_cnt, error_cnt, warn_cnt ); + if ( ( file_cnt > error_cnt ) && ( verbosity != 0 ) && + ( action == A_COMPRESS ) ) { + acc_jpgsize /= 1024.0; acc_pjgsize /= 1024.0; + total = (double) ( end - begin ) / CLOCKS_PER_SEC; + kbps = ( total > 0 ) ? ( acc_jpgsize / total ) : acc_jpgsize; + cr = ( acc_jpgsize > 0 ) ? ( 100.0 * acc_pjgsize / acc_jpgsize ) : 0; + + fprintf( msgout, " --------------------------------- \n" ); + if ( total >= 0 ) { + fprintf( msgout, " total time : %8.2f sec\n", total ); + fprintf( msgout, " avrg. kbyte per s : %8i byte\n", kbps ); + } + else { + fprintf( msgout, " total time : %8s sec\n", "N/A" ); + fprintf( msgout, " avrg. kbyte per s : %8s byte\n", "N/A" ); + } + fprintf( msgout, " avrg. comp. ratio : %8.2f %%\n", cr ); + fprintf( msgout, " --------------------------------- \n" ); + #if defined(DEV_INFOS) + if ( acc_jpgsize > 0 ) { + fprintf( msgout, " header %% : %8.2f %%\n", 100.0 * dev_size_hdr / acc_jpgsize ); + if ( dev_size_cmp[0] > 0 ) fprintf( msgout, " component [0] %% : %8.2f %%\n", 100.0 * dev_size_cmp[0] / acc_jpgsize ); + if ( dev_size_cmp[1] > 0 ) fprintf( msgout, " component [1] %% : %8.2f %%\n", 100.0 * dev_size_cmp[1] / acc_jpgsize ); + if ( dev_size_cmp[2] > 0 ) fprintf( msgout, " component [2] %% : %8.2f %%\n", 100.0 * dev_size_cmp[2] / acc_jpgsize ); + if ( dev_size_cmp[3] > 0 ) fprintf( msgout, " component [3] %% : %8.2f %%\n", 100.0 * dev_size_cmp[3] / acc_jpgsize ); + fprintf( msgout, " --------------------------------- \n" ); + for ( int i = 0; i < 4; i++ ) { + if ( dev_size_cmp[i] == 0 ) break; + fprintf( msgout, " ac coeffs h [%i] %% : %8.2f %%\n", i, 100.0 * dev_size_ach[i] / acc_jpgsize ); + fprintf( msgout, " ac coeffs l [%i] %% : %8.2f %%\n", i, 100.0 * dev_size_acl[i] / acc_jpgsize ); + fprintf( msgout, " dc coeffs [%i] %% : %8.2f %%\n", i, 100.0 * dev_size_dc[i] / acc_jpgsize ); + fprintf( msgout, " zero dist h [%i] %% : %8.2f %%\n", i, 100.0 * dev_size_zdh[i] / acc_jpgsize ); + fprintf( msgout, " zero dist l [%i] %% : %8.2f %%\n", i, 100.0 * dev_size_zdl[i] / acc_jpgsize ); + fprintf( msgout, " zero sort [%i] %% : %8.2f %%\n", i, 100.0 * dev_size_zsr[i] / acc_jpgsize ); + fprintf( msgout, " --------------------------------- \n" ); + } + } + #endif + } + + // pause before exit + if ( wait_exit && ( msgout != stderr ) ) { + fprintf( msgout, "\n\n< press ENTER >\n" ); + fgetc( stdin ); + } + + + return 0; +} +#endif + +/* ----------------------- Begin of library only functions -------------------------- */ + +/* ----------------------------------------------- + DLL export converter function + ----------------------------------------------- */ + +#if defined(BUILD_LIB) +EXPORT bool pjglib_convert_stream2stream( char* msg ) +{ + // process in main function + return pjglib_convert_stream2mem( NULL, NULL, msg ); +} +#endif + + +/* ----------------------------------------------- + DLL export converter function + ----------------------------------------------- */ + +#if defined(BUILD_LIB) +EXPORT bool 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( NULL, NULL, msg ); +} +#endif + + +/* ----------------------------------------------- + DLL export converter function + ----------------------------------------------- */ + +#if defined(BUILD_LIB) +EXPORT bool 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 != NULL ) && ( out_size != NULL ) ) { + *out_size = str_out->getsize(); + *out_file = str_out->getptr(); + } + + // close iostreams + if ( str_in != NULL ) delete( str_in ); str_in = NULL; + if ( str_out != NULL ) delete( str_out ); str_out = NULL; + + 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 != NULL ) 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 != NULL ) { + 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; +} +#endif + + +/* ----------------------------------------------- + DLL export init input (file/mem) + ----------------------------------------------- */ + +#if defined(BUILD_LIB) +EXPORT void 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 = NULL; + errorlevel = 0; + jpgfilesize = 0; + pjgfilesize = 0; + + // open input stream, check for errors + str_in = new iostream( in_src, in_type, in_size, 0 ); + if ( str_in->chkerr() ) { + sprintf( errormessage, "error opening input stream" ); + errorlevel = 2; + return; + } + + // open output stream, check for errors + str_out = new iostream( out_dest, out_type, 0, 1 ); + if ( str_out->chkerr() ) { + sprintf( errormessage, "error opening output stream" ); + errorlevel = 2; + return; + } + + // free memory from filenames if needed + if ( jpgfilename != NULL ) free( jpgfilename ); jpgfilename = NULL; + if ( pjgfilename != NULL ) free( pjgfilename ); pjgfilename = NULL; + + // check input stream + str_in->read( buffer, 1, 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; +} +#endif + + +/* ----------------------------------------------- + DLL export version information + ----------------------------------------------- */ + +#if defined(BUILD_LIB) +EXPORT const char* 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; +} +#endif + + +/* ----------------------------------------------- + DLL export version information + ----------------------------------------------- */ + +#if defined(BUILD_LIB) +EXPORT const char* 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; +} +#endif + +/* ----------------------- End of libary only functions -------------------------- */ + +/* ----------------------- Begin of main interface functions -------------------------- */ + + +/* ----------------------------------------------- + reads in commandline arguments + ----------------------------------------------- */ + +#if !defined(BUILD_LIB) +INTERN void initialize_options( int argc, char** argv ) +{ + int tmp_val; + char** tmp_flp; + int i; + + + // get memory for filelist & preset with NULL + filelist = (char**) calloc( argc, sizeof( char* ) ); + for ( i = 0; i < argc; i++ ) + filelist[ i ] = NULL; + + // preset temporary filelist pointer + tmp_flp = filelist; + + + // read in arguments + while ( --argc > 0 ) { + argv++; + // switches begin with '-' + if ( strcmp((*argv), "-p" ) == 0 ) { + err_tol = 2; + } + else if ( strcmp((*argv), "-d" ) == 0 ) { + disc_meta = true; + } + else if ( strcmp((*argv), "-ver" ) == 0 ) { + verify_lv = ( verify_lv < 1 ) ? 1 : verify_lv; + } + else if ( sscanf( (*argv), "-v%i", &tmp_val ) == 1 ){ + verbosity = tmp_val; + verbosity = ( verbosity < 0 ) ? 0 : verbosity; + verbosity = ( verbosity > 2 ) ? 2 : verbosity; + } + else if ( strcmp((*argv), "-vp" ) == 0 ) { + verbosity = -1; + } + else if ( strcmp((*argv), "-np" ) == 0 ) { + wait_exit = false; + } + else if ( strcmp((*argv), "-o" ) == 0 ) { + overwrite = true; + } + #if defined(DEV_BUILD) + else if ( strcmp((*argv), "-dev") == 0 ) { + developer = true; + } + else if ( strcmp((*argv), "-test") == 0 ) { + verify_lv = 2; + } + else if ( sscanf( (*argv), "-t%i,%i", &i, &tmp_val ) == 2 ) { + i = ( i < 0 ) ? 0 : i; + i = ( i > 3 ) ? 3 : i; + tmp_val = ( tmp_val < 0 ) ? 0 : tmp_val; + tmp_val = ( tmp_val > 10 ) ? 10 : tmp_val; + nois_trs[ i ] = tmp_val; + auto_set = false; + } + else if ( sscanf( (*argv), "-s%i,%i", &i, &tmp_val ) == 2 ) { + i = ( i < 0 ) ? 0 : i; + i = ( i > 3 ) ? 3 : i; + tmp_val = ( tmp_val < 1 ) ? 1 : tmp_val; + tmp_val = ( tmp_val > 49 ) ? 49 : tmp_val; + segm_cnt[ i ] = tmp_val; + auto_set = false; + } + else if ( sscanf( (*argv), "-t%i", &tmp_val ) == 1 ) { + tmp_val = ( tmp_val < 0 ) ? 0 : tmp_val; + tmp_val = ( tmp_val > 10 ) ? 10 : tmp_val; + nois_trs[0] = tmp_val; + nois_trs[1] = tmp_val; + nois_trs[2] = tmp_val; + nois_trs[3] = tmp_val; + auto_set = false; + } + else if ( sscanf( (*argv), "-s%i", &tmp_val ) == 1 ) { + tmp_val = ( tmp_val < 1 ) ? 1 : tmp_val; + tmp_val = ( tmp_val > 64 ) ? 64 : tmp_val; + segm_cnt[0] = tmp_val; + segm_cnt[1] = tmp_val; + segm_cnt[2] = tmp_val; + segm_cnt[3] = tmp_val; + auto_set = false; + } + else if ( sscanf( (*argv), "-coll%i", &tmp_val ) == 1 ) { + tmp_val = ( tmp_val < 0 ) ? 0 : tmp_val; + tmp_val = ( tmp_val > 5 ) ? 5 : tmp_val; + collmode = tmp_val; + action = A_COLL_DUMP; + } + else if ( sscanf( (*argv), "-fcol%i", &tmp_val ) == 1 ) { + tmp_val = ( tmp_val < 0 ) ? 0 : tmp_val; + tmp_val = ( tmp_val > 5 ) ? 5 : tmp_val; + collmode = tmp_val; + action = A_FCOLL_DUMP; + } + else if ( strcmp((*argv), "-split") == 0 ) { + action = A_SPLIT_DUMP; + } + else if ( strcmp((*argv), "-zdst") == 0 ) { + action = A_ZDST_DUMP; + } + else if ( strcmp((*argv), "-info") == 0 ) { + action = A_TXT_INFO; + } + else if ( strcmp((*argv), "-dist") == 0 ) { + action = A_DIST_INFO; + } + else if ( strcmp((*argv), "-pgm") == 0 ) { + action = A_PGM_DUMP; + } + else if ( ( strcmp((*argv), "-comp") == 0) ) { + action = A_COMPRESS; + } + #endif + else if ( strcmp((*argv), "-") == 0 ) { + // switch standard message out stream + msgout = stderr; + // use "-" as placeholder for stdin + *(tmp_flp++) = (char*) "-"; + } + else { + // if argument is not switch, it's a filename + *(tmp_flp++) = *argv; + } + } + + // count number of files (or filenames) in filelist + for ( file_cnt = 0; filelist[ file_cnt ] != NULL; file_cnt++ ); + + // alloc arrays for error messages and types storage + err_list = (char**) calloc( file_cnt, sizeof( char* ) ); + err_tp = (int*) calloc( file_cnt, sizeof( int ) ); + + // backup settings - needed to restore original setting later + if ( !auto_set ) { + orig_set[ 0 ] = nois_trs[ 0 ]; + orig_set[ 1 ] = nois_trs[ 1 ]; + orig_set[ 2 ] = nois_trs[ 2 ]; + orig_set[ 3 ] = nois_trs[ 3 ]; + orig_set[ 4 ] = segm_cnt[ 0 ]; + orig_set[ 5 ] = segm_cnt[ 1 ]; + orig_set[ 6 ] = segm_cnt[ 2 ]; + orig_set[ 7 ] = segm_cnt[ 3 ]; + } + else { + for ( i = 0; i < 8; i++ ) + orig_set[ i ] = 0; + } +} +#endif + + +/* ----------------------------------------------- + UI for processing one file + ----------------------------------------------- */ + +#if !defined(BUILD_LIB) +INTERN void process_ui( void ) +{ + clock_t begin, end; + const char* actionmsg = NULL; + const char* errtypemsg = NULL; + int total, bpms; + float cr; + + + errorfunction = NULL; + errorlevel = 0; + jpgfilesize = 0; + pjgfilesize = 0; + #if !defined(DEV_BUILD) + action = A_COMPRESS; + #endif + + // compare file name, set pipe if needed + if ( ( strcmp( filelist[ file_no ], "-" ) == 0 ) && ( action == A_COMPRESS ) ) { + pipe_on = true; + filelist[ file_no ] = (char*) "STDIN"; + } + else { + pipe_on = false; + } + + if ( verbosity >= 0 ) { // standard UI + fprintf( msgout, "\nProcessing file %i of %i \"%s\" -> ", + file_no + 1, file_cnt, filelist[ file_no ] ); + + if ( verbosity > 1 ) + fprintf( msgout, "\n----------------------------------------" ); + + // check input file and determine filetype + execute( check_file ); + + // get specific action message + if ( filetype == F_UNK ) actionmsg = "unknown filetype"; + else switch ( action ) { + case A_COMPRESS: actionmsg = ( filetype == F_JPG ) ? "Compressing" : "Decompressing"; break; + case A_SPLIT_DUMP: actionmsg = "Splitting"; break; + case A_COLL_DUMP: actionmsg = "Extracting Colls"; break; + case A_FCOLL_DUMP: actionmsg = "Extracting FColls"; break; + case A_ZDST_DUMP: actionmsg = "Extracting ZDST lists"; break; + case A_TXT_INFO: actionmsg = "Extracting info"; break; + case A_DIST_INFO: actionmsg = "Extracting distributions"; break; + case A_PGM_DUMP: actionmsg = "Converting"; break; + } + + if ( verbosity < 2 ) fprintf( msgout, "%s -> ", actionmsg ); + } + else { // progress bar UI + // update progress message + fprintf( msgout, "Processing file %2i of %2i ", file_no + 1, file_cnt ); + progress_bar( file_no, file_cnt ); + fprintf( msgout, "\r" ); + execute( check_file ); + } + fflush( msgout ); + + + // main function routine + begin = clock(); + + // streams are initiated, start processing file + process_file(); + + // close iostreams + if ( str_in != NULL ) delete( str_in ); str_in = NULL; + if ( str_out != NULL ) delete( str_out ); str_out = NULL; + if ( str_str != NULL ) delete( str_str ); str_str = NULL; + // delete if broken or if output not needed + if ( ( !pipe_on ) && ( ( errorlevel >= err_tol ) || ( action != A_COMPRESS ) ) ) { + if ( filetype == F_JPG ) { + if ( file_exists( pjgfilename ) ) remove( pjgfilename ); + } else if ( filetype == F_PJG ) { + if ( file_exists( jpgfilename ) ) remove( jpgfilename ); + } + } + + end = clock(); + + // speed and compression ratio calculation + total = (int) ( (double) (( end - begin ) * 1000) / CLOCKS_PER_SEC ); + bpms = ( total > 0 ) ? ( jpgfilesize / total ) : jpgfilesize; + cr = ( jpgfilesize > 0 ) ? ( 100.0 * pjgfilesize / jpgfilesize ) : 0; + + + if ( verbosity >= 0 ) { // standard UI + if ( verbosity > 1 ) + fprintf( msgout, "\n----------------------------------------" ); + + // display success/failure message + switch ( verbosity ) { + case 0: + if ( errorlevel < err_tol ) { + if ( action == A_COMPRESS ) fprintf( msgout, "%.2f%%", cr ); + else fprintf( msgout, "DONE" ); + } + else fprintf( msgout, "ERROR" ); + if ( errorlevel > 0 ) fprintf( msgout, "\n" ); + break; + + case 1: + fprintf( msgout, "%s\n", ( errorlevel < err_tol ) ? "DONE" : "ERROR" ); + break; + + case 2: + if ( errorlevel < err_tol ) fprintf( msgout, "\n-> %s OK\n", actionmsg ); + else fprintf( msgout, "\n-> %s ERROR\n", actionmsg ); + break; + } + + // set type of error message + switch ( errorlevel ) { + case 0: errtypemsg = "none"; break; + case 1: errtypemsg = ( err_tol > 1 ) ? "warning (ignored)" : "warning (skipped file)"; break; + case 2: errtypemsg = "fatal error"; break; + } + + // error/ warning message + if ( errorlevel > 0 ) { + fprintf( msgout, " %s -> %s:\n", get_status( errorfunction ), errtypemsg ); + fprintf( msgout, " %s\n", errormessage ); + } + if ( (verbosity > 0) && (errorlevel < err_tol) && (action == A_COMPRESS) ) { + if ( total >= 0 ) { + fprintf( msgout, " time taken : %7i msec\n", total ); + fprintf( msgout, " byte per ms : %7i byte\n", bpms ); + } + else { + fprintf( msgout, " time taken : %7s msec\n", "N/A" ); + fprintf( msgout, " byte per ms : %7s byte\n", "N/A" ); + } + fprintf( msgout, " comp. ratio : %7.2f %%\n", cr ); + } + if ( ( verbosity > 1 ) && ( action == A_COMPRESS ) ) + fprintf( msgout, "\n" ); + } + else { // progress bar UI + // if this is the last file, update progress bar one last time + if ( file_no + 1 == file_cnt ) { + // update progress message + fprintf( msgout, "Processed %2i of %2i files ", file_no + 1, file_cnt ); + progress_bar( 1, 1 ); + fprintf( msgout, "\r" ); + } + } +} +#endif + + +/* ----------------------------------------------- + gets statusmessage for function + ----------------------------------------------- */ + +#if !defined(BUILD_LIB) +INTERN inline const char* get_status( bool (*function)() ) +{ + if ( function == NULL ) { + return "unknown action"; + } else if ( function == *check_file ) { + return "Determining filetype"; + } else if ( function == *read_jpeg ) { + return "Reading header & image data"; + } else if ( function == *merge_jpeg ) { + return "Merging header & image data"; + } else if ( function == *decode_jpeg ) { + return "Decompressing JPEG image data"; + } else if ( function == *recode_jpeg ) { + return "Recompressing JPEG image data"; + } else if ( function == *adapt_icos ) { + return "Adapting DCT precalc. tables"; + } else if ( function == *predict_dc ) { + return "Applying prediction to DC"; + } else if ( function == *unpredict_dc ) { + return "Removing prediction from DC"; + } else if ( function == *check_value_range ) { + return "Checking values range"; + } else if ( function == *calc_zdst_lists ) { + return "Calculating zero dist lists"; + } else if ( function == *pack_pjg ) { + return "Compressing data to PJG"; + } else if ( function == *unpack_pjg ) { + return "Uncompressing data from PJG"; + } else if ( function == *swap_streams ) { + return "Swapping input/output streams"; + } else if ( function == *compare_output ) { + return "Verifying output stream"; + } else if ( function == *reset_buffers ) { + return "Resetting program"; + } + #if defined(DEV_BUILD) + else if ( function == *dump_hdr ) { + return "Writing header data to file"; + } else if ( function == *dump_huf ) { + return "Writing huffman data to file"; + } else if ( function == *dump_coll ) { + return "Writing collections to files"; + } else if ( function == *dump_zdst ) { + return "Writing zdist lists to files"; + } else if ( function == *dump_errfile ) { + return "Writing error info to file"; + } else if ( function == *dump_info ) { + return "Writing info to files"; + } else if ( function == *dump_dist ) { + return "Writing distributions to files"; + } else if ( function == *dump_pgm ) { + return "Writing converted image to pgm"; + } + #endif + else { + return "Function description missing!"; + } +} +#endif + + +/* ----------------------------------------------- + shows help in case of wrong input + ----------------------------------------------- */ + +#if !defined(BUILD_LIB) +INTERN void show_help( void ) +{ + fprintf( msgout, "\n" ); + fprintf( msgout, "Website: %s\n", website ); + fprintf( msgout, "Email : %s\n", email ); + fprintf( msgout, "\n" ); + fprintf( msgout, "Usage: %s [switches] [filename(s)]", appname ); + fprintf( msgout, "\n" ); + fprintf( msgout, "\n" ); + fprintf( msgout, " [-ver] verify files after processing\n" ); + fprintf( msgout, " [-v?] set level of verbosity (max: 2) (def: 0)\n" ); + fprintf( msgout, " [-np] no pause after processing files\n" ); + fprintf( msgout, " [-o] overwrite existing files\n" ); + fprintf( msgout, " [-p] proceed on warnings\n" ); + fprintf( msgout, " [-d] discard meta-info\n" ); + #if defined(DEV_BUILD) + if ( developer ) { + fprintf( msgout, "\n" ); + fprintf( msgout, " [-s?] set global number of segments (1<=s<=49)\n" ); + fprintf( msgout, " [-t?] set global noise threshold (0<=t<=10)\n" ); + fprintf( msgout, "\n" ); + fprintf( msgout, " [-s?,?] set number of segments for component\n" ); + fprintf( msgout, " [-t?,?] set noise threshold for component\n" ); + fprintf( msgout, "\n" ); + fprintf( msgout, " [-test] test algorithms, alert if error\n" ); + fprintf( msgout, " [-split] split jpeg (to header & image data)\n" ); + fprintf( msgout, " [-coll?] write collections (0=std,1=dhf,2=squ,3=unc)\n" ); + fprintf( msgout, " [-fcol?] write predicted collections (see above)\n" ); + fprintf( msgout, " [-zdst] write zero distribution lists\n" ); + fprintf( msgout, " [-info] write debug info to .nfo file\n" ); + fprintf( msgout, " [-dist] write distribution data to file\n" ); + fprintf( msgout, " [-pgm] convert and write to pgm files\n" ); + } + #endif + fprintf( msgout, "\n" ); + fprintf( msgout, "Examples: \"%s -v1 -o baboon.%s\"\n", appname, pjg_ext ); + fprintf( msgout, " \"%s -p *.%s\"\n", appname, jpg_ext ); +} +#endif + + +/* ----------------------------------------------- + processes one file + ----------------------------------------------- */ + +INTERN void process_file( void ) +{ + if ( filetype == F_JPG ) { + switch ( action ) { + case A_COMPRESS: + execute( read_jpeg ); + execute( decode_jpeg ); + execute( check_value_range ); + execute( adapt_icos ); + execute( predict_dc ); + execute( calc_zdst_lists ); + execute( pack_pjg ); + #if !defined(BUILD_LIB) + if ( verify_lv > 0 ) { // verifcation + execute( reset_buffers ); + execute( swap_streams ); + execute( unpack_pjg ); + execute( adapt_icos ); + execute( unpredict_dc ); + execute( recode_jpeg ); + execute( merge_jpeg ); + execute( compare_output ); + } + #endif + break; + + #if !defined(BUILD_LIB) && defined(DEV_BUILD) + case A_SPLIT_DUMP: + execute( read_jpeg ); + execute( dump_hdr ); + execute( dump_huf ); + break; + + case A_COLL_DUMP: + execute( read_jpeg ); + execute( decode_jpeg ); + execute( dump_coll ); + break; + + case A_FCOLL_DUMP: + execute( read_jpeg ); + execute( decode_jpeg ); + execute( check_value_range ); + execute( adapt_icos ); + execute( predict_dc ); + execute( dump_coll ); + break; + + case A_ZDST_DUMP: + execute( read_jpeg ); + execute( decode_jpeg ); + execute( check_value_range ); + execute( adapt_icos ); + execute( predict_dc ); + execute( calc_zdst_lists ); + execute( dump_zdst ); + break; + + case A_TXT_INFO: + execute( read_jpeg ); + execute( dump_info ); + break; + + case A_DIST_INFO: + execute( read_jpeg ); + execute( decode_jpeg ); + execute( check_value_range ); + execute( adapt_icos ); + execute( predict_dc ); + execute( dump_dist ); + break; + + case A_PGM_DUMP: + execute( read_jpeg ); + execute( decode_jpeg ); + execute( adapt_icos ); + execute( dump_pgm ); + break; + #else + default: + break; + #endif + } + } + else if ( filetype == F_PJG ) { + switch ( action ) + { + case A_COMPRESS: + execute( unpack_pjg ); + execute( adapt_icos ); + execute( unpredict_dc ); + execute( recode_jpeg ); + execute( merge_jpeg ); + #if !defined(BUILD_LIB) + if ( verify_lv > 0 ) { // verify + execute( reset_buffers ); + execute( swap_streams ); + execute( read_jpeg ); + execute( decode_jpeg ); + execute( check_value_range ); + execute( adapt_icos ); + execute( predict_dc ); + execute( calc_zdst_lists ); + execute( pack_pjg ); + execute( compare_output ); + } + #endif + break; + + #if !defined(BUILD_LIB) && defined(DEV_BUILD) + case A_SPLIT_DUMP: + execute( unpack_pjg ); + execute( adapt_icos ); + execute( unpredict_dc ); + execute( recode_jpeg ); + execute( dump_hdr ); + execute( dump_huf ); + break; + + case A_COLL_DUMP: + execute( unpack_pjg ); + execute( adapt_icos ); + execute( unpredict_dc ); + execute( dump_coll ); + break; + + case A_FCOLL_DUMP: + execute( unpack_pjg ); + execute( dump_coll ); + break; + + case A_ZDST_DUMP: + execute( unpack_pjg ); + execute( dump_zdst ); + break; + + case A_TXT_INFO: + execute( unpack_pjg ); + execute( dump_info ); + break; + + case A_DIST_INFO: + execute( unpack_pjg ); + execute( dump_dist ); + break; + + case A_PGM_DUMP: + execute( unpack_pjg ); + execute( adapt_icos ); + execute( unpredict_dc ); + execute( dump_pgm ); + break; + #else + default: + break; + #endif + } + } + #if !defined(BUILD_LIB) && defined(DEV_BUILD) + // write error file if verify lv > 1 + if ( ( verify_lv > 1 ) && ( errorlevel >= err_tol ) ) + dump_errfile(); + #endif + // reset buffers + reset_buffers(); +} + + +/* ----------------------------------------------- + main-function execution routine + ----------------------------------------------- */ + +INTERN void execute( bool (*function)() ) +{ + if ( errorlevel < err_tol ) { + #if !defined BUILD_LIB + clock_t begin, end; + bool success; + int total; + + // write statusmessage + if ( verbosity == 2 ) { + fprintf( msgout, "\n%s ", get_status( function ) ); + for ( int i = strlen( get_status( function ) ); i <= 30; i++ ) + fprintf( msgout, " " ); + } + + // set starttime + begin = clock(); + // call function + success = ( *function )(); + // set endtime + end = clock(); + + if ( ( errorlevel > 0 ) && ( errorfunction == NULL ) ) + errorfunction = function; + + // write time or failure notice + if ( success ) { + total = (int) ( (double) (( end - begin ) * 1000) / CLOCKS_PER_SEC ); + if ( verbosity == 2 ) fprintf( msgout, "%6ims", ( total >= 0 ) ? total : -1 ); + } + else { + errorfunction = function; + if ( verbosity == 2 ) fprintf( msgout, "%8s", "ERROR" ); + } + #else + // call function + ( *function )(); + + // store errorfunction if needed + if ( ( errorlevel > 0 ) && ( errorfunction == NULL ) ) + errorfunction = function; + #endif + } +} + +/* ----------------------- End of main interface functions -------------------------- */ + +/* ----------------------- Begin of main functions -------------------------- */ + + +/* ----------------------------------------------- + check file and determine filetype + ----------------------------------------------- */ + +#if !defined(BUILD_LIB) +INTERN bool check_file( void ) +{ + unsigned char fileid[ 2 ] = { 0, 0 }; + const char* filename = filelist[ file_no ]; + + + // open input stream, check for errors + str_in = new iostream( (void*) filename, ( !pipe_on ) ? 0 : 2, 0, 0 ); + if ( str_in->chkerr() ) { + sprintf( errormessage, FRD_ERRMSG, filename ); + errorlevel = 2; + return false; + } + + // free memory from filenames if needed + if ( jpgfilename != NULL ) free( jpgfilename ); jpgfilename = NULL; + if ( pjgfilename != NULL ) free( pjgfilename ); pjgfilename = NULL; + + // immediately return error if 2 bytes can't be read + if ( str_in->read( fileid, 1, 2 ) != 2 ) { + filetype = F_UNK; + sprintf( errormessage, "file doesn't contain enough data" ); + errorlevel = 2; + return false; + } + + // check file id, determine filetype + if ( ( fileid[0] == 0xFF ) && ( fileid[1] == 0xD8 ) ) { + // file is JPEG + filetype = F_JPG; + // create filenames + if ( !pipe_on ) { + jpgfilename = (char*) calloc( strlen( filename ) + 1, sizeof( char ) ); + strcpy( jpgfilename, filename ); + pjgfilename = ( overwrite ) ? + create_filename( filename, (char*) pjg_ext ) : + unique_filename( filename, (char*) pjg_ext ); + } + else { + jpgfilename = create_filename( "STDIN", NULL ); + pjgfilename = create_filename( "STDOUT", NULL ); + } + // open output stream, check for errors + str_out = new iostream( (void*) pjgfilename, ( !pipe_on ) ? 0 : 2, 0, 1 ); + if ( str_out->chkerr() ) { + sprintf( errormessage, FWR_ERRMSG, pjgfilename ); + errorlevel = 2; + return false; + } + // JPEG specific settings - restore original settings + if ( orig_set[ 0 ] == 0 ) + auto_set = true; + else { + nois_trs[ 0 ] = orig_set[ 0 ]; + nois_trs[ 1 ] = orig_set[ 1 ]; + nois_trs[ 2 ] = orig_set[ 2 ]; + nois_trs[ 3 ] = orig_set[ 3 ]; + segm_cnt[ 0 ] = orig_set[ 4 ]; + segm_cnt[ 1 ] = orig_set[ 5 ]; + segm_cnt[ 2 ] = orig_set[ 6 ]; + segm_cnt[ 3 ] = orig_set[ 7 ]; + auto_set = false; + } + } + else if ( ( fileid[0] == pjg_magic[0] ) && ( fileid[1] == pjg_magic[1] ) ) { + // file is PJG + filetype = F_PJG; + // create filenames + if ( !pipe_on ) { + pjgfilename = (char*) calloc( strlen( filename ) + 1, sizeof( char ) ); + strcpy( pjgfilename, filename ); + jpgfilename = ( overwrite ) ? + create_filename( filename, (char*) jpg_ext ) : + unique_filename( filename, (char*) jpg_ext ); + } + else { + jpgfilename = create_filename( "STDOUT", NULL ); + pjgfilename = create_filename( "STDIN", NULL ); + } + // open output stream, check for errors + str_out = new iostream( (void*) jpgfilename, ( !pipe_on ) ? 0 : 2, 0, 1 ); + if ( str_out->chkerr() ) { + sprintf( errormessage, FWR_ERRMSG, jpgfilename ); + errorlevel = 2; + return false; + } + // PJG specific settings - auto unless specified otherwise + auto_set = true; + } + else { + // file is neither + filetype = F_UNK; + sprintf( errormessage, "filetype of file \"%s\" is unknown", filename ); + errorlevel = 2; + return false; + } + + + return true; +} +#endif + + +/* ----------------------------------------------- + swap streams / init verification + ----------------------------------------------- */ + +#if !defined(BUILD_LIB) +INTERN bool swap_streams( void ) +{ + char dmp[ 2 ]; + + // store input stream + str_str = str_in; + str_str->rewind(); + + // replace input stream by output stream / switch mode for reading / read first bytes + str_in = str_out; + str_in->switch_mode(); + str_in->read( dmp, 1, 2 ); + + // open new stream for output / check for errors + str_out = new iostream( NULL, 1, 0, 1 ); + if ( str_out->chkerr() ) { + sprintf( errormessage, "error opening comparison stream" ); + errorlevel = 2; + return false; + } + + + return true; +} +#endif + + +/* ----------------------------------------------- + comparison between input & output + ----------------------------------------------- */ + +#if !defined(BUILD_LIB) +INTERN bool compare_output( void ) +{ + unsigned char* buff_ori; + unsigned char* buff_cmp; + int bsize = 1024; + int dsize; + int i, b; + + + // init buffer arrays + buff_ori = ( unsigned char* ) calloc( bsize, sizeof( char ) ); + buff_cmp = ( unsigned char* ) calloc( bsize, sizeof( char ) ); + if ( ( buff_ori == NULL ) || ( buff_cmp == NULL ) ) { + sprintf( errormessage, MEM_ERRMSG ); + errorlevel = 2; + return false; + } + + // switch output stream mode / check for stream errors + str_out->switch_mode(); + while ( true ) { + if ( str_out->chkerr() ) + sprintf( errormessage, "error in comparison stream" ); + else if ( str_in->chkerr() ) + sprintf( errormessage, "error in output stream" ); + else if ( str_str->chkerr() ) + sprintf( errormessage, "error in input stream" ); + else break; + errorlevel = 2; + return false; + } + + // compare sizes + dsize = str_str->getsize(); + if ( str_out->getsize() != dsize ) { + sprintf( errormessage, "file sizes do not match" ); + errorlevel = 2; + return false; + } + + // compare files byte by byte + for ( i = 0; i < dsize; i++ ) { + b = i % bsize; + if ( b == 0 ) { + str_str->read( buff_ori, sizeof( char ), bsize ); + str_out->read( buff_cmp, sizeof( char ), bsize ); + } + if ( buff_ori[ b ] != buff_cmp[ b ] ) { + sprintf( errormessage, "difference found at 0x%X", i ); + errorlevel = 2; + return false; + } + } + + // free buffers + free( buff_ori ); + free( buff_cmp ); + + + return true; +} +#endif + + +/* ----------------------------------------------- + set each variable to its initial value + ----------------------------------------------- */ + +INTERN bool reset_buffers( void ) +{ + int cmp, bpos; + int i; + + + // -- free buffers -- + + // free buffers & set pointers NULL + if ( hdrdata != NULL ) free ( hdrdata ); + if ( huffdata != NULL ) free ( huffdata ); + if ( grbgdata != NULL ) free ( grbgdata ); + if ( rst_err != NULL ) free ( rst_err ); + if ( rstp != NULL ) free ( rstp ); + if ( scnp != NULL ) free ( scnp ); + hdrdata = NULL; + huffdata = NULL; + grbgdata = NULL; + rst_err = NULL; + rstp = NULL; + scnp = NULL; + + // free image arrays + for ( cmp = 0; cmp < 4; cmp++ ) { + if ( zdstdata[ cmp ] != NULL ) free( zdstdata[cmp] ); + if ( eobxhigh[ cmp ] != NULL ) free( eobxhigh[cmp] ); + if ( eobyhigh[ cmp ] != NULL ) free( eobyhigh[cmp] ); + if ( zdstxlow[ cmp ] != NULL ) free( zdstxlow[cmp] ); + if ( zdstylow[ cmp ] != NULL ) free( zdstylow[cmp] ); + zdstdata[ cmp ] = NULL; + eobxhigh[ cmp ] = NULL; + eobyhigh[ cmp ] = NULL; + zdstxlow[ cmp ] = NULL; + zdstylow[ cmp ] = NULL; + freqscan[ cmp ] = (unsigned char*) stdscan; + + for ( bpos = 0; bpos < 64; bpos++ ) { + if ( colldata[ cmp ][ bpos ] != NULL ) free( colldata[cmp][bpos] ); + colldata[ cmp ][ bpos ] = NULL; + } + } + + + // -- 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 = NULL; + 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 + ----------------------------------------------- */ + +INTERN bool read_jpeg( void ) +{ + unsigned char* segment = NULL; // 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; + + abytewriter* huffw; + abytewriter* hdrw; + abytewriter* grbgw; + + + // preset count of scans + scnc = 0; + + // start headerwriter + hdrw = new abytewriter( 4096 ); + hdrs = 0; // size of header data, start with 0 + + // start huffman writer + huffw = new abytewriter( 0 ); + hufs = 0; // size of image data, start with 0 + + // alloc memory for segment data first + segment = ( unsigned char* ) calloc( ssize, sizeof( char ) ); + if ( segment == NULL ) { + 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( &tmp, 1, 1 ) == 0 ) + break; + + // non-0xFF loop + if ( tmp != 0xFF ) { + crst = 0; + while ( tmp != 0xFF ) { + huffw->write( tmp ); + if ( str_in->read( &tmp, 1, 1 ) == 0 ) + break; + } + } + + // treatment of 0xFF + if ( tmp == 0xFF ) { + if ( str_in->read( &tmp, 1, 1 ) == 0 ) + break; // read next byte & check + if ( tmp == 0x00 ) { + crst = 0; + // no zeroes needed -> ignore 0x00. write 0xFF + huffw->write( 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 == NULL ) { + rst_err = (unsigned char*) calloc( scnc + 1, sizeof( char ) ); + if ( rst_err == NULL ) { + sprintf( errormessage, MEM_ERRMSG ); + errorlevel = 2; + return false; + } + } + } + if ( rst_err != NULL ) { + // realloc and set only if needed + rst_err = ( unsigned char* ) realloc( rst_err, ( scnc + 1 ) * sizeof( char ) ); + if ( rst_err == NULL ) { + sprintf( errormessage, MEM_ERRMSG ); + errorlevel = 2; + return false; + } + if ( crst > 255 ) { + sprintf( errormessage, "Severe false use of RST markers (%i)", 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, 1, 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, 1, 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->getptr(); + hdrs = hdrw->getpos(); + // get pointer for huffman data & size + huffdata = huffw->getptr(); + hufs = huffw->getpos(); + // everything is done here now + break; + } + + // read in next segments' length and check it + if ( str_in->read( segment + 2, 1, 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* ) realloc( segment, len ); + if ( segment == NULL ) { + 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 ), 1, ( len - 4 ) ) != + ( unsigned short ) ( len - 4 ) ) break; + hdrw->write_n( 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( &tmp, 1, 1 ); + if ( grbs > 0 ) { + grbgw = new abytewriter( 1024 ); + grbgw->write( tmp ); + while( true ) { + len = str_in->read( segment, 1, ssize ); + if ( len == 0 ) break; + grbgw->write_n( segment, len ); + } + grbgdata = grbgw->getptr(); + grbs = grbgw->getpos(); + delete ( grbgw ); + } + + // free segment + free( segment ); + + // get filesize + jpgfilesize = str_in->getsize(); + + // parse header for image info + if ( !jpg_setup_imginfo() ) { + return false; + } + + + return true; +} + + +/* ----------------------------------------------- + Merges header & image data to jpeg + ----------------------------------------------- */ + +INTERN bool 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, 1, 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, 1, ( 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( huffdata + ipos, 1, 1 ); + // check current byte, stuff if needed + if ( huffdata[ ipos ] == 0xFF ) + str_out->write( &stv, 1, 1 ); + // insert restart markers if needed + if ( rstp != NULL ) { + if ( ipos == rstp[ rpos ] ) { + rst = 0xD0 + ( cpos % 8 ); + str_out->write( &mrk, 1, 1 ); + str_out->write( &rst, 1, 1 ); + rpos++; cpos++; + } + } + } + // insert false rst markers at end if needed + if ( rst_err != NULL ) { + while ( rst_err[ scan - 1 ] > 0 ) { + rst = 0xD0 + ( cpos % 8 ); + str_out->write( &mrk, 1, 1 ); + str_out->write( &rst, 1, 1 ); + cpos++; rst_err[ scan - 1 ]--; + } + } + + // proceed with next scan + scan++; + } + + // write EOI + str_out->write( EOI, 1, 2 ); + + // write garbage if needed + if ( grbs > 0 ) + str_out->write( grbgdata, 1, grbs ); + + // errormessage if write error + if ( str_out->chkerr() ) { + sprintf( errormessage, "write error, possibly drive is full" ); + errorlevel = 2; + return false; + } + + // get filesize + jpgfilesize = str_out->getsize(); + + + return true; +} + + +/* ----------------------------------------------- + JPEG decoding routine + ----------------------------------------------- */ + +INTERN bool decode_jpeg( void ) +{ + abitreader* 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 abitreader + huffr = new abitreader( 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 ); + + // 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 ); + + // 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 non optimal 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 non optimal 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 ) { + 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 + ----------------------------------------------- */ + +INTERN bool recode_jpeg( void ) +{ + abitwriter* huffw; // bitwise writer for image data + abytewriter* storw; // bytewise writer for storage of correction bits + + 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 abitwriter + huffw = new abitwriter( 0 ); + huffw->fillbit = padbit; + + // init storage writer + storw = new abytewriter( 0 ); + + // 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 == NULL ) scnp = ( unsigned int* ) calloc( scnc + 2, sizeof( int ) ); + else scnp = ( unsigned int* ) realloc( scnp, ( scnc + 2 ) * sizeof( int ) ); + if ( scnp == NULL ) { + 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 == NULL ) rstp = ( unsigned int* ) calloc( tmp + 1, sizeof( int ) ); + else rstp = ( unsigned int* ) realloc( rstp, ( tmp + 1 ) * sizeof( int ) ); + if ( rstp == NULL ) { + 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->getpos(); + + // 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].huffac ]), + &(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].huffac ]), + &(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( padbit ); + + // 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->getpos() - 1; + } + } + } + + // safety check for error in huffwriter + if ( huffw->error ) { + delete huffw; + sprintf( errormessage, MEM_ERRMSG ); + errorlevel = 2; + return false; + } + + // get data into huffdata + huffdata = huffw->getptr(); + hufs = huffw->getpos(); + delete huffw; + + // remove storage writer + delete storw; + + // store last scan & restart positions + scnp[ scnc ] = hufs; + if ( rstp != NULL ) + rstp[ rstc ] = hufs; + + + return true; +} + + +/* ----------------------------------------------- + adapt ICOS tables for quantizer tables + ----------------------------------------------- */ + +INTERN bool 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 + ----------------------------------------------- */ + +INTERN bool 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 + ----------------------------------------------- */ + +INTERN bool 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 + ----------------------------------------------- */ + +INTERN bool 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 + ----------------------------------------------- */ + +INTERN bool 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 + ----------------------------------------------- */ + +INTERN bool pack_pjg( void ) +{ + aricoder* encoder; + unsigned char hcode; + int cmp; + #if defined(DEV_INFOS) + int dev_size = 0; + #endif + + + // PJG-Header + str_out->write( (void*) pjg_magic, 1, 2 ); + + // store settings if not auto + if ( !auto_set ) { + hcode = 0x00; + str_out->write( &hcode, 1, 1 ); + str_out->write( nois_trs, 1, 4 ); + str_out->write( segm_cnt, 1, 4 ); + } + + // store version number + hcode = appversion; + str_out->write( &hcode, 1, 1 ); + + + // init arithmetic compression + encoder = new aricoder( str_out, 1 ); + + // 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 == NULL ) ? 0 : 1 ) ) return false; + // encode # of false set RST markers per scan + if ( rst_err != NULL ) + 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->chkerr() ) { + sprintf( errormessage, "write error, possibly drive is full" ); + errorlevel = 2; + return false; + } + + // get filesize + pjgfilesize = str_out->getsize(); + + + return true; +} + + +/* ----------------------------------------------- + unpacks compressed pjg to colldata + ----------------------------------------------- */ + +INTERN bool unpack_pjg( void ) +{ + aricoder* decoder; + unsigned char hcode; + unsigned char cb; + int cmp; + + + // check header codes ( maybe position in other function ? ) + while( true ) { + str_in->read( &hcode, 1, 1 ); + if ( hcode == 0x00 ) { + // retrieve compression settings from file + str_in->read( nois_trs, 1, 4 ); + str_in->read( segm_cnt, 1, 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 + decoder = new aricoder( str_in, 0 ); + + // 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, NULL ) ) 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->getsize(); + + + return true; +} + +/* ----------------------- End of main functions -------------------------- */ + +/* ----------------------- Begin of JPEG specific functions -------------------------- */ + + +/* ----------------------------------------------- + Parses header for imageinfo + ----------------------------------------------- */ +INTERN bool 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 == NULL ) || + ( 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] == NULL) { + 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] == NULL ) || + ( eobxhigh[cmp] == NULL ) || ( eobyhigh[cmp] == NULL ) || + ( zdstxlow[cmp] == NULL ) || ( zdstylow[cmp] == NULL ) ) { + 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 + ----------------------------------------------- */ +INTERN bool 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 ( 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: // APP12segment + 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: // RST1segment + 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 + ----------------------------------------------- */ +INTERN bool jpg_rebuild_header( void ) +{ + abytewriter* hdrw; // new header writer + + 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 + hdrw = new abytewriter( 4096 ); + + // 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_n( &(hdrdata[ hpos ]), len ); + } + hpos += len; + } + + // replace current header with the new one + free( hdrdata ); + hdrdata = hdrw->getptr(); + hdrs = hdrw->getpos(); + delete( hdrw ); + + + return true; +} + + +/* ----------------------------------------------- + sequential block decoding routine + ----------------------------------------------- */ +INTERN int jpg_decode_block_seq( abitreader* 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 + ----------------------------------------------- */ +INTERN int jpg_encode_block_seq( abitwriter* 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( dctbl->cval[ s ], dctbl->clen[ s ] ); + huffw->write( 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( 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( actbl->cval[ hc ], actbl->clen[ hc ] ); + huffw->write( n, s ); + // reset zeroes + z = 0; + } + else { // increment zero counter + z++; + } + } + // write eob if needed + if ( z > 0 ) + huffw->write( actbl->cval[ 0x00 ], actbl->clen[ 0x00 ] ); + + + return 64 - z; +} + + +/* ----------------------------------------------- + progressive DC decoding routine + ----------------------------------------------- */ +INTERN int jpg_decode_dc_prg_fs( abitreader* 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 + ----------------------------------------------- */ +INTERN int jpg_encode_dc_prg_fs( abitwriter* huffw, huffCodes* dctbl, short* block ) +{ + unsigned short n; + unsigned char s; + + + // encode DC + s = BITLEN2048N( block[ 0 ] ); + n = ENVLI( s, block[ 0 ] ); + huffw->write( dctbl->cval[ s ], dctbl->clen[ s ] ); + huffw->write( n, s ); + + + // return 0 if everything is ok + return 0; +} + + +/* ----------------------------------------------- + progressive AC decoding routine + ----------------------------------------------- */ +INTERN int jpg_decode_ac_prg_fs( abitreader* 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 + ----------------------------------------------- */ +INTERN int jpg_encode_ac_prg_fs( abitwriter* 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( 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( actbl->cval[ hc ], actbl->clen[ hc ] ); + huffw->write( 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 + ----------------------------------------------- */ +INTERN int jpg_decode_dc_prg_sa( abitreader* 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 + ----------------------------------------------- */ +INTERN int jpg_encode_dc_prg_sa( abitwriter* huffw, short* block ) +{ + // enocode next bit of dc coefficient + huffw->write( block[ 0 ], 1 ); + + // return 0 if everything is ok + return 0; +} + + +/* ----------------------------------------------- + progressive AC SA decoding routine + ----------------------------------------------- */ +INTERN int jpg_decode_ac_prg_sa( abitreader* 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 + ----------------------------------------------- */ +INTERN int jpg_encode_ac_prg_sa( abitwriter* huffw, abytewriter* 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( 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( actbl->cval[ hc ], actbl->clen[ hc ] ); + huffw->write( n, s ); + // write correction bits + jpg_encode_crbits( huffw, storw ); + // reset zeroes + z = 0; + } + else { // store correction bits + n = block[ bpos ] & 0x1; + storw->write( n ); + } + } + + // fast processing after eob + for ( ;bpos <= to; bpos++ ) + { + if ( block[ bpos ] != 0 ) { // store correction bits + n = block[ bpos ] & 0x1; + storw->write( 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 + ----------------------------------------------- */ +INTERN int jpg_decode_eobrun_sa( abitreader* 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 + ----------------------------------------------- */ +INTERN int jpg_encode_eobrun( abitwriter* huffw, huffCodes* actbl, int* eobrun ) +{ + unsigned short n; + unsigned char s; + int hc; + + + if ( (*eobrun) > 0 ) { + while ( (*eobrun) > actbl->max_eobrun ) { + huffw->write( actbl->cval[ 0xE0 ], actbl->clen[ 0xE0 ] ); + huffw->write( E_ENVLI( 14, 32767 ), 14 ); + (*eobrun) -= actbl->max_eobrun; + } + BITLEN( s, (*eobrun) ); + s--; + n = E_ENVLI( s, (*eobrun) ); + hc = ( s << 4 ); + huffw->write( actbl->cval[ hc ], actbl->clen[ hc ] ); + huffw->write( n, s ); + (*eobrun) = 0; + } + + + return 0; +} + + +/* ----------------------------------------------- + correction bits encoding routine + ----------------------------------------------- */ +INTERN int jpg_encode_crbits( abitwriter* huffw, abytewriter* storw ) +{ + unsigned char* data; + int len; + int i; + + + // peek into data from abytewriter + len = storw->getpos(); + if ( len == 0 ) return 0; + data = storw->peekptr(); + + // write bits to huffwriter + for ( i = 0; i < len; i++ ) + huffw->write( data[ i ], 1 ); + + // reset abytewriter, discard data + storw->reset(); + + + return 0; +} + + +/* ----------------------------------------------- + returns next code (from huffman-tree & -data) + ----------------------------------------------- */ +INTERN int jpg_next_huffcode( abitreader *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 + ----------------------------------------------- */ +INTERN int 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) + ----------------------------------------------- */ +INTERN int 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 + ----------------------------------------------- */ +INTERN int 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 + ----------------------------------------------- */ +INTERN void 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 -------------------------- */ + +/* ----------------------- End of PJG specific functions -------------------------- */ + + +/* ----------------------------------------------- + encodes frequency scanorder to pjg + ----------------------------------------------- */ +INTERN bool pjg_encode_zstscan( aricoder* 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( 'a', 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) + ----------------------------------------------- */ +INTERN bool pjg_encode_zdst_high( aricoder* 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) + ----------------------------------------------- */ +INTERN bool pjg_encode_zdst_low( aricoder* 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 + ----------------------------------------------- */ +INTERN bool pjg_encode_dc( aricoder* 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 == NULL ) { + 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 + ----------------------------------------------- */ +INTERN bool pjg_encode_ac_high( aricoder* 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 == NULL ) || ( sgn_store == NULL ) || ( zdstls == NULL ) ) { + 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( 'a', 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( 1 ); + mod_res->flush_model( 1 ); + mod_sgn->flush_model( 1 ); + } + + // 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 + ----------------------------------------------- */ +INTERN bool pjg_encode_ac_low( aricoder* 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( 'a', 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( 1 ); + mod_res->flush_model( 1 ); + mod_top->flush_model( 1 ); + mod_sgn->flush_model( 1 ); + } + + // 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 + ----------------------------------------------- */ +INTERN bool pjg_encode_generic( aricoder* 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 + ----------------------------------------------- */ +INTERN bool pjg_encode_bit( aricoder* 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 + ----------------------------------------------- */ +INTERN bool pjg_decode_zstscan( aricoder* 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( 'a', 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) + ----------------------------------------------- */ +INTERN bool pjg_decode_zdst_high( aricoder* 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) + ----------------------------------------------- */ +INTERN bool pjg_decode_zdst_low( aricoder* 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 + ----------------------------------------------- */ +INTERN bool pjg_decode_dc( aricoder* 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 == NULL ) { + 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 + ----------------------------------------------- */ +INTERN bool pjg_decode_ac_high( aricoder* 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 == NULL ) || ( sgn_store == NULL ) ) { + 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( 'a', 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( 1 ); + mod_res->flush_model( 1 ); + mod_sgn->flush_model( 1 ); + } + + // 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 + ----------------------------------------------- */ +INTERN bool pjg_decode_ac_low( aricoder* 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( 'a', 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( 1 ); + mod_res->flush_model( 1 ); + mod_top->flush_model( 1 ); + mod_sgn->flush_model( 1 ); + } + + // 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 + ----------------------------------------------- */ +INTERN bool pjg_decode_generic( aricoder* dec, unsigned char** data, int* len ) +{ + abytewriter* bwrt; + model_s* model; + int c; + + + // start byte writer + bwrt = new abytewriter( 1024 ); + + // 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( (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->getptr(); + if ( len != NULL ) (*len) = bwrt->getpos(); + delete bwrt; + + + return true; +} + + +/* ----------------------------------------------- + decodes one bit from pjg + ----------------------------------------------- */ +INTERN bool pjg_decode_bit( aricoder* dec, unsigned char* bit ) +{ + model_b* model; + + + model = INIT_MODEL_B( 1, -1 ); + (*bit) = decode_ari( dec, model ); + delete( model ); + + + return true; +} + + +/* ----------------------------------------------- + get zero sort frequency scan vector + ----------------------------------------------- */ +INTERN void 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 + ----------------------------------------------- */ +INTERN bool 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 + ----------------------------------------------- */ +INTERN bool 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 + ----------------------------------------------- */ +INTERN void 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 + ----------------------------------------------- */ +INTERN int 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 + ----------------------------------------------- */ +INTERN int 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 + ----------------------------------------------- */ +INTERN void 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 ofDCT specific functions -------------------------- */ + + +/* ----------------------------------------------- + inverse DCT transform using precalc tables (fast) + ----------------------------------------------- */ +#if !defined(BUILD_LIB) && defined(DEV_BUILD) +INTERN int idct_2d_fst_8x8( int cmp, int dpos, int ix, int iy ) +{ + int idct = 0; + int ixy; + + + // calculate start index + ixy = ( ( iy << 3 ) + ix ) << 6; + + // begin transform + idct += colldata[ cmp ][ 0 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 0 ]; + idct += colldata[ cmp ][ 1 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 1 ]; + idct += colldata[ cmp ][ 5 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 2 ]; + idct += colldata[ cmp ][ 6 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 3 ]; + idct += colldata[ cmp ][ 14 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 4 ]; + idct += colldata[ cmp ][ 15 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 5 ]; + idct += colldata[ cmp ][ 27 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 6 ]; + idct += colldata[ cmp ][ 28 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 7 ]; + idct += colldata[ cmp ][ 2 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 8 ]; + idct += colldata[ cmp ][ 4 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 9 ]; + idct += colldata[ cmp ][ 7 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 10 ]; + idct += colldata[ cmp ][ 13 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 11 ]; + idct += colldata[ cmp ][ 16 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 12 ]; + idct += colldata[ cmp ][ 26 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 13 ]; + idct += colldata[ cmp ][ 29 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 14 ]; + idct += colldata[ cmp ][ 42 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 15 ]; + idct += colldata[ cmp ][ 3 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 16 ]; + idct += colldata[ cmp ][ 8 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 17 ]; + idct += colldata[ cmp ][ 12 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 18 ]; + idct += colldata[ cmp ][ 17 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 19 ]; + idct += colldata[ cmp ][ 25 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 20 ]; + idct += colldata[ cmp ][ 30 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 21 ]; + idct += colldata[ cmp ][ 41 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 22 ]; + idct += colldata[ cmp ][ 43 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 23 ]; + idct += colldata[ cmp ][ 9 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 24 ]; + idct += colldata[ cmp ][ 11 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 25 ]; + idct += colldata[ cmp ][ 18 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 26 ]; + idct += colldata[ cmp ][ 24 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 27 ]; + idct += colldata[ cmp ][ 31 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 28 ]; + idct += colldata[ cmp ][ 40 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 29 ]; + idct += colldata[ cmp ][ 44 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 30 ]; + idct += colldata[ cmp ][ 53 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 31 ]; + idct += colldata[ cmp ][ 10 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 32 ]; + idct += colldata[ cmp ][ 19 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 33 ]; + idct += colldata[ cmp ][ 23 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 34 ]; + idct += colldata[ cmp ][ 32 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 35 ]; + idct += colldata[ cmp ][ 39 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 36 ]; + idct += colldata[ cmp ][ 45 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 37 ]; + idct += colldata[ cmp ][ 52 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 38 ]; + idct += colldata[ cmp ][ 54 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 39 ]; + idct += colldata[ cmp ][ 20 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 40 ]; + idct += colldata[ cmp ][ 22 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 41 ]; + idct += colldata[ cmp ][ 33 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 42 ]; + idct += colldata[ cmp ][ 38 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 43 ]; + idct += colldata[ cmp ][ 46 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 44 ]; + idct += colldata[ cmp ][ 51 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 45 ]; + idct += colldata[ cmp ][ 55 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 46 ]; + idct += colldata[ cmp ][ 60 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 47 ]; + idct += colldata[ cmp ][ 21 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 48 ]; + idct += colldata[ cmp ][ 34 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 49 ]; + idct += colldata[ cmp ][ 37 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 50 ]; + idct += colldata[ cmp ][ 47 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 51 ]; + idct += colldata[ cmp ][ 50 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 52 ]; + idct += colldata[ cmp ][ 56 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 53 ]; + idct += colldata[ cmp ][ 59 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 54 ]; + idct += colldata[ cmp ][ 61 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 55 ]; + idct += colldata[ cmp ][ 35 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 56 ]; + idct += colldata[ cmp ][ 36 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 57 ]; + idct += colldata[ cmp ][ 48 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 58 ]; + idct += colldata[ cmp ][ 49 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 59 ]; + idct += colldata[ cmp ][ 57 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 60 ]; + idct += colldata[ cmp ][ 58 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 61 ]; + idct += colldata[ cmp ][ 62 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 62 ]; + idct += colldata[ cmp ][ 63 ][ dpos ] * adpt_idct_8x8[ cmp ][ ixy + 63 ]; + + + return idct; +} +#endif + + +/* ----------------------------------------------- + inverse DCT transform using precalc tables (fast) + ----------------------------------------------- */ +INTERN int 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) + ----------------------------------------------- */ +INTERN int 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) +INTERN int 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) +INTERN int 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 + + +/* ----------------------------------------------- + loco-i predictor + ----------------------------------------------- */ +INTERN inline int plocoi( int a, int b, int c ) +{ + // a -> left; b -> above; c -> above-left + int min, max; + + min = ( a < b ) ? a : b; + max = ( a > b ) ? a : b; + + if ( c >= max ) return min; + if ( c <= min ) return max; + + return a + b - c; +} + + +/* ----------------------------------------------- + calculates median out of an integer array + ----------------------------------------------- */ +INTERN inline int median_int( int* values, int size ) +{ + int middle = ( size >> 1 ); + bool done; + int swap; + int i; + + + // sort data first + done = false; + while ( !done ) { + done = true; + for ( i = 1; i < size; i++ ) + if ( values[ i ] < values[ i - 1 ] ) { + swap = values[ i ]; + values[ i ] = values[ i - 1 ]; + values[ i - 1 ] = swap; + done = false; + } + } + + // return median + return ( ( size % 2 ) == 0 ) ? + ( values[ middle ] + values[ middle - 1 ] ) / 2 : values[ middle ]; +} + + +/* ----------------------------------------------- + calculates median out of an float array + ----------------------------------------------- */ +INTERN inline float median_float( float* values, int size ) +{ + int middle = ( size >> 1 ); + bool done; + float swap; + int i; + + + // sort data first + done = false; + while ( !done ) { + done = true; + for ( i = 1; i < size; i++ ) + if ( values[ i ] < values[ i - 1 ] ) { + swap = values[ i ]; + values[ i ] = values[ i - 1 ]; + values[ i - 1 ] = swap; + done = false; + } + } + + // return median + if ( ( size % 2 ) == 0 ) { + return ( values[ middle ] + values[ middle - 1 ] ) / 2.0; + } + else + return ( values[ middle ] ); +} + +/* ----------------------- End of prediction functions -------------------------- */ + +/* ----------------------- Begin of miscellaneous helper functions -------------------------- */ + + +/* ----------------------------------------------- + displays progress bar on screen + ----------------------------------------------- */ +#if !defined(BUILD_LIB) +INTERN inline void progress_bar( int current, int last ) +{ + int barpos = ( ( current * BARLEN ) + ( last / 2 ) ) / last; + int i; + + + // generate progress bar + fprintf( msgout, "[" ); + #if defined(_WIN32) + for ( i = 0; i < barpos; i++ ) + fprintf( msgout, "\xFE" ); + #else + for ( i = 0; i < barpos; i++ ) + fprintf( msgout, "X" ); + #endif + for ( ; i < BARLEN; i++ ) + fprintf( msgout, " " ); + fprintf( msgout, "]" ); +} +#endif + +/* ----------------------------------------------- + creates filename, callocs memory for it + ----------------------------------------------- */ +#if !defined(BUILD_LIB) +INTERN inline char* create_filename( const char* base, const char* extension ) +{ + int len = strlen( base ) + ( ( extension == NULL ) ? 0 : strlen( extension ) + 1 ) + 1; + char* filename = (char*) calloc( len, sizeof( char ) ); + + // create a filename from base & extension + strcpy( filename, base ); + set_extension( filename, extension ); + + return filename; +} +#endif + +/* ----------------------------------------------- + creates filename, callocs memory for it + ----------------------------------------------- */ +#if !defined(BUILD_LIB) +INTERN inline char* unique_filename( const char* base, const char* extension ) +{ + int len = strlen( base ) + ( ( extension == NULL ) ? 0 : strlen( extension ) + 1 ) + 1; + char* filename = (char*) calloc( len, sizeof( char ) ); + + // create a unique filename using underscores + strcpy( filename, base ); + set_extension( filename, extension ); + while ( file_exists( filename ) ) { + len += sizeof( char ); + filename = (char*) realloc( filename, len ); + add_underscore( filename ); + } + + return filename; +} +#endif + +/* ----------------------------------------------- + changes extension of filename + ----------------------------------------------- */ +#if !defined(BUILD_LIB) +INTERN inline void set_extension( char* filename, const char* extension ) +{ + char* extstr; + + // find position of extension in filename + extstr = ( strrchr( filename, '.' ) == NULL ) ? + strrchr( filename, '\0' ) : strrchr( filename, '.' ); + + // set new extension + if ( extension != NULL ) { + (*extstr++) = '.'; + strcpy( extstr, extension ); + } + else + (*extstr) = '\0'; +} +#endif + +/* ----------------------------------------------- + adds underscore after filename + ----------------------------------------------- */ +#if !defined(BUILD_LIB) +INTERN inline void add_underscore( char* filename ) +{ + char* tmpname = (char*) calloc( strlen( filename ) + 1, sizeof( char ) ); + char* extstr; + + // copy filename to tmpname + strcpy( tmpname, filename ); + // search extension in filename + extstr = strrchr( filename, '.' ); + + // add underscore before extension + if ( extstr != NULL ) { + (*extstr++) = '_'; + strcpy( extstr, strrchr( tmpname, '.' ) ); + } + else + sprintf( filename, "%s_", tmpname ); + + // free memory + free( tmpname ); +} +#endif + +/* ----------------------------------------------- + checks if a file exists + ----------------------------------------------- */ +INTERN inline bool file_exists( const char* filename ) +{ + // needed for both, executable and library + FILE* fp = fopen( filename, "rb" ); + + if ( fp == NULL ) return false; + else { + fclose( fp ); + return true; + } +} + +/* ----------------------- End of miscellaneous helper functions -------------------------- */ + +/* ----------------------- Begin of developers functions -------------------------- */ + + +/* ----------------------------------------------- + Writes header file + ----------------------------------------------- */ +#if !defined(BUILD_LIB) && defined(DEV_BUILD) +INTERN bool dump_hdr( void ) +{ + const char* ext = "hdr"; + const char* basename = filelist[ file_no ]; + + if ( !dump_file( basename, ext, hdrdata, 1, hdrs ) ) + return false; + + return true; +} +#endif + + +/* ----------------------------------------------- + Writes huffman coded file + ----------------------------------------------- */ +#if !defined(BUILD_LIB) && defined(DEV_BUILD) +INTERN bool dump_huf( void ) +{ + const char* ext = "huf"; + const char* basename = filelist[ file_no ]; + + if ( !dump_file( basename, ext, huffdata, 1, hufs ) ) + return false; + + return true; +} +#endif + + +/* ----------------------------------------------- + Writes collections of DCT coefficients + ----------------------------------------------- */ +#if !defined(BUILD_LIB) && defined(DEV_BUILD) +INTERN bool dump_coll( void ) +{ + FILE* fp; + + char* fn; + const char* ext[ 4 ]; + const char* base; + int cmp, bpos, dpos; + int i, j; + + ext[0] = "coll0"; + ext[1] = "coll1"; + ext[2] = "coll2"; + ext[3] = "coll3"; + base = filelist[ file_no ]; + + + for ( cmp = 0; cmp < cmpc; cmp++ ) { + + // create filename + fn = create_filename( base, ext[ cmp ] ); + + // open file for output + fp = fopen( fn, "wb" ); + if ( fp == NULL ){ + sprintf( errormessage, FWR_ERRMSG, fn); + errorlevel = 2; + return false; + } + free( fn ); + + switch ( collmode ) { + + case 0: // standard collections + for ( bpos = 0; bpos < 64; bpos++ ) + fwrite( colldata[cmp][bpos], sizeof( short ), cmpnfo[cmp].bc, fp ); + break; + + case 1: // sequential order collections, 'dhufs' + for ( dpos = 0; dpos < cmpnfo[cmp].bc; dpos++ ) + for ( bpos = 0; bpos < 64; bpos++ ) + fwrite( &(colldata[cmp][bpos][dpos]), sizeof( short ), 1, fp ); + break; + + case 2: // square collections + dpos = 0; + for ( i = 0; i < 64; ) { + bpos = zigzag[ i++ ]; + fwrite( &(colldata[cmp][bpos][dpos]), sizeof( short ), + cmpnfo[cmp].bch, fp ); + if ( ( i % 8 ) == 0 ) { + dpos += cmpnfo[cmp].bch; + if ( dpos >= cmpnfo[cmp].bc ) { + dpos = 0; + } + else { + i -= 8; + } + } + } + break; + + case 3: // uncollections + for ( i = 0; i < ( cmpnfo[cmp].bcv * 8 ); i++ ) + for ( j = 0; j < ( cmpnfo[cmp].bch * 8 ); j++ ) { + bpos = zigzag[ ( ( i % 8 ) * 8 ) + ( j % 8 ) ]; + dpos = ( ( i / 8 ) * cmpnfo[cmp].bch ) + ( j / 8 ); + fwrite( &(colldata[cmp][bpos][dpos]), sizeof( short ), 1, fp ); + } + break; + + case 4: // square collections / alt order (even/uneven) + dpos = 0; + for ( i = 0; i < 64; ) { + bpos = even_zigzag[ i++ ]; + fwrite( &(colldata[cmp][bpos][dpos]), sizeof( short ), + cmpnfo[cmp].bch, fp ); + if ( ( i % 8 ) == 0 ) { + dpos += cmpnfo[cmp].bch; + if ( dpos >= cmpnfo[cmp].bc ) { + dpos = 0; + } + else { + i -= 8; + } + } + } + break; + + case 5: // uncollections / alt order (even/uneven) + for ( i = 0; i < ( cmpnfo[cmp].bcv * 8 ); i++ ) + for ( j = 0; j < ( cmpnfo[cmp].bch * 8 ); j++ ) { + bpos = even_zigzag[ ( ( i % 8 ) * 8 ) + ( j % 8 ) ]; + dpos = ( ( i / 8 ) * cmpnfo[cmp].bch ) + ( j / 8 ); + fwrite( &(colldata[cmp][bpos][dpos]), sizeof( short ), 1, fp ); + } + break; + } + + fclose( fp ); + } + + return true; +} +#endif + + +/* ----------------------------------------------- + Writes zero distribution data to file; + ----------------------------------------------- */ +#if !defined(BUILD_LIB) && defined(DEV_BUILD) +INTERN bool dump_zdst( void ) +{ + const char* ext[4]; + const char* basename; + int cmp; + + + ext[0] = "zdst0"; + ext[1] = "zdst1"; + ext[2] = "zdst2"; + ext[3] = "zdst3"; + basename = filelist[ file_no ]; + + for ( cmp = 0; cmp < cmpc; cmp++ ) + if ( !dump_file( basename, ext[cmp], zdstdata[cmp], 1, cmpnfo[cmp].bc ) ) + return false; + + + return true; +} +#endif + + +/* ----------------------------------------------- + Writes to file + ----------------------------------------------- */ +#if !defined(BUILD_LIB) && defined(DEV_BUILD) +INTERN bool dump_file( const char* base, const char* ext, void* data, int bpv, int size ) +{ + FILE* fp; + char* fn; + + // create filename + fn = create_filename( base, ext ); + + // open file for output + fp = fopen( fn, "wb" ); + if ( fp == NULL ) { + sprintf( errormessage, FWR_ERRMSG, fn); + errorlevel = 2; + return false; + } + free( fn ); + + // write & close + fwrite( data, bpv, size, fp ); + fclose( fp ); + + return true; +} +#endif + + +/* ----------------------------------------------- + Writes error info file + ----------------------------------------------- */ +#if !defined(BUILD_LIB) && defined(DEV_BUILD) +INTERN bool dump_errfile( void ) +{ + FILE* fp; + char* fn; + + + // return immediately if theres no error + if ( errorlevel == 0 ) return true; + + // create filename based on errorlevel + if ( errorlevel == 1 ) { + fn = create_filename( filelist[ file_no ], "wrn.nfo" ); + } + else { + fn = create_filename( filelist[ file_no ], "err.nfo" ); + } + + // open file for output + fp = fopen( fn, "w" ); + if ( fp == NULL ){ + sprintf( errormessage, FWR_ERRMSG, fn); + errorlevel = 2; + return false; + } + free( fn ); + + // write status and errormessage to file + fprintf( fp, "--> error (level %i) in file \"%s\" <--\n", errorlevel, filelist[ file_no ] ); + fprintf( fp, "\n" ); + // write error specification to file + fprintf( fp, " %s -> %s:\n", get_status( errorfunction ), + ( errorlevel == 1 ) ? "warning" : "error" ); + fprintf( fp, " %s\n", errormessage ); + + // done, close file + fclose( fp ); + + + return true; +} +#endif + + +/* ----------------------------------------------- + Writes info to textfile + ----------------------------------------------- */ +#if !defined(BUILD_LIB) && defined(DEV_BUILD) +INTERN bool dump_info( void ) +{ + FILE* fp; + char* fn; + + 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; + + + // create filename + fn = create_filename( filelist[ file_no ], "nfo" ); + + // open file for output + fp = fopen( fn, "w" ); + if ( fp == NULL ){ + sprintf( errormessage, FWR_ERRMSG, fn); + errorlevel = 2; + return false; + } + free( fn ); + + // info about image + fprintf( fp, "\n\n\n", jpgfilename ); + fprintf( fp, "coding process: %s\n", ( jpegtype == 1 ) ? "sequential" : "progressive" ); + // fprintf( fp, "no of scans: %i\n", scnc ); + fprintf( fp, "imageheight: %i / imagewidth: %i\n", imgheight, imgwidth ); + fprintf( fp, "component count: %i\n", cmpc ); + fprintf( fp, "mcu count: %i/%i/%i (all/v/h)\n\n", mcuc, mcuv, mcuh ); + + // info about header + fprintf( fp, "\nfile header structure:\n" ); + fprintf( fp, " type length hpos\n" ); + // header parser loop + for ( hpos = 0; (int) hpos < hdrs; hpos += len ) { + type = hdrdata[ hpos + 1 ]; + len = 2 + B_SHORT( hdrdata[ hpos + 2 ], hdrdata[ hpos + 3 ] ); + fprintf( fp, " FF%2X %6i %6i\n", type, len, hpos ); + } + fprintf( fp, " _END 0 %6i\n", hpos ); + fprintf( fp, "\n" ); + + // info about compression settings + fprintf( fp, "\ncompression settings:\n" ); + fprintf( fp, " no of segments -> %3i[0] %3i[1] %3i[2] %3i[3]\n", + segm_cnt[0], segm_cnt[1], segm_cnt[2], segm_cnt[3] ); + fprintf( fp, " noise threshold -> %3i[0] %3i[1] %3i[2] %3i[3]\n", + nois_trs[0], nois_trs[1], nois_trs[2], nois_trs[3] ); + fprintf( fp, "\n" ); + + // info about components + for ( cmp = 0; cmp < cmpc; cmp++ ) { + fprintf( fp, "\n" ); + fprintf( fp, "component number %i ->\n", cmp ); + fprintf( fp, "sample factors: %i/%i (v/h)\n", cmpnfo[cmp].sfv, cmpnfo[cmp].sfh ); + fprintf( fp, "blocks per mcu: %i\n", cmpnfo[cmp].mbs ); + fprintf( fp, "block count (mcu): %i/%i/%i (all/v/h)\n", + cmpnfo[cmp].bc, cmpnfo[cmp].bcv, cmpnfo[cmp].bch ); + fprintf( fp, "block count (sng): %i/%i/%i (all/v/h)\n", + cmpnfo[cmp].nc, cmpnfo[cmp].ncv, cmpnfo[cmp].nch ); + fprintf( fp, "quantiser table ->" ); + for ( i = 0; i < 64; i++ ) { + bpos = zigzag[ i ]; + if ( ( i % 8 ) == 0 ) fprintf( fp, "\n" ); + fprintf( fp, "%4i, ", QUANT( cmp, bpos ) ); + } + fprintf( fp, "\n" ); + fprintf( fp, "maximum values ->" ); + for ( i = 0; i < 64; i++ ) { + bpos = zigzag[ i ]; + if ( ( i % 8 ) == 0 ) fprintf( fp, "\n" ); + fprintf( fp, "%4i, ", MAX_V( cmp, bpos ) ); + } + fprintf( fp, "\n\n" ); + } + + + fclose( fp ); + + + return true; +} +#endif + + +/* ----------------------------------------------- + Writes distribution for use in valdist.h + ----------------------------------------------- */ +#if !defined(BUILD_LIB) && defined(DEV_BUILD) +INTERN bool dump_dist( void ) +{ + FILE* fp; + char* fn; + + unsigned int dist[ 1024 + 1 ]; + int cmp, bpos, dpos; + int i; + + + // create filename + fn = create_filename( filelist[ file_no ], "dist" ); + + // open file for output + fp = fopen( fn, "wb" ); + free( fn ); + if ( fp == NULL ){ + sprintf( errormessage, FWR_ERRMSG, fn); + errorlevel = 2; + return false; + } + + // calculate & write distributions for each frequency + for ( cmp = 0; cmp < cmpc; cmp++ ) + for ( bpos = 0; bpos < 64; bpos++ ) { + // preset dist with zeroes + for ( i = 0; i <= 1024; i++ ) dist[ i ] = 0; + // get distribution + for ( dpos = 0; dpos < cmpnfo[cmp].bc; dpos++ ) + dist[ ABS( colldata[cmp][bpos][dpos] ) ]++; + // write to file + fwrite( dist, sizeof( int ), 1024 + 1, fp ); + } + + + // close file + fclose( fp ); + + return true; +} +#endif + + +/* ----------------------------------------------- + Do inverse DCT and write pgms + ----------------------------------------------- */ +#if !defined(BUILD_LIB) && defined(DEV_BUILD) +INTERN bool dump_pgm( void ) +{ + unsigned char* imgdata; + + FILE* fp; + char* fn; + const char* ext[4]; + + int cmp, dpos; + int pix_v; + int xpos, ypos, dcpos; + int x, y; + + + ext[0] = "cmp0.pgm"; + ext[1] = "cmp1.pgm"; + ext[2] = "cmp2.pgm"; + ext[3] = "cmp3.pgm"; + + + for ( cmp = 0; cmp < cmpc; cmp++ ) + { + // create filename + fn = create_filename( filelist[ file_no ], ext[ cmp ] ); + + // open file for output + fp = fopen( fn, "wb" ); + if ( fp == NULL ){ + sprintf( errormessage, FWR_ERRMSG, fn ); + errorlevel = 2; + return false; + } + free( fn ); + + // alloc memory for image data + imgdata = (unsigned char*) calloc ( cmpnfo[cmp].bc * 64, sizeof( char ) ); + if ( imgdata == NULL ) { + sprintf( errormessage, MEM_ERRMSG ); + errorlevel = 2; + return false; + } + + for ( dpos = 0; dpos < cmpnfo[cmp].bc; dpos++ ) { + // do inverse DCT, store in imgdata + dcpos = ( ( ( dpos / cmpnfo[cmp].bch ) * cmpnfo[cmp].bch ) << 6 ) + + ( ( dpos % cmpnfo[cmp].bch ) << 3 ); + for ( y = 0; y < 8; y++ ) { + ypos = dcpos + ( y * ( cmpnfo[cmp].bch << 3 ) ); + for ( x = 0; x < 8; x++ ) { + xpos = ypos + x; + pix_v = idct_2d_fst_8x8( cmp, dpos, x, y ); + pix_v = DCT_RESCALE( pix_v ); + pix_v = pix_v + 128; + imgdata[ xpos ] = ( unsigned char ) CLAMPED( 0, 255, pix_v ); + } + } + } + + // write PGM header + fprintf( fp, "P5\n" ); + fprintf( fp, "# created by %s v%i.%i%s (%s) by %s\n", + apptitle, appversion / 10, appversion % 10, subversion, versiondate, author ); + fprintf( fp, "%i %i\n", cmpnfo[cmp].bch * 8, cmpnfo[cmp].bcv * 8 ); + fprintf( fp, "255\n" ); + + // write image data + fwrite( imgdata, sizeof( char ), cmpnfo[cmp].bc * 64, fp ); + + // free memory + free( imgdata ); + + // close file + fclose( fp ); + } + + return true; +} +#endif + +/* ----------------------- End of developers functions -------------------------- */ + +/* ----------------------- End of file -------------------------- */ diff --git a/filters/packjpg/packjpglib.h b/filters/packjpg/packjpglib.h new file mode 100644 index 0000000..852215c --- /dev/null +++ b/filters/packjpg/packjpglib.h @@ -0,0 +1,40 @@ +// packJPGlib.h - function declarations for the packJPG library +#if defined BUILD_DLL + #define EXPORT __declspec( dllexport ) +#else + #define EXPORT extern +#endif + +/* ----------------------------------------------- + function declarations: library only functions + ----------------------------------------------- */ + +EXPORT bool pjglib_convert_stream2stream( char* msg ); +EXPORT bool pjglib_convert_file2file( char* in, char* out, char* msg ); +EXPORT bool pjglib_convert_stream2mem( unsigned char** out_file, unsigned int* out_size, char* msg ); +EXPORT void pjglib_init_streams( void* in_src, int in_type, int in_size, void* out_dest, int out_type ); +EXPORT const char* pjglib_version_info( void ); +EXPORT const char* pjglib_short_name( void ); + +/* a short reminder about input/output stream types + for the pjglib_init_streams() function + + 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! */ diff --git a/filters/packjpg/pjpgtbl.h b/filters/packjpg/pjpgtbl.h new file mode 100644 index 0000000..c81083e --- /dev/null +++ b/filters/packjpg/pjpgtbl.h @@ -0,0 +1,1659 @@ +/* ----------------------------------------------- + defines for use in packJPG processing + ----------------------------------------------- */ + +// action defines +#define A_COMPRESS 1 +#define A_SPLIT_DUMP 2 +#define A_COLL_DUMP 3 +#define A_FCOLL_DUMP 4 +#define A_ZDST_DUMP 5 +#define A_TXT_INFO 6 +#define A_DIST_INFO 7 +#define A_PGM_DUMP 8 + +// file type defines +#define F_JPG 1 +#define F_PJG 2 +#define F_UNK 3 + + +/* ----------------------------------------------- + compression helper tables + ----------------------------------------------- */ + +// maxima for each frequency in zigzag order +// dc maximum is fixed by offset (+4/QUANT) +static const unsigned short int freqmax[] = +{ + 1024, 931, 932, 985, 858, 985, 968, 884, + 884, 967, 1020, 841, 871, 840, 1020, 968, + 932, 875, 876, 932, 969, 1020, 838, 985, + 844, 985, 838, 1020, 1020, 854, 878, 967, + 967, 878, 854, 1020, 854, 871, 886, 1020, + 886, 871, 854, 854, 870, 969, 969, 870, + 854, 838, 1010, 838, 1020, 837, 1020, 969, + 969, 1020, 838, 1020, 838, 1020, 1020, 838 +}; + +/* +// maxima for each frequency - IJG DCT float (not used) +static const unsigned short int freqmax_float[] = +{ + 1024, 924, 942, 924, 1020, 924, 942, 924, + 924, 837, 854, 837, 924, 837, 854, 837, + 942, 854, 871, 854, 942, 854, 871, 854, + 924, 837, 854, 837, 924, 837, 854, 837, + 1020, 924, 942, 924, 1020, 924, 942, 924, + 924, 837, 854, 837, 924, 837, 854, 837, + 942, 854, 871, 854, 942, 854, 871, 854, + 924, 837, 854, 837, 924, 837, 854, 837 +}; +*/ + +/* +// maxima for each frequency - IJG DCT int (not used) +static const unsigned short int freqmax_int[] = +{ + 1024, 924, 942, 924, 1020, 924, 942, 924, + 924, 838, 854, 838, 924, 838, 854, 838, + 942, 854, 871, 854, 942, 854, 871, 854, + 924, 837, 854, 837, 924, 837, 854, 837, + 1020, 924, 942, 924, 1020, 924, 942, 924, + 924, 838, 854, 838, 924, 838, 854, 838, + 942, 854, 871, 854, 942, 854, 871, 854, + 924, 838, 854, 838, 924, 838, 854, 838 +}; +*/ + +/* +// maxima for each frequency - IJG DCT fast (not used) +static const unsigned short int freqmax_fast[] = +{ + 1024, 931, 985, 968, 1020, 968, 1020, 1020, + 932, 858, 884, 840, 932, 812, 854, 854, + 985, 884, 849, 875, 985, 878, 821, 821, + 967, 841, 876, 844, 967, 886, 870, 726, + 1020, 932, 985, 967, 1020, 969, 1020, 1020, + 969, 812, 878, 886, 969, 829, 969, 727, + 1020, 854, 821, 870, 1010, 969, 1020, 1020, + 1020, 854, 821, 725, 1020, 727, 1020, 510 +}; +*/ + +/* +// maxima for each frequency - IJG DCT max (not used) +static const unsigned short int freqmax_ijg[] = +{ + 1024, 931, 985, 968, 1020, 968, 1020, 1020, + 932, 858, 884, 840, 932, 838, 854, 854, + 985, 884, 871, 875, 985, 878, 871, 854, + 967, 841, 876, 844, 967, 886, 870, 837, + 1020, 932, 985, 967, 1020, 969, 1020, 1020, + 969, 838, 878, 886, 969, 838, 969, 838, + 1020, 854, 871, 870, 1010, 969, 1020, 1020, + 1020, 854, 854, 838, 1020, 838, 1020, 838 +}; +*/ + +/* +// valdist 99.0% quantiles +int vdqu[ 3 ][ 64 ] = +{ + // table for statistical id 0 + { + 206, 346, 187, 126, 91, 68, 51, 42, + 353, 173, 124, 87, 63, 49, 39, 33, + 186, 119, 93, 70, 53, 42, 34, 29, + 127, 84, 68, 55, 44, 35, 29, 25, + 88, 63, 53, 44, 36, 30, 25, 22, + 67, 48, 42, 36, 30, 26, 22, 20, + 48, 38, 33, 29, 25, 22, 20, 18, + 43, 32, 29, 26, 23, 20, 18, 17, + }, + // table for statistical id 1 + { + 23, 86, 46, 28, 19, 14, 11, 9, + 93, 48, 32, 21, 15, 11, 9, 7, + 51, 32, 24, 18, 13, 10, 8, 7, + 31, 22, 18, 14, 11, 9, 7, 6, + 21, 16, 14, 11, 9, 7, 6, 5, + 15, 12, 11, 9, 7, 6, 5, 5, + 12, 10, 9, 7, 6, 5, 5, 4, + 10, 8, 7, 6, 5, 5, 4, 4, + }, + // table for statistical id 2 + { + 25, 89, 45, 27, 18, 13, 10, 8, + 94, 48, 31, 21, 15, 11, 8, 6, + 49, 32, 24, 17, 13, 10, 8, 6, + 29, 22, 18, 14, 11, 8, 7, 5, + 20, 16, 13, 11, 9, 7, 6, 5, + 15, 12, 11, 9, 7, 6, 5, 4, + 11, 9, 9, 7, 6, 5, 4, 4, + 8, 7, 7, 6, 5, 4, 4, 3, + }, +}; +*/ + +// standard scan = zigzag scan +static const unsigned char stdscan[] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63 +}; + +// zigzag scan conversion table +static const unsigned char zigzag[] = +{ + 0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63 +}; + +// zigzag scan reverse conversion table +static const unsigned char unzigzag[] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +// even/uneven zigzag scan conversion table +static const unsigned char even_zigzag[] = +{ + + 0, 5, 14, 27, 1, 6, 15, 28, + 3, 12, 25, 41, 8, 17, 30, 43, + 10, 23, 39, 52, 19, 32, 45, 54, + 21, 37, 50, 59, 34, 47, 56, 61, + 2, 7, 16, 29, 4, 13, 26, 42, + 9, 18, 31, 44, 11, 24, 40, 53, + 20, 33, 46, 55, 22, 38, 51, 60, + 35, 48, 57, 62, 36, 49, 58, 63, +}; + +// context weighting for each band (luminance) (from POTY 2006/2007) +static const signed int abs_ctx_weights_lum[ 64 ][ 3 ][ 5 ] = +{ + { // DCT(0/0) + { 0, 0, 7, 0, 0, }, + { 0, 6, 11, 8, 0, }, + { 9, 13, 0, 0, 0, }, + }, + { // DCT(1/0) + { 0, 0, 8, 0, 0, }, + { 0, 3, 28, 7, 0, }, + { 5, 7, 0, 0, 0, }, + }, + { // DCT(0/1) + { 0, 0, 5, 0, 0, }, + { 0, 4, 4, 6, 0, }, + { 8, 30, 0, 0, 0, }, + }, + { // DCT(0/2) + { 0, 0, 5, 0, 0, }, + { 0, 3, 5, 5, 0, }, + { 11, 27, 0, 0, 0, }, + }, + { // DCT(1/1) + { 0, 0, 4, 0, 0, }, + { 0, 7, 13, 10, 0, }, + { 6, 16, 0, 0, 0, }, + }, + { // DCT(2/0) + { 0, 0, 10, 0, 0, }, + { 0, 2, 25, 6, 0, }, + { 6, 9, 0, 0, 0, }, + }, + { // DCT(3/0) + { 0, 0, 10, 0, 0, }, + { 0, 1, 24, 6, 0, }, + { 7, 9, 0, 0, 0, }, + }, + { // DCT(2/1) + { 0, 0, 5, 0, 0, }, + { 0, 7, 15, 10, 0, }, + { 8, 12, 0, 0, 0, }, + }, + { // DCT(1/2) + { 0, 0, 6, 0, 0, }, + { 0, 8, 8, 10, 0, }, + { 7, 18, 0, 0, 0, }, + }, + { // DCT(0/3) + { 0, 0, 6, 0, 0, }, + { 0, 3, 5, 5, 0, }, + { 12, 26, 0, 0, 0, }, + }, + { // DCT(0/4) + { 0, 0, 6, 0, 0, }, + { 0, 3, 6, 5, 0, }, + { 13, 25, 0, 0, 0, }, + }, + { // DCT(1/3) + { 0, 0, 6, 0, 0, }, + { 0, 7, 8, 8, 0, }, + { 8, 19, 0, 0, 0, }, + }, + { // DCT(2/2) + { 0, 0, 5, 0, 0, }, + { 0, 8, 11, 11, 0, }, + { 8, 14, 0, 0, 0, }, + }, + { // DCT(3/1) + { 0, 0, 6, 0, 0, }, + { 0, 6, 16, 9, 0, }, + { 8, 11, 0, 0, 0, }, + }, + { // DCT(4/0) + { 0, 0, 11, 0, 0, }, + { 0, 1, 24, 5, 0, }, + { 7, 10, 0, 0, 0, }, + }, + { // DCT(5/0) + { 0, 0, 11, 0, 0, }, + { 0, 1, 24, 5, 0, }, + { 7, 10, 0, 0, 0, }, + }, + { // DCT(4/1) + { 0, 0, 7, 0, 0, }, + { 0, 6, 16, 9, 0, }, + { 8, 11, 0, 0, 0, }, + }, + { // DCT(3/2) + { 0, 0, 5, 0, 0, }, + { 0, 8, 12, 11, 0, }, + { 8, 12, 0, 0, 0, }, + }, + { // DCT(2/3) + { 0, 0, 6, 0, 0, }, + { 0, 8, 9, 10, 0, }, + { 8, 15, 0, 0, 0, }, + }, + { // DCT(1/4) + { 0, 0, 7, 0, 0, }, + { 0, 6, 8, 8, 0, }, + { 9, 19, 0, 0, 0, }, + }, + { // DCT(0/5) + { 0, 0, 6, 0, 0, }, + { 0, 2, 6, 5, 0, }, + { 13, 25, 0, 0, 0, }, + }, + { // DCT(0/6) + { 0, 0, 5, 0, 0, }, + { 0, 2, 6, 5, 0, }, + { 13, 24, 0, 0, 0, }, + }, + { // DCT(1/5) + { 0, 0, 7, 0, 0, }, + { 0, 6, 8, 7, 0, }, + { 10, 19, 0, 0, 0, }, + }, + { // DCT(2/4) + { 0, 0, 6, 0, 0, }, + { 0, 8, 9, 9, 0, }, + { 8, 16, 0, 0, 0, }, + }, + { // DCT(3/3) + { 0, 0, 6, 0, 0, }, + { 0, 8, 10, 11, 0, }, + { 8, 13, 0, 0, 0, }, + }, + { // DCT(4/2) + { 0, 0, 6, 0, 0, }, + { 0, 7, 13, 10, 0, }, + { 8, 11, 0, 0, 0, }, + }, + { // DCT(5/1) + { 0, 0, 7, 0, 0, }, + { 0, 6, 15, 8, 0, }, + { 8, 11, 0, 0, 0, }, + }, + { // DCT(6/0) + { 0, 0, 11, 0, 0, }, + { 0, 1, 23, 5, 0, }, + { 7, 10, 0, 0, 0, }, + }, + { // DCT(7/0) + { 0, 0, 11, 0, 0, }, + { 0, 1, 23, 5, 0, }, + { 7, 9, 0, 0, 0, }, + }, + { // DCT(6/1) + { 0, 0, 7, 0, 0, }, + { 0, 6, 15, 8, 0, }, + { 8, 10, 0, 0, 0, }, + }, + { // DCT(5/2) + { 0, 0, 7, 0, 0, }, + { 0, 7, 13, 9, 0, }, + { 8, 11, 0, 0, 0, }, + }, + { // DCT(4/3) + { 0, 0, 6, 0, 0, }, + { 0, 8, 11, 10, 0, }, + { 8, 12, 0, 0, 0, }, + }, + { // DCT(3/4) + { 0, 0, 6, 0, 0, }, + { 0, 8, 9, 10, 0, }, + { 8, 14, 0, 0, 0, }, + }, + { // DCT(2/5) + { 0, 0, 7, 0, 0, }, + { 0, 7, 8, 8, 0, }, + { 9, 16, 0, 0, 0, }, + }, + { // DCT(1/6) + { 0, 0, 7, 0, 0, }, + { 0, 6, 7, 7, 0, }, + { 10, 18, 0, 0, 0, }, + }, + { // DCT(0/7) + { 0, 0, 6, 0, 0, }, + { 0, 3, 6, 5, 0, }, + { 13, 24, 0, 0, 0, }, + }, + { // DCT(1/7) + { 0, 0, 6, 0, 0, }, + { 0, 5, 7, 6, 0, }, + { 10, 18, 0, 0, 0, }, + }, + { // DCT(2/6) + { 0, 0, 7, 0, 0, }, + { 0, 7, 8, 8, 0, }, + { 9, 15, 0, 0, 0, }, + }, + { // DCT(3/5) + { 0, 0, 6, 0, 0, }, + { 0, 8, 9, 9, 0, }, + { 8, 14, 0, 0, 0, }, + }, + { // DCT(4/4) + { 0, 0, 6, 0, 0, }, + { 0, 8, 10, 10, 0, }, + { 8, 12, 0, 0, 0, }, + }, + { // DCT(5/3) + { 0, 0, 6, 0, 0, }, + { 0, 7, 11, 10, 0, }, + { 8, 11, 0, 0, 0, }, + }, + { // DCT(6/2) + { 0, 0, 7, 0, 0, }, + { 0, 7, 13, 8, 0, }, + { 8, 11, 0, 0, 0, }, + }, + { // DCT(7/1) + { 0, 0, 8, 0, 0, }, + { 0, 5, 15, 8, 0, }, + { 8, 10, 0, 0, 0, }, + }, + { // DCT(7/2) + { 0, 0, 7, 0, 0, }, + { 0, 6, 13, 8, 0, }, + { 8, 10, 0, 0, 0, }, + }, + { // DCT(6/3) + { 0, 0, 6, 0, 0, }, + { 0, 7, 11, 9, 0, }, + { 8, 10, 0, 0, 0, }, + }, + { // DCT(5/4) + { 0, 0, 6, 0, 0, }, + { 0, 8, 10, 10, 0, }, + { 8, 11, 0, 0, 0, }, + }, + { // DCT(4/5) + { 0, 0, 6, 0, 0, }, + { 0, 8, 9, 9, 0, }, + { 8, 12, 0, 0, 0, }, + }, + { // DCT(3/6) + { 0, 0, 6, 0, 0, }, + { 0, 8, 8, 8, 0, }, + { 8, 13, 0, 0, 0, }, + }, + { // DCT(2/7) + { 0, 0, 6, 0, 0, }, + { 0, 6, 7, 7, 0, }, + { 9, 16, 0, 0, 0, }, + }, + { // DCT(3/7) + { 0, 0, 6, 0, 0, }, + { 0, 7, 7, 7, 0, }, + { 8, 14, 0, 0, 0, }, + }, + { // DCT(4/6) + { 0, 0, 6, 0, 0, }, + { 0, 8, 9, 9, 0, }, + { 7, 12, 0, 0, 0, }, + }, + { // DCT(5/5) + { 0, 0, 6, 0, 0, }, + { 0, 8, 9, 10, 0, }, + { 8, 11, 0, 0, 0, }, + }, + { // DCT(6/4) + { 0, 0, 6, 0, 0, }, + { 0, 7, 10, 9, 0, }, + { 7, 10, 0, 0, 0, }, + }, + { // DCT(7/3) + { 0, 0, 6, 0, 0, }, + { 0, 7, 12, 8, 0, }, + { 8, 10, 0, 0, 0, }, + }, + { // DCT(7/4) + { 0, 0, 6, 0, 0, }, + { 0, 7, 11, 8, 0, }, + { 7, 9, 0, 0, 0, }, + }, + { // DCT(6/5) + { 0, 0, 6, 0, 0, }, + { 0, 7, 9, 9, 0, }, + { 7, 10, 0, 0, 0, }, + }, + { // DCT(5/6) + { 0, 0, 6, 0, 0, }, + { 0, 8, 9, 9, 0, }, + { 7, 11, 0, 0, 0, }, + }, + { // DCT(4/7) + { 0, 0, 6, 0, 0, }, + { 0, 7, 7, 8, 0, }, + { 7, 12, 0, 0, 0, }, + }, + { // DCT(5/7) + { 0, 0, 6, 0, 0, }, + { 0, 8, 8, 8, 0, }, + { 7, 11, 0, 0, 0, }, + }, + { // DCT(6/6) + { 0, 0, 8, 0, 0, }, + { 0, 6, 7, 8, 0, }, + { 8, 12, 0, 0, 0, }, + }, + { // DCT(7/5) + { 0, 0, 6, 0, 0, }, + { 0, 7, 10, 9, 0, }, + { 7, 9, 0, 0, 0, }, + }, + { // DCT(7/6) + { 0, 0, 6, 0, 0, }, + { 0, 7, 9, 8, 0, }, + { 7, 10, 0, 0, 0, }, + }, + { // DCT(6/7) + { 0, 0, 6, 0, 0, }, + { 0, 7, 7, 8, 0, }, + { 7, 11, 0, 0, 0, }, + }, + { // DCT(7/7) + { 0, 0, 6, 0, 0, }, + { 0, 8, 8, 9, 0, }, + { 7, 9, 0, 0, 0, }, + }, +}; + +/* +// context weighting for each band (chrominance) (from POTY 2006/2007) +static const signed int abs_ctx_weights_chr[ 64 ][ 3 ][ 5 ] = +{ + { // DCT(0/0) + { 0, 0, 7, 0, 0, }, + { 0, 6, 11, 8, 0, }, + { 9, 13, 0, 0, 0, }, + }, + { // DCT(1/0) + { 0, 0, 6, 0, 0, }, + { 0, 4, 28, 8, 0, }, + { 5, 7, 0, 0, 0, }, + }, + { // DCT(0/1) + { 0, 0, 5, 0, 0, }, + { 0, 4, 5, 7, 0, }, + { 7, 29, 0, 0, 0, }, + }, + { // DCT(0/2) + { 0, 0, 5, 0, 0, }, + { 0, 4, 7, 6, 0, }, + { 10, 23, 0, 0, 0, }, + }, + { // DCT(1/1) + { 0, 0, 4, 0, 0, }, + { 0, 7, 13, 10, 0, }, + { 6, 16, 0, 0, 0, }, + }, + { // DCT(2/0) + { 0, 0, 9, 0, 0, }, + { 0, 3, 22, 7, 0, }, + { 6, 9, 0, 0, 0, }, + }, + { // DCT(3/0) + { 0, 0, 10, 0, 0, }, + { 0, 4, 19, 7, 0, }, + { 6, 9, 0, 0, 0, }, + }, + { // DCT(2/1) + { 0, 0, 6, 0, 0, }, + { 0, 7, 14, 10, 0, }, + { 7, 11, 0, 0, 0, }, + }, + { // DCT(1/2) + { 0, 0, 6, 0, 0, }, + { 0, 8, 9, 9, 0, }, + { 7, 16, 0, 0, 0, }, + }, + { // DCT(0/3) + { 0, 0, 6, 0, 0, }, + { 0, 4, 7, 6, 0, }, + { 10, 20, 0, 0, 0, }, + }, + { // DCT(0/4) + { 0, 0, 6, 0, 0, }, + { 0, 4, 7, 6, 0, }, + { 10, 19, 0, 0, 0, }, + }, + { // DCT(1/3) + { 0, 0, 6, 0, 0, }, + { 0, 7, 8, 8, 0, }, + { 7, 16, 0, 0, 0, }, + }, + { // DCT(2/2) + { 0, 0, 6, 0, 0, }, + { 0, 8, 10, 10, 0, }, + { 7, 12, 0, 0, 0, }, + }, + { // DCT(3/1) + { 0, 0, 6, 0, 0, }, + { 0, 6, 14, 9, 0, }, + { 7, 10, 0, 0, 0, }, + }, + { // DCT(4/0) + { 0, 0, 10, 0, 0, }, + { 0, 3, 19, 6, 0, }, + { 6, 8, 0, 0, 0, }, + }, + { // DCT(5/0) + { 0, 0, 9, 0, 0, }, + { 0, 3, 18, 6, 0, }, + { 6, 8, 0, 0, 0, }, + }, + { // DCT(4/1) + { 0, 0, 6, 0, 0, }, + { 0, 6, 13, 8, 0, }, + { 7, 9, 0, 0, 0, }, + }, + { // DCT(3/2) + { 0, 0, 6, 0, 0, }, + { 0, 7, 11, 9, 0, }, + { 7, 10, 0, 0, 0, }, + }, + { // DCT(2/3) + { 0, 0, 6, 0, 0, }, + { 0, 7, 9, 9, 0, }, + { 7, 12, 0, 0, 0, }, + }, + { // DCT(1/4) + { 0, 0, 6, 0, 0, }, + { 0, 6, 8, 7, 0, }, + { 7, 14, 0, 0, 0, }, + }, + { // DCT(0/5) + { 0, 0, 5, 0, 0, }, + { 0, 4, 7, 5, 0, }, + { 10, 19, 0, 0, 0, }, + }, + { // DCT(0/6) + { 0, 0, 5, 0, 0, }, + { 0, 4, 7, 5, 0, }, + { 10, 18, 0, 0, 0, }, + }, + { // DCT(1/5) + { 0, 0, 6, 0, 0, }, + { 0, 6, 8, 7, 0, }, + { 7, 14, 0, 0, 0, }, + }, + { // DCT(2/4) + { 0, 0, 6, 0, 0, }, + { 0, 7, 8, 8, 0, }, + { 7, 12, 0, 0, 0, }, + }, + { // DCT(3/3) + { 0, 0, 6, 0, 0, }, + { 0, 7, 9, 9, 0, }, + { 7, 10, 0, 0, 0, }, + }, + { // DCT(4/2) + { 0, 0, 6, 0, 0, }, + { 0, 7, 11, 9, 0, }, + { 6, 9, 0, 0, 0, }, + }, + { // DCT(5/1) + { 0, 0, 6, 0, 0, }, + { 0, 6, 12, 7, 0, }, + { 6, 9, 0, 0, 0, }, + }, + { // DCT(6/0) + { 0, 0, 9, 0, 0, }, + { 0, 3, 18, 5, 0, }, + { 5, 7, 0, 0, 0, }, + }, + { // DCT(7/0) + { 0, 0, 9, 0, 0, }, + { 0, 3, 18, 5, 0, }, + { 5, 6, 0, 0, 0, }, + }, + { // DCT(6/1) + { 0, 0, 6, 0, 0, }, + { 0, 6, 12, 7, 0, }, + { 6, 8, 0, 0, 0, }, + }, + { // DCT(5/2) + { 0, 0, 6, 0, 0, }, + { 0, 6, 10, 8, 0, }, + { 6, 9, 0, 0, 0, }, + }, + { // DCT(4/3) + { 0, 0, 6, 0, 0, }, + { 0, 7, 10, 9, 0, }, + { 6, 9, 0, 0, 0, }, + }, + { // DCT(3/4) + { 0, 0, 6, 0, 0, }, + { 0, 7, 9, 9, 0, }, + { 7, 11, 0, 0, 0, }, + }, + { // DCT(2/5) + { 0, 0, 6, 0, 0, }, + { 0, 6, 8, 7, 0, }, + { 7, 12, 0, 0, 0, }, + }, + { // DCT(1/6) + { 0, 0, 5, 0, 0, }, + { 0, 6, 7, 6, 0, }, + { 7, 14, 0, 0, 0, }, + }, + { // DCT(0/7) + { 0, 0, 5, 0, 0, }, + { 0, 3, 6, 5, 0, }, + { 9, 21, 0, 0, 0, }, + }, + { // DCT(1/7) + { 0, 0, 5, 0, 0, }, + { 0, 5, 7, 6, 0, }, + { 7, 14, 0, 0, 0, }, + }, + { // DCT(2/6) + { 0, 0, 5, 0, 0, }, + { 0, 6, 8, 7, 0, }, + { 7, 12, 0, 0, 0, }, + }, + { // DCT(3/5) + { 0, 0, 6, 0, 0, }, + { 0, 7, 8, 8, 0, }, + { 7, 11, 0, 0, 0, }, + }, + { // DCT(4/4) + { 0, 0, 6, 0, 0, }, + { 0, 7, 9, 8, 0, }, + { 6, 10, 0, 0, 0, }, + }, + { // DCT(5/3) + { 0, 0, 6, 0, 0, }, + { 0, 6, 10, 8, 0, }, + { 6, 9, 0, 0, 0, }, + }, + { // DCT(6/2) + { 0, 0, 6, 0, 0, }, + { 0, 6, 10, 7, 0, }, + { 6, 8, 0, 0, 0, }, + }, + { // DCT(7/1) + { 0, 0, 6, 0, 0, }, + { 0, 5, 12, 7, 0, }, + { 6, 7, 0, 0, 0, }, + }, + { // DCT(7/2) + { 0, 0, 6, 0, 0, }, + { 0, 6, 11, 7, 0, }, + { 6, 8, 0, 0, 0, }, + }, + { // DCT(6/3) + { 0, 0, 6, 0, 0, }, + { 0, 6, 9, 8, 0, }, + { 6, 8, 0, 0, 0, }, + }, + { // DCT(5/4) + { 0, 0, 6, 0, 0, }, + { 0, 7, 9, 8, 0, }, + { 6, 9, 0, 0, 0, }, + }, + { // DCT(4/5) + { 0, 0, 6, 0, 0, }, + { 0, 7, 8, 8, 0, }, + { 6, 10, 0, 0, 0, }, + }, + { // DCT(3/6) + { 0, 0, 6, 0, 0, }, + { 0, 7, 8, 7, 0, }, + { 7, 11, 0, 0, 0, }, + }, + { // DCT(2/7) + { 0, 0, 5, 0, 0, }, + { 0, 6, 7, 6, 0, }, + { 6, 12, 0, 0, 0, }, + }, + { // DCT(3/7) + { 0, 0, 5, 0, 0, }, + { 0, 6, 7, 6, 0, }, + { 6, 11, 0, 0, 0, }, + }, + { // DCT(4/6) + { 0, 0, 6, 0, 0, }, + { 0, 7, 8, 8, 0, }, + { 6, 10, 0, 0, 0, }, + }, + { // DCT(5/5) + { 0, 0, 6, 0, 0, }, + { 0, 7, 8, 8, 0, }, + { 6, 9, 0, 0, 0, }, + }, + { // DCT(6/4) + { 0, 0, 6, 0, 0, }, + { 0, 6, 9, 8, 0, }, + { 6, 8, 0, 0, 0, }, + }, + { // DCT(7/3) + { 0, 0, 6, 0, 0, }, + { 0, 6, 10, 7, 0, }, + { 6, 8, 0, 0, 0, }, + }, + { // DCT(7/4) + { 0, 0, 6, 0, 0, }, + { 0, 6, 9, 7, 0, }, + { 6, 8, 0, 0, 0, }, + }, + { // DCT(6/5) + { 0, 0, 6, 0, 0, }, + { 0, 7, 8, 8, 0, }, + { 6, 8, 0, 0, 0, }, + }, + { // DCT(5/6) + { 0, 0, 6, 0, 0, }, + { 0, 7, 8, 8, 0, }, + { 6, 9, 0, 0, 0, }, + }, + { // DCT(4/7) + { 0, 0, 6, 0, 0, }, + { 0, 7, 7, 7, 0, }, + { 6, 10, 0, 0, 0, }, + }, + { // DCT(5/7) + { 0, 0, 6, 0, 0, }, + { 0, 7, 7, 7, 0, }, + { 6, 9, 0, 0, 0, }, + }, + { // DCT(6/6) + { 0, 0, 6, 0, 0, }, + { 0, 7, 10, 8, 0, }, + { 6, 10, 0, 0, 0, }, + }, + { // DCT(7/5) + { 0, 0, 6, 0, 0, }, + { 0, 6, 8, 7, 0, }, + { 6, 8, 0, 0, 0, }, + }, + { // DCT(7/6) + { 0, 0, 6, 0, 0, }, + { 0, 7, 10, 8, 0, }, + { 6, 10, 0, 0, 0, }, + }, + { // DCT(6/7) + { 0, 0, 6, 0, 0, }, + { 0, 7, 10, 8, 0, }, + { 6, 10, 0, 0, 0, }, + }, + { // DCT(7/7) + { 0, 0, 6, 0, 0, }, + { 0, 7, 10, 8, 0, }, + { 6, 9, 0, 0, 0, }, + }, +}; +*/ + +// tresholds (size of component) for configuration sets +static const unsigned int conf_sets[][3] = +{ + { 76800, 19200, 19200 }, // 2480x1920 + { 19200, 4800, 4800 }, // 1280x960 + { 10800, 2700, 2700 }, // 960x720 + { 4800, 1200, 1200 }, // 640x480 + { 1200, 300, 300 }, // 320x240 + { 0, 0, 0 } // 0x0 +}; + +// configuration sets for number of segments +static const unsigned char conf_segm[][3] = +{ + { 10, 10, 10 }, + { 10, 10, 10 }, + { 10, 10, 10 }, + { 10, 10, 10 }, + { 10, 10, 10 }, + { 10, 10, 10 } +}; + +// configuration sets for noise thresholds +static const unsigned char conf_ntrs[][3] = +{ + { 7, 7, 7 }, + { 6, 6, 6 }, + { 5, 5, 5 }, + { 5, 5, 5 }, + { 4, 4, 4 }, + { 4, 4, 4 } +}; + + +// standard huffman tables, found in JPEG specification, Chapter K.3 +static const unsigned char std_huff_tables[4][272] = +{ + { // standard luma dc table (0/0) + 0x00,0x01,0x05,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B + }, + { // standard chroma dc table (0/1) + 0x00,0x03,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B + }, + { // standard luma ac table (1/0) + 0x00,0x02,0x01,0x03,0x03,0x02,0x04,0x03,0x05,0x05,0x04,0x04,0x00,0x00,0x01,0x7D, + 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07, + 0x22,0x71,0x14,0x32,0x81,0x91,0xA1,0x08,0x23,0x42,0xB1,0xC1,0x15,0x52,0xD1,0xF0, + 0x24,0x33,0x62,0x72,0x82,0x09,0x0A,0x16,0x17,0x18,0x19,0x1A,0x25,0x26,0x27,0x28, + 0x29,0x2A,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48,0x49, + 0x4A,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68,0x69, + 0x6A,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x83,0x84,0x85,0x86,0x87,0x88,0x89, + 0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7, + 0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xC2,0xC3,0xC4,0xC5, + 0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xE1,0xE2, + 0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8, + 0xF9,0xFA + }, + { // standard chroma ac table (1/1) + 0x00,0x02,0x01,0x02,0x04,0x04,0x03,0x04,0x07,0x05,0x04,0x04,0x00,0x01,0x02,0x77, + 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71, + 0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xA1,0xB1,0xC1,0x09,0x23,0x33,0x52,0xF0, + 0x15,0x62,0x72,0xD1,0x0A,0x16,0x24,0x34,0xE1,0x25,0xF1,0x17,0x18,0x19,0x1A,0x26, + 0x27,0x28,0x29,0x2A,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48, + 0x49,0x4A,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68, + 0x69,0x6A,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,0xA4,0xA5, + 0xA6,0xA7,0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xC2,0xC3, + 0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA, + 0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8, + 0xF9,0xFA + } +}; + +// lengths of standard huffmann tables +static const unsigned char std_huff_lengths[ 4 ] = { 28, 28, 178, 178 }; + + +// precalculated bit lengths for values 0...1024 +int pbitlen_0_1024[] = +{ + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 32 + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 64 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 96 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 128 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 160 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 192 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 224 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 256 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 288 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 320 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 352 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 384 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 416 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 448 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 480 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 512 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 544 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 576 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 608 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 640 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 672 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 704 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 736 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 768 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 800 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 832 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 864 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 896 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 928 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 960 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 992 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 1024 + 11 +}; + +// precalculated bit lengths for values -2048...2047 +int pbitlen_n2048_2047[] = +{ + 12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -2016 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1984 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1952 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1920 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1888 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1856 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1824 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1792 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1760 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1728 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1696 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1664 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1632 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1600 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1568 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1536 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1504 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1472 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1440 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1408 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1376 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1344 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1312 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1280 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1248 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1216 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1184 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1152 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1120 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1088 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1056 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // -1024 + 11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // -992 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // -960 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // -928 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // -896 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // -864 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // -832 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // -800 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // -768 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // -736 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // -704 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // -672 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // -640 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // -608 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // -576 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // -544 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // -512 + 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // -480 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // -448 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // -416 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // -384 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // -352 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // -320 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // -288 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // -256 + 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // -224 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // -192 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // -160 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // -128 + 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // -96 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // -64 + 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // -32 + 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 1, // 0 + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 32 + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 64 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 96 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 128 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 160 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 192 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 224 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 256 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 288 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 320 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 352 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 384 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 416 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 448 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 480 + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 512 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 544 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 576 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 608 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 640 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 672 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 704 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 736 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 768 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 800 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 832 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 864 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 896 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 928 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 960 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 992 + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // 1024 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1056 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1088 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1120 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1152 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1184 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1216 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1248 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1280 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1312 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1344 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1376 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1408 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1440 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1472 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1504 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1536 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1568 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1600 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1632 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1664 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1696 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1728 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1760 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1792 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1824 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1856 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1888 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1920 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1952 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 1984 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, // 2016 + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11 // 2048 +}; + + +// precalculated segmentation settings (the 0th setting corresponds to 1 segments) +unsigned char segm_tables[ 49 ][ 50 ] = +{ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, // s0 + { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }, // s1 + { 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, }, // s2 + { 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, }, // s3 + { 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, }, // s4 + { 0, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, }, // s5 + { 0, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, }, // s6 + { 0, 1, 2, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, }, // s7 + { 0, 1, 2, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, }, // s8 + { 0, 1, 2, 3, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, }, // s9 + { 0, 1, 2, 3, 4, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, }, // s10 + { 0, 1, 2, 3, 4, 5, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, }, // s11 + { 0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, + 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, }, // s12 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, + 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, }, // s13 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, + 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, }, // s14 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, + 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, }, // s15 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 13, 14, + 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, }, // s16 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 14, + 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, }, // s17 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, + 15, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, }, // s18 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, + 16, 16, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, }, // s19 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 16, 16, 16, 17, 17, 17, + 17, 17, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, }, // s20 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 16, 17, 17, 17, 17, 18, 18, + 18, 18, 18, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, }, // s21 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 17, 17, 18, 18, 18, 18, 19, + 19, 19, 19, 19, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, }, // s22 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, 18, 19, 19, 19, 19, + 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, }, // s23 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 19, 20, 20, 20, + 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, }, // s24 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 20, 21, 21, 21, + 21, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, }, // s25 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 21, 22, 22, + 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, }, // s26 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 22, 23, + 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, }, // s27 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, }, // s28 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, }, // s29 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, }, // s30 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, }, // s31 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, }, // s32 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 29, 30, 30, 30, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, }, // s33 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 34, }, // s34 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, }, // s35 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, }, // s36 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, }, // s37 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, }, // s38 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, }, // s39 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, }, // s40 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 41, }, // s41 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 41, 41, 41, 42, 42, 42, 42, 42, }, // s42 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 42, 42, 43, 43, 43, 43, 43, }, // s43 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 43, 44, 44, 44, 44, 44, }, // s44 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 45, 45, 45, 45, }, // s45 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 46, 46, 46, }, // s46 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 47, 47, }, // s47 + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 48, }, // s48 +}; + + +/* +// old stuff starting here - no more used, therefore commented out + +// zagzig scan, can be used instead of zigzag scan +static const unsigned char zagscan[] = +{ + 0, 2, 1, 5, 4, 3, 9, 8, + 7, 6, 14, 13, 12, 11, 10, 20, + 19, 18, 17, 16, 15, 27, 26, 25, + 24, 23, 22, 21, 35, 34, 33, 32, + 31, 30, 29, 28, 42, 41, 40, 39, + 38, 37, 36, 48, 47, 46, 45, 44, + 43, 53, 52, 51, 50, 49, 57, 56, + 55, 54, 60, 59, 58, 62, 61, 63 +}; + +// distance scan, can be used instead of zigzag scan +static const unsigned char distscan[] = +{ + 0, 2, 1, 4, 3, 5, 7, 8, + 12, 6, 9, 11, 13, 17, 18, 10, + 14, 16, 19, 24, 25, 23, 20, 32, + 31, 15, 26, 22, 33, 30, 39, 38, + 40, 27, 21, 34, 29, 41, 37, 46, + 45, 44, 47, 35, 28, 51, 36, 42, + 52, 50, 48, 43, 53, 49, 56, 55, + 54, 57, 59, 60, 58, 62, 61, 63 +}; + +// diagonal / horizontal / vertical scan, don't use this unless you want bad results +static const unsigned char dhvscan[] = +{ + 0, 4, 12, 24, 39, 51, 59, 63, + 1, 5, 6, 7, 13, 14, 15, 16, + 17, 25, 26, 27, 28, 29, 30, 31, + 40, 41, 42, 43, 44, 45, 52, 53, + 54, 55, 60, 61, + 2, 3, 8, 9, 10, 11, 18, 19, + 20, 21, 22, 23, 32, 33, 34, 35, + 36, 37, 38, 46, 47, 48, 49, 50, + 56, 57, 58, 62 +}; + +// sign relevancy scan +static const unsigned char sgnscan[] = +{ + 0, 1, 2, 3, 5, 6, 9, 10, + 14, 15, 20, 21, 27, 28, 35, 4, + 7, 13, 16, 26, 29, 42, 8, 12, + 17, 25, 30, 41, 43, 11, 18, 24, + 31, 40, 44, 53, 19, 23, 32, 39, + 45, 52, 54, 22, 33, 38, 46, 51, + 55, 60, 34, 37, 47, 50, 56, 59, + 61, 36, 48, 49, 57, 58, 62, 63 +}; + +// even/uneven zigzag scan reverse conversion table +static const int even_natural_order[] = +{ + + 0, 8, 9, 3, 1, 16, 2, 10, + 12, 26, 40, 41, 19, 33, 48, 34, + 35, 49, 57, 43, 42, 56, 50, 36, + 58, 52, 38, 39, 59, 45, 31, 46, + 17, 32, 18, 4, 24, 25, 11, 5, + 27, 13, 7, 21, 20, 6, 14, 28, + 29, 15, 30, 44, 22, 23, 37, 51, + 53, 61, 47, 62, 60, 54, 55, 63, +}; + +// scans for each frequency +static const char freqalign[] = +{ + 'm', 'v', 'v', 'v', 'v', 'v', 'v', 'v', + 'h', 'm', 'v', 'v', 'v', 'v', 'v', 'v', + 'h', 'h', 'm', 'v', 'v', 'v', 'v', 'v', + 'h', 'h', 'h', 'm', 'v', 'v', 'v', 'v', + 'h', 'h', 'h', 'h', 'm', 'v', 'v', 'v', + 'h', 'h', 'h', 'h', 'h', 'm', 'v', 'v', + 'h', 'h', 'h', 'h', 'h', 'h', 'm', 'v', + 'h', 'h', 'h', 'h', 'h', 'h', 'h', 'm' +}; + +// chengjie tu subband classification +static const unsigned char ctxclass[] = +{ + 0, 1, 3, 3, 3, 6, 6, 6, // 0 -> DC (DC subband) + 2, 5, 5, 5, 6, 6, 6, 6, // 1 -> PV (principal vertical) + 4, 5, 5, 5, 6, 6, 6, 6, // 2 -> PH (principal horizontal) + 4, 5, 5, 6, 6, 6, 6, 6, // 3 -> LV (low-frequency vertical) + 4, 6, 6, 6, 6, 6, 6, 6, // 4 -> LH (low-frequency horizontal) + 6, 6, 6, 6, 6, 6, 6, 6, // 5 -> LD (low-frequency diagonal) + 6, 6, 6, 6, 6, 6, 6, 6, // 6 -> HP (high-pass) + 6, 6, 6, 6, 6, 6, 6, 6 +}; + +// context weighting for subband classification +static const signed int ctx_weights[ 7 ][ 3 ][ 5 ] = +{ + { // 0 -> DC (DC subband) + { 0, 0, 2, 0, 0 }, + { 0, 3, 4, 3, 0 }, + { 2, 4, 0, 0, 0 } + }, + { // 1 -> PV (principal vertical) + { 0, 0, 3, 0, 0 }, + { 0, 0, 6, 0, 0 }, + { 0, 0, 0, 0, 0 } + }, + { // 2 -> PH (principal horizontal) + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + { 3, 6, 0, 0, 0 } + }, + { // 3 -> LV (low-frequency vertical) + { 0, 0, 3, 0, 0 }, + { 0, 1, 6, 1, 0 }, + { 0, 1, 0, 0, 0 } + }, + { // 4 -> LH (low-frequency horizontal) + { 0, 0, 0, 0, 0 }, + { 0, 1, 1, 1, 0 }, + { 3, 6, 0, 0, 0 } + }, + { // 5 -> LD (low-frequency diagonal) + { 0, 0, 2, 0, 0 }, + { 0, 3, 4, 3, 0 }, + { 2, 4, 0, 0, 0 } + }, + { // 6 -> HP (high-pass) + { 0, 0, 2, 0, 0 }, + { 0, 3, 4, 3, 0 }, + { 2, 4, 0, 0, 0 } + } +}; + +// context weighting for each band (from mixedlum27 set) +static const signed int abs_ctx_weights[ 64 ][ 3 ][ 5 ] = +{ + { // DCT(0/0) + { 0, 0, 7, 0, 0, }, + { 0, 6, 11, 8, 0, }, + { 9, 13, 0, 0, 0, }, + }, + { // DCT(1/0) + { 0, 0, 7, 0, 0, }, + { 0, 4, 30, 6, 0, }, + { 5, 6, 0, 0, 0, }, + }, + { // DCT(0/1) + { 0, 0, 4, 0, 0, }, + { 0, 3, 3, 6, 0, }, + { 7, 35, 0, 0, 0, }, + }, + { // DCT(0/2) + { 0, 0, 5, 0, 0, }, + { 0, 2, 5, 6, 0, }, + { 10, 29, 0, 0, 0, }, + }, + { // DCT(1/1) + { 0, 0, 4, 0, 0, }, + { 0, 7, 13, 11, 0, }, + { 5, 16, 0, 0, 0, }, + }, + { // DCT(2/0) + { 0, 0, 10, 0, 0, }, + { 0, 2, 27, 6, 0, }, + { 5, 8, 0, 0, 0, }, + }, + { // DCT(3/0) + { 0, 0, 11, 0, 0, }, + { 0, 2, 24, 6, 0, }, + { 6, 9, 0, 0, 0, }, + }, + { // DCT(2/1) + { 0, 0, 5, 0, 0, }, + { 0, 8, 15, 10, 0, }, + { 6, 12, 0, 0, 0, }, + }, + { // DCT(1/2) + { 0, 0, 6, 0, 0, }, + { 0, 7, 9, 11, 0, }, + { 7, 17, 0, 0, 0, }, + }, + { // DCT(0/3) + { 0, 0, 6, 0, 0, }, + { 0, 3, 6, 6, 0, }, + { 11, 26, 0, 0, 0, }, + }, + { // DCT(0/4) + { 0, 0, 6, 0, 0, }, + { 0, 3, 6, 7, 0, }, + { 11, 24, 0, 0, 0, }, + }, + { // DCT(1/3) + { 0, 0, 6, 0, 0, }, + { 0, 6, 9, 10, 0, }, + { 8, 17, 0, 0, 0, }, + }, + { // DCT(2/2) + { 0, 0, 5, 0, 0, }, + { 0, 9, 11, 11, 0, }, + { 7, 13, 0, 0, 0, }, + }, + { // DCT(3/1) + { 0, 0, 6, 0, 0, }, + { 0, 7, 16, 10, 0, }, + { 7, 11, 0, 0, 0, }, + }, + { // DCT(4/0) + { 0, 0, 11, 0, 0, }, + { 0, 3, 22, 6, 0, }, + { 7, 9, 0, 0, 0, }, + }, + { // DCT(5/0) + { 0, 0, 11, 0, 0, }, + { 0, 3, 19, 6, 0, }, + { 7, 9, 0, 0, 0, }, + }, + { // DCT(4/1) + { 0, 0, 7, 0, 0, }, + { 0, 7, 15, 9, 0, }, + { 8, 11, 0, 0, 0, }, + }, + { // DCT(3/2) + { 0, 0, 6, 0, 0, }, + { 0, 8, 13, 10, 0, }, + { 7, 12, 0, 0, 0, }, + }, + { // DCT(2/3) + { 0, 0, 6, 0, 0, }, + { 0, 8, 10, 11, 0, }, + { 7, 14, 0, 0, 0, }, + }, + { // DCT(1/4) + { 0, 0, 7, 0, 0, }, + { 0, 6, 9, 10, 0, }, + { 8, 16, 0, 0, 0, }, + }, + { // DCT(0/5) + { 0, 0, 5, 0, 0, }, + { 0, 3, 6, 6, 0, }, + { 13, 24, 0, 0, 0, }, + }, + { // DCT(0/6) + { 0, 0, 5, 0, 0, }, + { 0, 3, 6, 6, 0, }, + { 13, 20, 0, 0, 0, }, + }, + { // DCT(1/5) + { 0, 0, 7, 0, 0, }, + { 0, 7, 9, 9, 0, }, + { 8, 15, 0, 0, 0, }, + }, + { // DCT(2/4) + { 0, 0, 7, 0, 0, }, + { 0, 8, 10, 10, 0, }, + { 7, 13, 0, 0, 0, }, + }, + { // DCT(3/3) + { 0, 0, 7, 0, 0, }, + { 0, 9, 10, 11, 0, }, + { 7, 12, 0, 0, 0, }, + }, + { // DCT(4/2) + { 0, 0, 7, 0, 0, }, + { 0, 8, 12, 9, 0, }, + { 8, 11, 0, 0, 0, }, + }, + { // DCT(5/1) + { 0, 0, 7, 0, 0, }, + { 0, 7, 13, 9, 0, }, + { 8, 10, 0, 0, 0, }, + }, + { // DCT(6/0) + { 0, 0, 12, 0, 0, }, + { 0, 3, 18, 5, 0, }, + { 5, 7, 0, 0, 0, }, + }, + { // DCT(7/0) + { 0, 0, 13, 0, 0, }, + { 0, 3, 19, 3, 0, }, + { 5, 6, 0, 0, 0, }, + }, + { // DCT(6/1) + { 0, 0, 7, 0, 0, }, + { 0, 6, 11, 8, 0, }, + { 7, 9, 0, 0, 0, }, + }, + { // DCT(5/2) + { 0, 0, 7, 0, 0, }, + { 0, 7, 11, 8, 0, }, + { 7, 10, 0, 0, 0, }, + }, + { // DCT(4/3) + { 0, 0, 6, 0, 0, }, + { 0, 8, 10, 10, 0, }, + { 7, 11, 0, 0, 0, }, + }, + { // DCT(3/4) + { 0, 0, 7, 0, 0, }, + { 0, 8, 10, 10, 0, }, + { 7, 11, 0, 0, 0, }, + }, + { // DCT(2/5) + { 0, 0, 6, 0, 0, }, + { 0, 7, 9, 9, 0, }, + { 8, 12, 0, 0, 0, }, + }, + { // DCT(1/6) + { 0, 0, 6, 0, 0, }, + { 0, 6, 8, 8, 0, }, + { 8, 12, 0, 0, 0, }, + }, + { // DCT(0/7) + { 0, 0, 3, 0, 0, }, + { 0, 1, 4, 4, 0, }, + { 17, 24, 0, 0, 0, }, + }, + { // DCT(1/7) + { 0, 0, 5, 0, 0, }, + { 0, 5, 7, 7, 0, }, + { 6, 11, 0, 0, 0, }, + }, + { // DCT(2/6) + { 0, 0, 6, 0, 0, }, + { 0, 7, 8, 7, 0, }, + { 7, 10, 0, 0, 0, }, + }, + { // DCT(3/5) + { 0, 0, 6, 0, 0, }, + { 0, 7, 9, 8, 0, }, + { 7, 11, 0, 0, 0, }, + }, + { // DCT(4/4) + { 0, 0, 6, 0, 0, }, + { 0, 7, 9, 9, 0, }, + { 7, 10, 0, 0, 0, }, + }, + { // DCT(5/3) + { 0, 0, 6, 0, 0, }, + { 0, 7, 9, 8, 0, }, + { 7, 9, 0, 0, 0, }, + }, + { // DCT(6/2) + { 0, 0, 7, 0, 0, }, + { 0, 6, 9, 7, 0, }, + { 6, 9, 0, 0, 0, }, + }, + { // DCT(7/1) + { 0, 0, 8, 0, 0, }, + { 0, 7, 11, 8, 0, }, + { 8, 9, 0, 0, 0, }, + }, + { // DCT(7/2) + { 0, 0, 7, 0, 0, }, + { 0, 7, 9, 8, 0, }, + { 8, 10, 0, 0, 0, }, + }, + { // DCT(6/3) + { 0, 0, 5, 0, 0, }, + { 0, 6, 9, 7, 0, }, + { 6, 8, 0, 0, 0, }, + }, + { // DCT(5/4) + { 0, 0, 6, 0, 0, }, + { 0, 7, 8, 8, 0, }, + { 6, 8, 0, 0, 0, }, + }, + { // DCT(4/5) + { 0, 0, 5, 0, 0, }, + { 0, 7, 9, 8, 0, }, + { 6, 9, 0, 0, 0, }, + }, + { // DCT(3/6) + { 0, 0, 6, 0, 0, }, + { 0, 7, 7, 7, 0, }, + { 6, 10, 0, 0, 0, }, + }, + { // DCT(2/7) + { 0, 0, 5, 0, 0, }, + { 0, 6, 6, 6, 0, }, + { 6, 10, 0, 0, 0, }, + }, + { // DCT(3/7) + { 0, 0, 5, 0, 0, }, + { 0, 6, 6, 6, 0, }, + { 6, 9, 0, 0, 0, }, + }, + { // DCT(4/6) + { 0, 0, 6, 0, 0, }, + { 0, 5, 7, 7, 0, }, + { 6, 8, 0, 0, 0, }, + }, + { // DCT(5/5) + { 0, 0, 6, 0, 0, }, + { 0, 6, 7, 7, 0, }, + { 6, 8, 0, 0, 0, }, + }, + { // DCT(6/4) + { 0, 0, 5, 0, 0, }, + { 0, 5, 7, 7, 0, }, + { 6, 8, 0, 0, 0, }, + }, + { // DCT(7/3) + { 0, 0, 6, 0, 0, }, + { 0, 6, 9, 7, 0, }, + { 7, 8, 0, 0, 0, }, + }, + { // DCT(7/4) + { 0, 0, 6, 0, 0, }, + { 0, 5, 7, 6, 0, }, + { 7, 8, 0, 0, 0, }, + }, + { // DCT(6/5) + { 0, 0, 5, 0, 0, }, + { 0, 5, 6, 6, 0, }, + { 6, 6, 0, 0, 0, }, + }, + { // DCT(5/6) + { 0, 0, 5, 0, 0, }, + { 0, 5, 6, 6, 0, }, + { 5, 8, 0, 0, 0, }, + }, + { // DCT(4/7) + { 0, 0, 5, 0, 0, }, + { 0, 5, 7, 5, 0, }, + { 7, 7, 0, 0, 0, }, + }, + { // DCT(5/7) + { 0, 0, 7, 0, 0, }, + { 0, 3, 7, 6, 0, }, + { 6, 7, 0, 0, 0, }, + }, + { // DCT(6/6) + { 0, 0, 5, 0, 0, }, + { 0, 4, 5, 6, 0, }, + { 5, 6, 0, 0, 0, }, + }, + { // DCT(7/5) + { 0, 0, 5, 0, 0, }, + { 0, 4, 7, 5, 0, }, + { 7, 8, 0, 0, 0, }, + }, + { // DCT(7/6) + { 0, 0, 5, 0, 0, }, + { 0, 4, 7, 5, 0, }, + { 5, 6, 0, 0, 0, }, + }, + { // DCT(6/7) + { 0, 0, 6, 0, 0, }, + { 0, 6, 6, 6, 0, }, + { 6, 7, 0, 0, 0, }, + }, + { // DCT(7/7) + { 0, 0, 10, 0, 0, }, + { 0, 4, 8, 5, 0, }, + { 11, 8, 0, 0, 0, }, + }, +}; +*/ diff --git a/transpose/transpose.c b/filters/transpose/transpose.c similarity index 100% rename from transpose/transpose.c rename to filters/transpose/transpose.c diff --git a/transpose/transpose.h b/filters/transpose/transpose.h similarity index 100% rename from transpose/transpose.h rename to filters/transpose/transpose.h