2025-04-27 07:49:33 -04:00

188 lines
4.3 KiB
C

#include <windows.h>
#include "mandel.h"
#define ESCAPE 0
#define ESC_ENDLINE 0
#define ESC_ENDBITMAP 1
#define ESC_DELTA 2
#define ESC_RANDOM 3
#define RANDOM_COUNT(c) ((c)-(ESC_RANDOM-1))
#define COUNT_SIZE 256
#define MAXRUN (COUNT_SIZE-1)
#define MAXRND (RANDOM_COUNT(COUNT_SIZE)-1)
typedef unsigned char *HwMem;
typedef unsigned long HwMemSize;
#define HW_UNALIGNED UNALIGNED
static HwMem prle, rndcnt;
static unsigned char prev;
static HwMemSize repeat;
static void RleWrite(unsigned char cur)
{
if (repeat > 1)
{
/*
A single unique byte will be represented as ESCAPE, ESC_RANDOM,
<byte>. This can be more efficiently encoded as a run of 1 byte.
We can achieve this effect in two ways: intially encode single
bytes as runs and then change them to random if random bytes
come in a sequence. Alternately, when we start a run we
can check for an existing random and change it to a run.
The second version is implemented here
*/
if (rndcnt && RANDOM_COUNT(*rndcnt) == 1)
{
/* Change ESCAPE to a length one run */
*(rndcnt-1) = 1;
/* Move run byte into proper position */
*rndcnt = *(rndcnt+1);
prle--;
}
if (prev == 0 && repeat > MAXRUN)
{
while (repeat > 0)
{
unsigned short d;
*prle++ = ESCAPE;
*prle++ = ESC_DELTA;
d = (unsigned short)min(0xffff, repeat);
*((unsigned short HW_UNALIGNED *)prle)++ = d;
repeat -= d;
}
}
else
{
*prle++ = (unsigned char)repeat;
*prle++ = prev;
}
rndcnt = NULL;
repeat = 1;
}
else
{
if (rndcnt == NULL || RANDOM_COUNT(*rndcnt) >= MAXRND)
{
*prle++ = ESCAPE;
rndcnt = prle++;
*rndcnt = ESC_RANDOM-1;
}
(*rndcnt)++;
*prle++ = prev;
}
prev = cur;
}
HwMemSize HwuRle(HwMem src, HwMem dest, HwMemSize size, HwMemSize stride)
{
unsigned char cur;
HwMem f;
HwMemSize count;
f = src;
prle = dest;
prev = *f;
f += stride;
repeat = 1;
count = size-stride;
rndcnt = NULL;
while (count > 0)
{
cur = *f;
f += stride;
if (prev != cur || (repeat >= MAXRUN && prev != 0))
{
RleWrite(cur);
}
else
{
repeat++;
}
count -= stride;
}
RleWrite(cur);
*prle++ = ESCAPE;
*prle++ = ESC_ENDBITMAP;
return prle-dest;
}
#define ALPHA_SIGNATURE 0xa0a1a2a3
#define COMPRESS_NONE 0
#define COMPRESS_RLE 1
BOOL SaveA8(TCHAR *file, DWORD width, DWORD height,
RGBQUAD *rgb_pal, DWORD transp_index, void *data)
{
HANDLE fho;
DWORD *out_image, dw, dwWrite;
DWORD pixels, i;
HwMemSize msize;
RGBQUAD full_pal[256];
BOOL success = FALSE;
fho = CreateFile(file, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (fho == NULL || fho == INVALID_HANDLE_VALUE)
{
goto Fail;
}
pixels = width*height;
for (i = 0; i < 256; i++)
{
full_pal[i] = rgb_pal[i];
if (i == transp_index)
{
full_pal[i].rgbReserved = 0;
}
else
{
full_pal[i].rgbReserved = 0xff;
}
}
out_image = LocalAlloc(LMEM_FIXED, pixels);
if (out_image == NULL)
{
goto Fail_fho;
}
msize = HwuRle((HwMem)data, (HwMem)out_image, pixels, 1);
if (msize > (HwMemSize)pixels)
{
goto Fail_out_image;
}
dw = ALPHA_SIGNATURE;
WriteFile(fho, &dw, sizeof(dw), &dwWrite, NULL);
WriteFile(fho, &width, sizeof(DWORD), &dwWrite, NULL);
WriteFile(fho, &height, sizeof(DWORD), &dwWrite, NULL);
dw = 8;
WriteFile(fho, &dw, sizeof(dw), &dwWrite, NULL);
dw = COMPRESS_RLE;
WriteFile(fho, &dw, sizeof(dw), &dwWrite, NULL);
WriteFile(fho, &msize, sizeof(msize), &dwWrite, NULL);
WriteFile(fho, full_pal, 256*sizeof(RGBQUAD), &dwWrite, NULL);
WriteFile(fho, out_image, msize, &dwWrite, NULL);
success = TRUE;
Fail_out_image:
LocalFree(out_image);
Fail_fho:
CloseHandle(fho);
Fail:
return success;
}