Pillow
158 строк · 4.3 Кб
1
2#include "Imaging.h"3
4#include <assert.h>5#include <string.h>6
7static int8comparePixels(const UINT8 *buf, int x, int bytesPerPixel) {9buf += x * bytesPerPixel;10return memcmp(buf, buf + bytesPerPixel, bytesPerPixel) == 0;11}
12
13int
14ImagingTgaRleEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {15UINT8 *dst;16int bytesPerPixel;17
18if (state->state == 0) {19if (state->ystep < 0) {20state->ystep = -1;21state->y = state->ysize - 1;22} else {23state->ystep = 1;24}25
26state->state = 1;27}28
29dst = buf;30bytesPerPixel = (state->bits + 7) / 8;31
32while (1) {33int flushCount;34
35/*36* state->count is the numbers of bytes in the packet,
37* excluding the 1-byte descriptor.
38*/
39if (state->count == 0) {40UINT8 *row;41UINT8 descriptor;42int startX;43
44assert(state->x <= state->xsize);45
46/* Make sure we have space for the descriptor. */47if (bytes < 1) {48break;49}50
51if (state->x == state->xsize) {52state->x = 0;53
54state->y += state->ystep;55if (state->y < 0 || state->y >= state->ysize) {56state->errcode = IMAGING_CODEC_END;57break;58}59}60
61if (state->x == 0) {62state->shuffle(63state->buffer,64(UINT8 *)im->image[state->y + state->yoff] +65state->xoff * im->pixelsize,66state->xsize67);68}69
70row = state->buffer;71
72/* Start with a raw packet for 1 px. */73descriptor = 0;74startX = state->x;75state->count = bytesPerPixel;76
77if (state->x + 1 < state->xsize) {78int maxLookup;79int isRaw;80
81isRaw = !comparePixels(row, state->x, bytesPerPixel);82++state->x;83
84/*85* A packet can contain up to 128 pixels;
86* 2 are already behind (state->x points to
87* the second one).
88*/
89maxLookup = state->x + 126;90/* A packet must not span multiple rows. */91if (maxLookup > state->xsize - 1) {92maxLookup = state->xsize - 1;93}94
95if (isRaw) {96while (state->x < maxLookup) {97if (!comparePixels(row, state->x, bytesPerPixel)) {98++state->x;99} else {100/* Two identical pixels will go to RLE packet. */101--state->x;102break;103}104}105
106state->count += (state->x - startX) * bytesPerPixel;107} else {108descriptor |= 0x80;109
110while (state->x < maxLookup) {111if (comparePixels(row, state->x, bytesPerPixel)) {112++state->x;113} else {114break;115}116}117}118}119
120/*121* state->x currently points to the last pixel to be
122* included in the packet. The pixel count in the
123* descriptor is 1 less than actual number of pixels in
124* the packet, that is, state->x == startX if we encode
125* only 1 pixel.
126*/
127descriptor += state->x - startX;128*dst++ = descriptor;129--bytes;130
131/* Advance to past-the-last encoded pixel. */132++state->x;133}134
135assert(bytes >= 0);136assert(state->count > 0);137assert(state->x > 0);138assert(state->count <= state->x * bytesPerPixel);139
140if (bytes == 0) {141break;142}143
144flushCount = state->count;145if (flushCount > bytes) {146flushCount = bytes;147}148
149memcpy(150dst, state->buffer + (state->x * bytesPerPixel - state->count), flushCount151);152dst += flushCount;153bytes -= flushCount;154
155state->count -= flushCount;156}157
158return dst - buf;159}
160