123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- #include "Imaging.h"
- #include <assert.h>
- #include <string.h>
- static int comparePixels(const UINT8* buf, int x, int bytesPerPixel)
- {
- buf += x * bytesPerPixel;
- return memcmp(buf, buf + bytesPerPixel, bytesPerPixel) == 0;
- }
- int
- ImagingTgaRleEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
- {
- UINT8* dst;
- int bytesPerPixel;
- if (state->state == 0) {
- if (state->ystep < 0) {
- state->ystep = -1;
- state->y = state->ysize - 1;
- } else
- state->ystep = 1;
- state->state = 1;
- }
- dst = buf;
- bytesPerPixel = (state->bits + 7) / 8;
- while (1) {
- int flushCount;
- /*
- * state->count is the numbers of bytes in the packet,
- * excluding the 1-byte descriptor.
- */
- if (state->count == 0) {
- UINT8* row;
- UINT8 descriptor;
- int startX;
- assert(state->x <= state->xsize);
- /* Make sure we have space for the descriptor. */
- if (bytes < 1)
- break;
- if (state->x == state->xsize) {
- state->x = 0;
- state->y += state->ystep;
- if (state->y < 0 || state->y >= state->ysize) {
- state->errcode = IMAGING_CODEC_END;
- break;
- }
- }
- if (state->x == 0)
- state->shuffle(
- state->buffer,
- (UINT8*)im->image[state->y + state->yoff]
- + state->xoff * im->pixelsize,
- state->xsize);
- row = state->buffer;
- /* Start with a raw packet for 1 px. */
- descriptor = 0;
- startX = state->x;
- state->count = bytesPerPixel;
- if (state->x + 1 < state->xsize) {
- int maxLookup;
- int isRaw;
- isRaw = !comparePixels(row, state->x, bytesPerPixel);
- ++state->x;
- /*
- * A packet can contain up to 128 pixels;
- * 2 are already behind (state->x points to
- * the second one).
- */
- maxLookup = state->x + 126;
- /* A packet must not span multiple rows. */
- if (maxLookup > state->xsize - 1)
- maxLookup = state->xsize - 1;
- if (isRaw) {
- while (state->x < maxLookup)
- if (!comparePixels(row, state->x, bytesPerPixel))
- ++state->x;
- else {
- /* Two identical pixels will go to RLE packet. */
- --state->x;
- break;
- }
- state->count += (state->x - startX) * bytesPerPixel;
- } else {
- descriptor |= 0x80;
- while (state->x < maxLookup)
- if (comparePixels(row, state->x, bytesPerPixel))
- ++state->x;
- else
- break;
- }
- }
- /*
- * state->x currently points to the last pixel to be
- * included in the packet. The pixel count in the
- * descriptor is 1 less than actual number of pixels in
- * the packet, that is, state->x == startX if we encode
- * only 1 pixel.
- */
- descriptor += state->x - startX;
- *dst++ = descriptor;
- --bytes;
- /* Advance to past-the-last encoded pixel. */
- ++state->x;
- }
- assert(bytes >= 0);
- assert(state->count > 0);
- assert(state->x > 0);
- assert(state->count <= state->x * bytesPerPixel);
- if (bytes == 0)
- break;
- flushCount = state->count;
- if (flushCount > bytes)
- flushCount = bytes;
- memcpy(
- dst,
- state->buffer + (state->x * bytesPerPixel - state->count),
- flushCount);
- dst += flushCount;
- bytes -= flushCount;
- state->count -= flushCount;
- }
- return dst - buf;
- }
|