mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2025-12-26 22:48:19 +00:00
When using config.h, it must be the very first include in all source files since it contains #define that may change the compilation process (eg libc structure layout changes when it's used to enable large file support on 32 bit x86 archs). This commit adds it at the beginning of all .c and .cpp files
576 lines
17 KiB
C
576 lines
17 KiB
C
/*
|
|
Copyright (C) 2009 Red Hat, Inc.
|
|
|
|
This library 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 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library 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 library; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#define DJB2_START 5381;
|
|
#define DJB2_HASH(hash, c) (hash = ((hash << 5) + hash) ^ (c)) //|{hash = ((hash << 5) + hash) + c;}
|
|
|
|
/*
|
|
For each pixel type the following macros are defined:
|
|
PIXEL : input type
|
|
FNAME(name)
|
|
ENCODE_PIXEL(encoder, pixel) : writing a pixel to the compressed buffer (byte by byte)
|
|
SAME_PIXEL(pix1, pix2) : comparing two pixels
|
|
HASH_FUNC(value, pix_ptr) : hash func of 3 consecutive pixels
|
|
*/
|
|
|
|
#ifdef LZ_PLT
|
|
#define PIXEL one_byte_pixel_t
|
|
#define FNAME(name) glz_plt_##name
|
|
#define ENCODE_PIXEL(e, pix) encode(e, (pix).a) // gets the pixel and write only the needed bytes
|
|
// from the pixel
|
|
#define SAME_PIXEL(pix1, pix2) ((pix1).a == (pix2).a)
|
|
#define MIN_REF_ENCODE_SIZE 4
|
|
#define MAX_REF_ENCODE_SIZE 7
|
|
#define HASH_FUNC(v, p) { \
|
|
v = DJB2_START; \
|
|
DJB2_HASH(v, p[0].a); \
|
|
DJB2_HASH(v, p[1].a); \
|
|
DJB2_HASH(v, p[2].a); \
|
|
v &= HASH_MASK; \
|
|
}
|
|
#endif
|
|
|
|
#ifdef LZ_RGB_ALPHA
|
|
//#undef LZ_RGB_ALPHA
|
|
#define PIXEL rgb32_pixel_t
|
|
#define FNAME(name) glz_rgb_alpha_##name
|
|
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).pad);}
|
|
#define SAME_PIXEL(pix1, pix2) ((pix1).pad == (pix2).pad)
|
|
#define MIN_REF_ENCODE_SIZE 4
|
|
#define MAX_REF_ENCODE_SIZE 7
|
|
#define HASH_FUNC(v, p) { \
|
|
v = DJB2_START; \
|
|
DJB2_HASH(v, p[0].pad); \
|
|
DJB2_HASH(v, p[1].pad); \
|
|
DJB2_HASH(v, p[2].pad); \
|
|
v &= HASH_MASK; \
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef LZ_RGB16
|
|
#define PIXEL rgb16_pixel_t
|
|
#define FNAME(name) glz_rgb16_##name
|
|
#define GET_r(pix) (((pix) >> 10) & 0x1f)
|
|
#define GET_g(pix) (((pix) >> 5) & 0x1f)
|
|
#define GET_b(pix) ((pix) & 0x1f)
|
|
#define ENCODE_PIXEL(e, pix) {encode(e, (pix) >> 8); encode(e, (pix) & 0xff);}
|
|
#define MIN_REF_ENCODE_SIZE 2
|
|
#define MAX_REF_ENCODE_SIZE 3
|
|
#define HASH_FUNC(v, p) { \
|
|
v = DJB2_START; \
|
|
DJB2_HASH(v, p[0] & (0x00ff)); \
|
|
DJB2_HASH(v, (p[0] >> 8) & (0x007f)); \
|
|
DJB2_HASH(v, p[1] & (0x00ff)); \
|
|
DJB2_HASH(v, (p[1] >> 8) & (0x007f)); \
|
|
DJB2_HASH(v, p[2] & (0x00ff)); \
|
|
DJB2_HASH(v, (p[2] >> 8) & (0x007f)); \
|
|
v &= HASH_MASK; \
|
|
}
|
|
#endif
|
|
|
|
#ifdef LZ_RGB24
|
|
#define PIXEL rgb24_pixel_t
|
|
#define FNAME(name) glz_rgb24_##name
|
|
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);}
|
|
#define MIN_REF_ENCODE_SIZE 2
|
|
#define MAX_REF_ENCODE_SIZE 2
|
|
#endif
|
|
|
|
#ifdef LZ_RGB32
|
|
#define PIXEL rgb32_pixel_t
|
|
#define FNAME(name) glz_rgb32_##name
|
|
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);}
|
|
#define MIN_REF_ENCODE_SIZE 2
|
|
#define MAX_REF_ENCODE_SIZE 2
|
|
#endif
|
|
|
|
|
|
#if defined(LZ_RGB24) || defined(LZ_RGB32)
|
|
#define GET_r(pix) ((pix).r)
|
|
#define GET_g(pix) ((pix).g)
|
|
#define GET_b(pix) ((pix).b)
|
|
#define HASH_FUNC(v, p) { \
|
|
v = DJB2_START; \
|
|
DJB2_HASH(v, p[0].r); \
|
|
DJB2_HASH(v, p[0].g); \
|
|
DJB2_HASH(v, p[0].b); \
|
|
DJB2_HASH(v, p[1].r); \
|
|
DJB2_HASH(v, p[1].g); \
|
|
DJB2_HASH(v, p[1].b); \
|
|
DJB2_HASH(v, p[2].r); \
|
|
DJB2_HASH(v, p[2].g); \
|
|
DJB2_HASH(v, p[2].b); \
|
|
v &= HASH_MASK; \
|
|
}
|
|
#endif
|
|
|
|
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
|
|
#define SAME_PIXEL(p1, p2) (GET_r(p1) == GET_r(p2) && GET_g(p1) == GET_g(p2) && \
|
|
GET_b(p1) == GET_b(p2))
|
|
|
|
#endif
|
|
|
|
#ifndef LZ_PLT
|
|
#define PIXEL_ID(pix_ptr, seg_ptr) \
|
|
((pix_ptr) - ((PIXEL *)(seg_ptr)->lines) + (seg_ptr)->pixels_so_far)
|
|
#define PIXEL_DIST(src_pix_ptr, src_seg_ptr, ref_pix_ptr, ref_seg_ptr) \
|
|
(PIXEL_ID(src_pix_ptr,src_seg_ptr) - PIXEL_ID(ref_pix_ptr, ref_seg_ptr))
|
|
#else
|
|
#define PIXEL_ID(pix_ptr, seg_ptr, pix_per_byte) \
|
|
(((pix_ptr) - ((PIXEL *)(seg_ptr)->lines)) * pix_per_byte + (seg_ptr)->pixels_so_far)
|
|
#define PIXEL_DIST(src_pix_ptr, src_seg_ptr, ref_pix_ptr, ref_seg_ptr, pix_per_byte) \
|
|
((PIXEL_ID(src_pix_ptr,src_seg_ptr, pix_per_byte) - \
|
|
PIXEL_ID(ref_pix_ptr, ref_seg_ptr, pix_per_byte)) / pix_per_byte)
|
|
#endif
|
|
|
|
/* returns the length of the match. 0 if no match.
|
|
if image_distance = 0, pixel_distance is the distance between the matching pixels.
|
|
Otherwise, it is the offset from the beginning of the referred image */
|
|
static INLINE size_t FNAME(do_match)(SharedDictionary *dict,
|
|
WindowImageSegment *ref_seg, const PIXEL *ref,
|
|
const PIXEL *ref_limit,
|
|
WindowImageSegment *ip_seg, const PIXEL *ip,
|
|
const PIXEL *ip_limit,
|
|
#ifdef LZ_PLT
|
|
int pix_per_byte,
|
|
#endif
|
|
size_t *o_image_dist, size_t *o_pix_distance)
|
|
{
|
|
int encode_size;
|
|
const PIXEL *tmp_ip = ip;
|
|
const PIXEL *tmp_ref = ref;
|
|
|
|
if (ref > (ref_limit - MIN_REF_ENCODE_SIZE)) {
|
|
return 0; // in case the hash entry is not relevant
|
|
}
|
|
|
|
|
|
/* min match length == MIN_REF_ENCODE_SIZE (depends on pixel type) */
|
|
|
|
if (!SAME_PIXEL(*tmp_ref, *tmp_ip)) {
|
|
return 0;
|
|
} else {
|
|
tmp_ref++;
|
|
tmp_ip++;
|
|
}
|
|
|
|
|
|
if (!SAME_PIXEL(*tmp_ref, *tmp_ip)) {
|
|
return 0;
|
|
} else {
|
|
tmp_ref++;
|
|
tmp_ip++;
|
|
}
|
|
|
|
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
|
|
if (!SAME_PIXEL(*tmp_ref, *tmp_ip)) {
|
|
return 0;
|
|
} else {
|
|
tmp_ref++;
|
|
tmp_ip++;
|
|
}
|
|
|
|
|
|
if (!SAME_PIXEL(*tmp_ref, *tmp_ip)) {
|
|
return 0;
|
|
} else {
|
|
tmp_ref++;
|
|
tmp_ip++;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
*o_image_dist = ip_seg->image->id - ref_seg->image->id;
|
|
|
|
if (!(*o_image_dist)) { // the ref is inside the same image - encode distance
|
|
#ifndef LZ_PLT
|
|
*o_pix_distance = PIXEL_DIST(ip, ip_seg, ref, ref_seg);
|
|
#else
|
|
// in bytes
|
|
*o_pix_distance = PIXEL_DIST(ip, ip_seg, ref, ref_seg, pix_per_byte);
|
|
#endif
|
|
} else { // the ref is at different image - encode offset from the image start
|
|
#ifndef LZ_PLT
|
|
*o_pix_distance = PIXEL_DIST(ref, ref_seg,
|
|
(PIXEL *)(dict->window.segs[ref_seg->image->first_seg].lines),
|
|
&dict->window.segs[ref_seg->image->first_seg]
|
|
);
|
|
#else
|
|
// in bytes
|
|
*o_pix_distance = PIXEL_DIST(ref, ref_seg,
|
|
(PIXEL *)(dict->window.segs[ref_seg->image->first_seg].lines),
|
|
&dict->window.segs[ref_seg->image->first_seg],
|
|
pix_per_byte);
|
|
#endif
|
|
}
|
|
|
|
if ((*o_pix_distance == 0) || (*o_pix_distance >= MAX_PIXEL_LONG_DISTANCE) ||
|
|
(*o_image_dist > MAX_IMAGE_DIST)) {
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* continue the match*/
|
|
while ((tmp_ip < ip_limit) && (tmp_ref < ref_limit)) {
|
|
if (!SAME_PIXEL(*tmp_ref, *tmp_ip)) {
|
|
break;
|
|
} else {
|
|
tmp_ref++;
|
|
tmp_ip++;
|
|
}
|
|
}
|
|
|
|
|
|
if ((tmp_ip - ip) > MAX_REF_ENCODE_SIZE) {
|
|
return (tmp_ip - ip);
|
|
}
|
|
|
|
encode_size = get_encode_ref_size(*o_image_dist, *o_pix_distance);
|
|
|
|
// min number of identical pixels for a match
|
|
#if defined(LZ_RGB16)
|
|
encode_size /= 2;
|
|
#elif defined(LZ_RGB24) || defined(LZ_RGB32)
|
|
encode_size /= 3;
|
|
#endif
|
|
|
|
encode_size++; // the minimum match
|
|
// match len is smaller than the encoding - not worth encoding
|
|
if ((tmp_ip - ip) < encode_size) {
|
|
return 0;
|
|
}
|
|
return (tmp_ip - ip);
|
|
}
|
|
|
|
/* compresses one segment starting from 'from'.
|
|
In order to encode a match, we use pixels resolution when we encode RGB image,
|
|
and bytes count when we encode PLT.
|
|
*/
|
|
static void FNAME(compress_seg)(Encoder *encoder, uint32_t seg_idx, PIXEL *from, int copied)
|
|
{
|
|
WindowImageSegment *seg = &encoder->dict->window.segs[seg_idx];
|
|
const PIXEL *ip = from;
|
|
const PIXEL *ip_bound = (PIXEL *)(seg->lines_end) - BOUND_OFFSET;
|
|
const PIXEL *ip_limit = (PIXEL *)(seg->lines_end) - LIMIT_OFFSET;
|
|
int hval;
|
|
int copy = copied;
|
|
#ifdef LZ_PLT
|
|
int pix_per_byte = PLT_PIXELS_PER_BYTE[encoder->cur_image.type];
|
|
#endif
|
|
|
|
#ifdef DEBUG_ENCODE
|
|
int n_encoded = 0;
|
|
#endif
|
|
|
|
if (copy == 0) {
|
|
encode_copy_count(encoder, MAX_COPY - 1);
|
|
}
|
|
|
|
|
|
while (LZ_EXPECT_CONDITIONAL(ip < ip_limit)) {
|
|
const PIXEL *ref;
|
|
const PIXEL *ref_limit;
|
|
WindowImageSegment *ref_seg;
|
|
uint32_t ref_seg_idx;
|
|
size_t pix_dist;
|
|
size_t image_dist;
|
|
/* minimum match length */
|
|
size_t len = 0;
|
|
|
|
/* comparison starting-point */
|
|
const PIXEL *anchor = ip;
|
|
#ifdef CHAINED_HASH
|
|
int hash_id = 0;
|
|
size_t best_len = 0;
|
|
size_t best_pix_dist = 0;
|
|
size_t best_image_dist = 0;
|
|
#endif
|
|
|
|
/* check for a run */
|
|
|
|
if (LZ_EXPECT_CONDITIONAL(ip > (PIXEL *)(seg->lines))) {
|
|
if (SAME_PIXEL(ip[-1], ip[0]) && SAME_PIXEL(ip[0], ip[1]) && SAME_PIXEL(ip[1], ip[2])) {
|
|
PIXEL x;
|
|
pix_dist = 1;
|
|
image_dist = 0;
|
|
|
|
ip += 3;
|
|
ref = anchor + 2;
|
|
ref_limit = (PIXEL *)(seg->lines_end);
|
|
len = 3;
|
|
|
|
x = *ref;
|
|
|
|
while (ip < ip_bound) { // TODO: maybe separate a run from the same seg or from
|
|
// different ones in order to spare ref < ref_limit
|
|
if (!SAME_PIXEL(*ip, x)) {
|
|
ip++;
|
|
break;
|
|
} else {
|
|
ip++;
|
|
len++;
|
|
}
|
|
}
|
|
|
|
goto match;
|
|
} // END RLE MATCH
|
|
}
|
|
|
|
/* find potential match */
|
|
HASH_FUNC(hval, ip);
|
|
|
|
#ifdef CHAINED_HASH
|
|
for (hash_id = 0; hash_id < HASH_CHAIN_SIZE; hash_id++) {
|
|
ref_seg_idx = encoder->dict->htab[hval][hash_id].image_seg_idx;
|
|
#else
|
|
ref_seg_idx = encoder->dict->htab[hval].image_seg_idx;
|
|
#endif
|
|
ref_seg = encoder->dict->window.segs + ref_seg_idx;
|
|
if (REF_SEG_IS_VALID(encoder->dict, encoder->id,
|
|
ref_seg, seg)) {
|
|
#ifdef CHAINED_HASH
|
|
ref = ((PIXEL *)ref_seg->lines) + encoder->dict->htab[hval][hash_id].ref_pix_idx;
|
|
#else
|
|
ref = ((PIXEL *)ref_seg->lines) + encoder->dict->htab[hval].ref_pix_idx;
|
|
#endif
|
|
ref_limit = (PIXEL *)ref_seg->lines_end;
|
|
|
|
len = FNAME(do_match)(encoder->dict, ref_seg, ref, ref_limit, seg, ip, ip_bound,
|
|
#ifdef LZ_PLT
|
|
pix_per_byte,
|
|
#endif
|
|
&image_dist, &pix_dist);
|
|
|
|
#ifdef CHAINED_HASH
|
|
// TODO. not compare len but rather len - encode_size
|
|
if (len > best_len) {
|
|
best_len = len;
|
|
best_pix_dist = pix_dist;
|
|
best_image_dist = image_dist;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef CHAINED_HASH
|
|
} // end chain loop
|
|
len = best_len;
|
|
pix_dist = best_pix_dist;
|
|
image_dist = best_image_dist;
|
|
#endif
|
|
|
|
/* update hash table */
|
|
UPDATE_HASH(encoder->dict, hval, seg_idx, anchor - ((PIXEL *)seg->lines));
|
|
|
|
if (!len) {
|
|
goto literal;
|
|
}
|
|
|
|
match: // RLE or dictionary (both are encoded by distance from ref (-1) and length)
|
|
#ifdef DEBUG_ENCODE
|
|
printf(", match(%d, %d, %d)", image_dist, pix_dist, len);
|
|
n_encoded += len;
|
|
#endif
|
|
|
|
/* distance is biased */
|
|
if (!image_dist) {
|
|
pix_dist--;
|
|
}
|
|
|
|
/* if we have copied something, adjust the copy count */
|
|
if (copy) {
|
|
/* copy is biased, '0' means 1 byte copy */
|
|
update_copy_count(encoder, copy - 1);
|
|
} else {
|
|
/* back, to overwrite the copy count */
|
|
compress_output_prev(encoder);
|
|
}
|
|
|
|
/* reset literal counter */
|
|
copy = 0;
|
|
|
|
/* length is biased, '1' means a match of 3 pixels for PLT and alpha*/
|
|
/* for RGB 16 1 means 2 */
|
|
/* for RGB24/32 1 means 1...*/
|
|
ip = anchor + len - 2;
|
|
|
|
#if defined(LZ_RGB16)
|
|
len--;
|
|
#elif defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
|
|
len -= 2;
|
|
#endif
|
|
GLZ_ASSERT(encoder->usr, len > 0);
|
|
encode_match(encoder, image_dist, pix_dist, len);
|
|
|
|
/* update the hash at match boundary */
|
|
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
|
|
if (ip > anchor) {
|
|
#endif
|
|
HASH_FUNC(hval, ip);
|
|
UPDATE_HASH(encoder->dict, hval, seg_idx, ip - ((PIXEL *)seg->lines));
|
|
ip++;
|
|
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
|
|
} else {ip++;
|
|
}
|
|
#endif
|
|
#if defined(LZ_RGB24) || defined(LZ_RGB32)
|
|
if (ip > anchor) {
|
|
#endif
|
|
HASH_FUNC(hval, ip);
|
|
UPDATE_HASH(encoder->dict, hval, seg_idx, ip - ((PIXEL *)seg->lines));
|
|
ip++;
|
|
#if defined(LZ_RGB24) || defined(LZ_RGB32)
|
|
} else {
|
|
ip++;
|
|
}
|
|
#endif
|
|
/* assuming literal copy */
|
|
encode_copy_count(encoder, MAX_COPY - 1);
|
|
continue;
|
|
|
|
literal:
|
|
#ifdef DEBUG_ENCODE
|
|
printf(", copy");
|
|
n_encoded++;
|
|
#endif
|
|
ENCODE_PIXEL(encoder, *anchor);
|
|
anchor++;
|
|
ip = anchor;
|
|
copy++;
|
|
|
|
if (LZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) {
|
|
copy = 0;
|
|
encode_copy_count(encoder, MAX_COPY - 1);
|
|
}
|
|
} // END LOOP (ip < ip_limit)
|
|
|
|
|
|
/* left-over as literal copy */
|
|
ip_bound++;
|
|
while (ip <= ip_bound) {
|
|
#ifdef DEBUG_ENCODE
|
|
printf(", copy");
|
|
n_encoded++;
|
|
#endif
|
|
ENCODE_PIXEL(encoder, *ip);
|
|
ip++;
|
|
copy++;
|
|
if (copy == MAX_COPY) {
|
|
copy = 0;
|
|
encode_copy_count(encoder, MAX_COPY - 1);
|
|
}
|
|
}
|
|
|
|
/* if we have copied something, adjust the copy length */
|
|
if (copy) {
|
|
update_copy_count(encoder, copy - 1);
|
|
} else {
|
|
compress_output_prev(encoder);
|
|
}
|
|
#ifdef DEBUG_ENCODE
|
|
printf("\ntotal encoded=%d\n", n_encoded);
|
|
#endif
|
|
}
|
|
|
|
|
|
/* If the file is very small, copies it.
|
|
copies the first two pixels of the first segment, and sends the segments
|
|
one by one to compress_seg.
|
|
the number of bytes compressed are stored inside encoder. */
|
|
static void FNAME(compress)(Encoder *encoder)
|
|
{
|
|
uint32_t seg_id = encoder->cur_image.first_win_seg;
|
|
PIXEL *ip;
|
|
SharedDictionary *dict = encoder->dict;
|
|
int hval;
|
|
|
|
// fetch the first image segment that is not too small
|
|
while ((seg_id != NULL_IMAGE_SEG_ID) &&
|
|
(dict->window.segs[seg_id].image->id == encoder->cur_image.id) &&
|
|
((((PIXEL *)dict->window.segs[seg_id].lines_end) -
|
|
((PIXEL *)dict->window.segs[seg_id].lines)) < 4)) {
|
|
// coping the segment
|
|
if (dict->window.segs[seg_id].lines != dict->window.segs[seg_id].lines_end) {
|
|
ip = (PIXEL *)dict->window.segs[seg_id].lines;
|
|
// Note: we assume MAX_COPY > 3
|
|
encode_copy_count(encoder, (uint8_t)(
|
|
(((PIXEL *)dict->window.segs[seg_id].lines_end) -
|
|
((PIXEL *)dict->window.segs[seg_id].lines)) - 1));
|
|
while (ip < (PIXEL *)dict->window.segs[seg_id].lines_end) {
|
|
ENCODE_PIXEL(encoder, *ip);
|
|
ip++;
|
|
}
|
|
}
|
|
seg_id = dict->window.segs[seg_id].next;
|
|
}
|
|
|
|
if ((seg_id == NULL_IMAGE_SEG_ID) ||
|
|
(dict->window.segs[seg_id].image->id != encoder->cur_image.id)) {
|
|
return;
|
|
}
|
|
|
|
ip = (PIXEL *)dict->window.segs[seg_id].lines;
|
|
|
|
|
|
encode_copy_count(encoder, MAX_COPY - 1);
|
|
|
|
HASH_FUNC(hval, ip);
|
|
UPDATE_HASH(encoder->dict, hval, seg_id, 0);
|
|
|
|
ENCODE_PIXEL(encoder, *ip);
|
|
ip++;
|
|
ENCODE_PIXEL(encoder, *ip);
|
|
ip++;
|
|
#ifdef DEBUG_ENCODE
|
|
printf("copy, copy");
|
|
#endif
|
|
// compressing the first segment
|
|
FNAME(compress_seg)(encoder, seg_id, ip, 2);
|
|
|
|
// compressing the next segments
|
|
for (seg_id = dict->window.segs[seg_id].next;
|
|
seg_id != NULL_IMAGE_SEG_ID && (
|
|
dict->window.segs[seg_id].image->id == encoder->cur_image.id);
|
|
seg_id = dict->window.segs[seg_id].next) {
|
|
FNAME(compress_seg)(encoder, seg_id, (PIXEL *)dict->window.segs[seg_id].lines, 0);
|
|
}
|
|
}
|
|
|
|
#undef FNAME
|
|
#undef PIXEL_ID
|
|
#undef PIXEL_DIST
|
|
#undef PIXEL
|
|
#undef ENCODE_PIXEL
|
|
#undef SAME_PIXEL
|
|
#undef HASH_FUNC
|
|
#undef GET_r
|
|
#undef GET_g
|
|
#undef GET_b
|
|
#undef GET_CODE
|
|
#undef LZ_PLT
|
|
#undef LZ_RGB_ALPHA
|
|
#undef LZ_RGB16
|
|
#undef LZ_RGB24
|
|
#undef LZ_RGB32
|
|
#undef MIN_REF_ENCODE_SIZE
|
|
#undef MAX_REF_ENCODE_SIZE
|
|
|