123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
-
- #include "sys-defines.h"
- #include "extern.h"
- #include "i_rle.h"
- static void _block_out (rle_out *rle, unsigned char c);
- static void
- _write_block (rle_out *rle)
- {
- if (rle->ofile)
- {
- fputc (rle->oblen, rle->ofile);
- fwrite ((void *) &(rle->oblock[0]), 1, rle->oblen, rle->ofile);
- }
- #ifdef LIBPLOTTER
- else if (rle->outstream)
- {
- rle->outstream->put ((unsigned char)(rle->oblen));
- rle->outstream->write ((const char *)(&(rle->oblock[0])), rle->oblen);
- }
- #endif
- rle->oblen = 0;
- }
- static void
- _block_out (rle_out *rle, unsigned char c)
- {
- rle->oblock[(rle->oblen)++] = c;
- if (rle->oblen >= 255)
- _write_block (rle);
- }
- static void
- _block_flush (rle_out *rle)
- {
- if (rle->oblen > 0)
- _write_block (rle);
- }
- static void
- _output (rle_out *rle, int val)
- {
- rle->obuf |= val << rle->obits;
- rle->obits += rle->out_bits;
- while (rle->obits >= 8)
- {
- _block_out (rle, (unsigned char)(rle->obuf & 0xff));
- rle->obuf >>= 8;
- rle->obits -= 8;
- }
- }
- static void
- _output_flush (rle_out *rle)
- {
- if (rle->obits > 0)
- _block_out (rle, (unsigned char)(rle->obuf));
- _block_flush (rle);
- }
- static void
- _did_clear (rle_out *rle)
- {
- rle->out_bits = rle->out_bits_init;
- rle->out_bump = rle->out_bump_init;
- rle->out_clear = rle->out_clear_init;
- rle->out_count = 0;
- rle->rl_table_max = 0;
- rle->just_cleared = true;
- }
- static void
- _output_plain (rle_out *rle, int c)
- {
- rle->just_cleared = false;
- _output (rle, c);
- rle->out_count++;
- if (rle->out_count >= rle->out_bump)
- {
- rle->out_bits++;
- rle->out_bump += 1 << (rle->out_bits - 1);
- }
- if (rle->out_count >= rle->out_clear)
- {
- _output (rle, rle->code_clear);
- _did_clear (rle);
- }
- }
- static unsigned int
- _isqrt (unsigned int x)
- {
- unsigned int r;
- unsigned int v;
- if (x < 2)
- return x;
- for (v=x, r=1; v; v>>=2, r<<=1)
- ;
- for ( ; ; )
- {
- v = ((x / r) + r) / 2;
- if ((v == r) || (v == r+1))
- return r;
- r = v;
- }
- }
- static unsigned int
- _compute_triangle_count (unsigned int count, unsigned int nrepcodes)
- {
- unsigned int perrep, cost;
- cost = 0;
- perrep = (nrepcodes * (nrepcodes+1)) / 2;
- while (count >= perrep)
- {
- cost += nrepcodes;
- count -= perrep;
- }
- if (count > 0)
- {
- unsigned int n;
- n = _isqrt (count);
- while ((n*(n+1)) >= 2*count)
- n--;
- while ((n*(n+1)) < 2*count)
- n++;
- cost += n;
- }
- return cost;
- }
- static void
- _max_out_clear (rle_out *rle)
- {
- rle->out_clear = rle->max_ocodes;
- }
- static void
- _reset_out_clear (rle_out *rle)
- {
- rle->out_clear = rle->out_clear_init;
- if (rle->out_count >= rle->out_clear)
- {
- _output (rle, rle->code_clear);
- _did_clear (rle);
- }
- }
- static void
- _rl_flush_fromclear (rle_out *rle, int count)
- {
- int n;
- _max_out_clear (rle);
- rle->rl_table_pixel = rle->rl_pixel;
- n = 1;
- while (count > 0)
- {
- if (n == 1)
- {
- rle->rl_table_max = 1;
- _output_plain (rle, rle->rl_pixel);
- count--;
- }
- else if (count >= n)
- {
- rle->rl_table_max = n;
- _output_plain (rle, rle->rl_basecode + n - 2);
- count -= n;
- }
- else if (count == 1)
- {
- (rle->rl_table_max)++;
- _output_plain (rle, rle->rl_pixel);
- count = 0;
- }
- else
- {
- rle->rl_table_max++;
- _output_plain (rle, rle->rl_basecode+count-2);
- count = 0;
- }
- if (rle->out_count == 0)
- n = 1;
- else
- n++;
- }
- _reset_out_clear (rle);
- }
- static void
- _rl_flush_clearorrep (rle_out *rle, int count)
- {
- int withclr;
- withclr = 1 + _compute_triangle_count ((unsigned int)count,
- (unsigned int)(rle->max_ocodes));
- if (withclr < count)
- {
- _output (rle, rle->code_clear);
- _did_clear (rle);
- _rl_flush_fromclear (rle, count);
- }
- else
- for ( ; count>0; count--)
- _output_plain (rle, rle->rl_pixel);
- }
- static void
- _rl_flush_withtable (rle_out *rle, int count)
- {
- int repmax;
- int repleft;
- int leftover;
- repmax = count / rle->rl_table_max;
- leftover = count % rle->rl_table_max;
- repleft = (leftover ? 1 : 0);
- if (rle->out_count + repmax + repleft > rle->max_ocodes)
- {
- repmax = rle->max_ocodes - rle->out_count;
- leftover = count - (repmax * rle->rl_table_max);
- repleft = 1 + _compute_triangle_count ((unsigned int)leftover,
- (unsigned int)(rle->max_ocodes));
- }
- if (1 + _compute_triangle_count ((unsigned int)count,
- (unsigned int)(rle->max_ocodes))
- < repmax + repleft)
- {
- _output (rle, rle->code_clear);
- _did_clear (rle);
- _rl_flush_fromclear (rle, count);
- return;
- }
- _max_out_clear (rle);
- for ( ; repmax>0; repmax--)
- _output_plain (rle, rle->rl_basecode + rle->rl_table_max - 2);
- if (leftover)
- {
- if (rle->just_cleared)
- _rl_flush_fromclear (rle, leftover);
- else if (leftover == 1)
- _output_plain (rle, rle->rl_pixel);
- else
- _output_plain (rle, rle->rl_basecode + leftover - 2);
- }
- _reset_out_clear (rle);
- }
- static void
- _rl_flush (rle_out *rle)
- {
- if (rle->rl_count == 1)
- _output_plain (rle, rle->rl_pixel);
- else
- {
- if (rle->just_cleared)
- _rl_flush_fromclear (rle, rle->rl_count);
- else if ((rle->rl_table_max < 2)
- || (rle->rl_table_pixel != rle->rl_pixel))
- _rl_flush_clearorrep (rle, rle->rl_count);
- else
- _rl_flush_withtable (rle, rle->rl_count);
- }
- rle->rl_count = 0;
- }
- rle_out *
- #ifdef LIBPLOTTER
- _rle_init (FILE *fp, ostream *out, int bit_depth)
- #else
- _rle_init (FILE *fp, int bit_depth)
- #endif
- {
- int init_bits;
- rle_out *rle;
-
- init_bits = IMAX(bit_depth, 2) + 1;
- rle = (rle_out *)_pl_xmalloc(sizeof(rle_out));
- rle->ofile = fp;
- #ifdef LIBPLOTTER
- rle->outstream = out;
- #endif
- rle->obuf = 0;
- rle->obits = 0;
- rle->oblen = 0;
- rle->code_clear = 1 << (init_bits - 1);
- rle->code_eof = rle->code_clear + 1;
- rle->rl_basecode = rle->code_eof + 1;
- rle->out_bump_init = (1 << (init_bits - 1)) - 1;
-
-
-
- rle->out_clear_init = (init_bits <= 3) ? 9 : (rle->out_bump_init - 1);
- rle->out_bits_init = init_bits;
- rle->max_ocodes = (1 << GIFBITS) - ((1 << (rle->out_bits_init - 1)) + 3);
- _did_clear (rle);
- _output (rle, rle->code_clear);
- rle->rl_count = 0;
- return rle;
- }
- void
- _rle_do_pixel (rle_out *rle, int c)
- {
-
- if ((rle->rl_count > 0) && (c != rle->rl_pixel))
- _rl_flush (rle);
-
- if (rle->rl_pixel == c)
- rle->rl_count++;
-
- else
- {
- rle->rl_pixel = c;
- rle->rl_count = 1;
- }
- }
- void
- _rle_terminate (rle_out *rle)
- {
-
- if (rle->rl_count > 0)
- _rl_flush (rle);
- _output (rle, rle->code_eof);
- _output_flush (rle);
-
- free (rle);
- }
|