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