Blame libfreerdp/codec/include/bitmap.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * RLE Compressed Bitmap Stream
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2011 Jay Sorg <jay.sorg@gmail.com>
Packit 1fb8d4
 * Copyright 2016 Armin Novak <armin.novak@thincast.com>
Packit 1fb8d4
 * Copyright 2016 Thincast Technologies GmbH
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
/* do not compile the file directly */
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write a foreground/background image to a destination buffer.
Packit 1fb8d4
 */
Packit 1fb8d4
static INLINE BYTE* WRITEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, UINT32 rowDelta,
Packit 1fb8d4
                                   BYTE bitmask, PIXEL fgPel, INT32 cBits)
Packit 1fb8d4
{
Packit 1fb8d4
	PIXEL xorPixel;
Packit 1fb8d4
	BYTE mask = 0x01;
Packit 1fb8d4
Packit 1fb8d4
	if (cBits > 8)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	UNROLL(cBits,
Packit 1fb8d4
	{
Packit 1fb8d4
		UINT32 data;
Packit 1fb8d4
		DESTREADPIXEL(xorPixel, pbDest - rowDelta);
Packit 1fb8d4
Packit 1fb8d4
		if (bitmask & mask)
Packit 1fb8d4
			data = xorPixel ^ fgPel;
Packit 1fb8d4
		else
Packit 1fb8d4
			data = xorPixel;
Packit 1fb8d4
Packit 1fb8d4
		DESTWRITEPIXEL(pbDest, data);
Packit 1fb8d4
		DESTNEXTPIXEL(pbDest);
Packit 1fb8d4
		mask = mask << 1;
Packit 1fb8d4
	});
Packit 1fb8d4
	return pbDest;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Write a foreground/background image to a destination buffer
Packit 1fb8d4
 * for the first line of compressed data.
Packit 1fb8d4
 */
Packit 1fb8d4
static INLINE BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, BYTE bitmask,
Packit 1fb8d4
        PIXEL fgPel, UINT32 cBits)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE mask = 0x01;
Packit 1fb8d4
Packit 1fb8d4
	if (cBits > 8)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	UNROLL(cBits,
Packit 1fb8d4
	{
Packit 1fb8d4
		UINT32 data;
Packit 1fb8d4
Packit 1fb8d4
		if (bitmask & mask)
Packit 1fb8d4
			data = fgPel;
Packit 1fb8d4
		else
Packit 1fb8d4
			data =  BLACK_PIXEL;
Packit 1fb8d4
Packit 1fb8d4
		DESTWRITEPIXEL(pbDest, data);
Packit 1fb8d4
		DESTNEXTPIXEL(pbDest);
Packit 1fb8d4
		mask = mask << 1;
Packit 1fb8d4
	});
Packit 1fb8d4
	return pbDest;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Decompress an RLE compressed bitmap.
Packit 1fb8d4
 */
Packit 1fb8d4
static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer,
Packit 1fb8d4
                                 BYTE* pbDestBuffer,
Packit 1fb8d4
                                 UINT32 rowDelta, UINT32 width, UINT32 height)
Packit 1fb8d4
{
Packit 1fb8d4
	const BYTE* pbSrc = pbSrcBuffer;
Packit 1fb8d4
	const BYTE* pbEnd = pbSrcBuffer + cbSrcBuffer;
Packit 1fb8d4
	const BYTE* pbDestEnd = pbDestBuffer + rowDelta * height;
Packit 1fb8d4
	BYTE* pbDest = pbDestBuffer;
Packit 1fb8d4
	PIXEL temp;
Packit 1fb8d4
	PIXEL fgPel = WHITE_PIXEL;
Packit 1fb8d4
	BOOL fInsertFgPel = FALSE;
Packit 1fb8d4
	BOOL fFirstLine = TRUE;
Packit 1fb8d4
	BYTE bitmask;
Packit 1fb8d4
	PIXEL pixelA, pixelB;
Packit 1fb8d4
	UINT32 runLength;
Packit 1fb8d4
	UINT32 code;
Packit 1fb8d4
	UINT32 advance;
Packit 1fb8d4
	RLEEXTRA
Packit 1fb8d4
Packit 1fb8d4
	if ((rowDelta == 0) || (rowDelta < width))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!pbSrcBuffer || !pbDestBuffer)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	while (pbSrc < pbEnd)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* Watch out for the end of the first scanline. */
Packit 1fb8d4
		if (fFirstLine)
Packit 1fb8d4
		{
Packit 1fb8d4
			if ((UINT32)(pbDest - pbDestBuffer) >= rowDelta)
Packit 1fb8d4
			{
Packit 1fb8d4
				fFirstLine = FALSE;
Packit 1fb8d4
				fInsertFgPel = FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		/*
Packit 1fb8d4
		   Extract the compression order code ID from the compression
Packit 1fb8d4
		   order header.
Packit 1fb8d4
		*/
Packit 1fb8d4
		code = ExtractCodeId(*pbSrc);
Packit 1fb8d4
Packit 1fb8d4
		/* Handle Background Run Orders. */
Packit 1fb8d4
		if (code == REGULAR_BG_RUN || code == MEGA_MEGA_BG_RUN)
Packit 1fb8d4
		{
Packit 1fb8d4
			runLength = ExtractRunLength(code, pbSrc, &advance);
Packit 1fb8d4
			pbSrc = pbSrc + advance;
Packit 1fb8d4
Packit 1fb8d4
			if (fFirstLine)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (fInsertFgPel)
Packit 1fb8d4
				{
Packit 1fb8d4
					if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
Packit 1fb8d4
						return FALSE;
Packit 1fb8d4
Packit 1fb8d4
					DESTWRITEPIXEL(pbDest, fgPel);
Packit 1fb8d4
					DESTNEXTPIXEL(pbDest);
Packit 1fb8d4
					runLength = runLength - 1;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
Packit 1fb8d4
				UNROLL(runLength,
Packit 1fb8d4
				{
Packit 1fb8d4
					DESTWRITEPIXEL(pbDest, BLACK_PIXEL);
Packit 1fb8d4
					DESTNEXTPIXEL(pbDest);
Packit 1fb8d4
				});
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				if (fInsertFgPel)
Packit 1fb8d4
				{
Packit 1fb8d4
					DESTREADPIXEL(temp, pbDest - rowDelta);
Packit 1fb8d4
Packit 1fb8d4
					if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
Packit 1fb8d4
						return FALSE;
Packit 1fb8d4
Packit 1fb8d4
					DESTWRITEPIXEL(pbDest, temp ^ fgPel);
Packit 1fb8d4
					DESTNEXTPIXEL(pbDest);
Packit 1fb8d4
					runLength--;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
Packit 1fb8d4
				UNROLL(runLength,
Packit 1fb8d4
				{
Packit 1fb8d4
					DESTREADPIXEL(temp, pbDest - rowDelta);
Packit 1fb8d4
					DESTWRITEPIXEL(pbDest, temp);
Packit 1fb8d4
					DESTNEXTPIXEL(pbDest);
Packit 1fb8d4
				});
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			/* A follow-on background run order will need a foreground pel inserted. */
Packit 1fb8d4
			fInsertFgPel = TRUE;
Packit 1fb8d4
			continue;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		/* For any of the other run-types a follow-on background run
Packit 1fb8d4
			order does not need a foreground pel inserted. */
Packit 1fb8d4
		fInsertFgPel = FALSE;
Packit 1fb8d4
Packit 1fb8d4
		switch (code)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* Handle Foreground Run Orders. */
Packit 1fb8d4
			case REGULAR_FG_RUN:
Packit 1fb8d4
			case MEGA_MEGA_FG_RUN:
Packit 1fb8d4
			case LITE_SET_FG_FG_RUN:
Packit 1fb8d4
			case MEGA_MEGA_SET_FG_RUN:
Packit 1fb8d4
				runLength = ExtractRunLength(code, pbSrc, &advance);
Packit 1fb8d4
				pbSrc = pbSrc + advance;
Packit 1fb8d4
Packit 1fb8d4
				if (code == LITE_SET_FG_FG_RUN || code == MEGA_MEGA_SET_FG_RUN)
Packit 1fb8d4
				{
Packit 1fb8d4
					SRCREADPIXEL(fgPel, pbSrc);
Packit 1fb8d4
					SRCNEXTPIXEL(pbSrc);
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
Packit 1fb8d4
				if (fFirstLine)
Packit 1fb8d4
				{
Packit 1fb8d4
					UNROLL(runLength,
Packit 1fb8d4
					{
Packit 1fb8d4
						DESTWRITEPIXEL(pbDest, fgPel);
Packit 1fb8d4
						DESTNEXTPIXEL(pbDest);
Packit 1fb8d4
					});
Packit 1fb8d4
				}
Packit 1fb8d4
				else
Packit 1fb8d4
				{
Packit 1fb8d4
					UNROLL(runLength,
Packit 1fb8d4
					{
Packit 1fb8d4
						DESTREADPIXEL(temp, pbDest - rowDelta);
Packit 1fb8d4
						DESTWRITEPIXEL(pbDest, temp ^ fgPel);
Packit 1fb8d4
						DESTNEXTPIXEL(pbDest);
Packit 1fb8d4
					});
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			/* Handle Dithered Run Orders. */
Packit 1fb8d4
			case LITE_DITHERED_RUN:
Packit 1fb8d4
			case MEGA_MEGA_DITHERED_RUN:
Packit 1fb8d4
				runLength = ExtractRunLength(code, pbSrc, &advance);
Packit 1fb8d4
				pbSrc = pbSrc + advance;
Packit 1fb8d4
				SRCREADPIXEL(pixelA, pbSrc);
Packit 1fb8d4
				SRCNEXTPIXEL(pbSrc);
Packit 1fb8d4
				SRCREADPIXEL(pixelB, pbSrc);
Packit 1fb8d4
				SRCNEXTPIXEL(pbSrc);
Packit 1fb8d4
Packit 1fb8d4
				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength * 2))
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
Packit 1fb8d4
				UNROLL(runLength,
Packit 1fb8d4
				{
Packit 1fb8d4
					DESTWRITEPIXEL(pbDest, pixelA);
Packit 1fb8d4
					DESTNEXTPIXEL(pbDest);
Packit 1fb8d4
					DESTWRITEPIXEL(pbDest, pixelB);
Packit 1fb8d4
					DESTNEXTPIXEL(pbDest);
Packit 1fb8d4
				});
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			/* Handle Color Run Orders. */
Packit 1fb8d4
			case REGULAR_COLOR_RUN:
Packit 1fb8d4
			case MEGA_MEGA_COLOR_RUN:
Packit 1fb8d4
				runLength = ExtractRunLength(code, pbSrc, &advance);
Packit 1fb8d4
				pbSrc = pbSrc + advance;
Packit 1fb8d4
				SRCREADPIXEL(pixelA, pbSrc);
Packit 1fb8d4
				SRCNEXTPIXEL(pbSrc);
Packit 1fb8d4
Packit 1fb8d4
				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
Packit 1fb8d4
				UNROLL(runLength,
Packit 1fb8d4
				{
Packit 1fb8d4
					DESTWRITEPIXEL(pbDest, pixelA);
Packit 1fb8d4
					DESTNEXTPIXEL(pbDest);
Packit 1fb8d4
				});
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			/* Handle Foreground/Background Image Orders. */
Packit 1fb8d4
			case REGULAR_FGBG_IMAGE:
Packit 1fb8d4
			case MEGA_MEGA_FGBG_IMAGE:
Packit 1fb8d4
			case LITE_SET_FG_FGBG_IMAGE:
Packit 1fb8d4
			case MEGA_MEGA_SET_FGBG_IMAGE:
Packit 1fb8d4
				runLength = ExtractRunLength(code, pbSrc, &advance);
Packit 1fb8d4
				pbSrc = pbSrc + advance;
Packit 1fb8d4
Packit 1fb8d4
				if (code == LITE_SET_FG_FGBG_IMAGE || code == MEGA_MEGA_SET_FGBG_IMAGE)
Packit 1fb8d4
				{
Packit 1fb8d4
					SRCREADPIXEL(fgPel, pbSrc);
Packit 1fb8d4
					SRCNEXTPIXEL(pbSrc);
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (fFirstLine)
Packit 1fb8d4
				{
Packit 1fb8d4
					while (runLength > 8)
Packit 1fb8d4
					{
Packit 1fb8d4
						bitmask = *pbSrc;
Packit 1fb8d4
						pbSrc = pbSrc + 1;
Packit 1fb8d4
						pbDest = WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, 8);
Packit 1fb8d4
Packit 1fb8d4
						if (!pbDest)
Packit 1fb8d4
							return FALSE;
Packit 1fb8d4
Packit 1fb8d4
						runLength = runLength - 8;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
				else
Packit 1fb8d4
				{
Packit 1fb8d4
					while (runLength > 8)
Packit 1fb8d4
					{
Packit 1fb8d4
						bitmask = *pbSrc;
Packit 1fb8d4
						pbSrc = pbSrc + 1;
Packit 1fb8d4
						pbDest = WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, 8);
Packit 1fb8d4
Packit 1fb8d4
						if (!pbDest)
Packit 1fb8d4
							return FALSE;
Packit 1fb8d4
Packit 1fb8d4
						runLength = runLength - 8;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (runLength > 0)
Packit 1fb8d4
				{
Packit 1fb8d4
					bitmask = *pbSrc;
Packit 1fb8d4
					pbSrc = pbSrc + 1;
Packit 1fb8d4
Packit 1fb8d4
					if (fFirstLine)
Packit 1fb8d4
					{
Packit 1fb8d4
						pbDest = WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, runLength);
Packit 1fb8d4
					}
Packit 1fb8d4
					else
Packit 1fb8d4
					{
Packit 1fb8d4
						pbDest = WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, runLength);
Packit 1fb8d4
					}
Packit 1fb8d4
Packit 1fb8d4
					if (!pbDest)
Packit 1fb8d4
						return FALSE;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			/* Handle Color Image Orders. */
Packit 1fb8d4
			case REGULAR_COLOR_IMAGE:
Packit 1fb8d4
			case MEGA_MEGA_COLOR_IMAGE:
Packit 1fb8d4
				runLength = ExtractRunLength(code, pbSrc, &advance);
Packit 1fb8d4
				pbSrc = pbSrc + advance;
Packit 1c2678
Packit 1c2678
				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
Packit 1c2678
					return FALSE;
Packit 1c2678
Packit 1fb8d4
				UNROLL(runLength,
Packit 1fb8d4
				{
Packit 1fb8d4
					SRCREADPIXEL(temp, pbSrc);
Packit 1fb8d4
					SRCNEXTPIXEL(pbSrc);
Packit 1fb8d4
					DESTWRITEPIXEL(pbDest, temp);
Packit 1fb8d4
					DESTNEXTPIXEL(pbDest);
Packit 1fb8d4
				});
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			/* Handle Special Order 1. */
Packit 1fb8d4
			case SPECIAL_FGBG_1:
Packit 1fb8d4
				pbSrc = pbSrc + 1;
Packit 1fb8d4
Packit 1fb8d4
				if (fFirstLine)
Packit 1fb8d4
				{
Packit 1fb8d4
					pbDest = WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg1, fgPel, 8);
Packit 1fb8d4
				}
Packit 1fb8d4
				else
Packit 1fb8d4
				{
Packit 1fb8d4
					pbDest = WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg1, fgPel, 8);
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (!pbDest)
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			/* Handle Special Order 2. */
Packit 1fb8d4
			case SPECIAL_FGBG_2:
Packit 1fb8d4
				pbSrc = pbSrc + 1;
Packit 1fb8d4
Packit 1fb8d4
				if (fFirstLine)
Packit 1fb8d4
				{
Packit 1fb8d4
					pbDest = WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg2, fgPel, 8);
Packit 1fb8d4
				}
Packit 1fb8d4
				else
Packit 1fb8d4
				{
Packit 1fb8d4
					pbDest = WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg2, fgPel, 8);
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				if (!pbDest)
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			/* Handle White Order. */
Packit 1fb8d4
			case SPECIAL_WHITE:
Packit 1fb8d4
				pbSrc = pbSrc + 1;
Packit 1fb8d4
Packit 1fb8d4
				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
Packit 1fb8d4
				DESTWRITEPIXEL(pbDest, WHITE_PIXEL);
Packit 1fb8d4
				DESTNEXTPIXEL(pbDest);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			/* Handle Black Order. */
Packit 1fb8d4
			case SPECIAL_BLACK:
Packit 1fb8d4
				pbSrc = pbSrc + 1;
Packit 1fb8d4
Packit 1fb8d4
				if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
Packit 1fb8d4
				DESTWRITEPIXEL(pbDest, BLACK_PIXEL);
Packit 1fb8d4
				DESTNEXTPIXEL(pbDest);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			default:
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}