diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:24:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:24:41 +0000 |
commit | a9bcc81f821d7c66f623779fa5147e728eb3c388 (patch) | |
tree | 98676963bcdd537ae5908a067a8eb110b93486a6 /libfreerdp/codec/include/bitmap.c | |
parent | Initial commit. (diff) | |
download | freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.tar.xz freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.zip |
Adding upstream version 3.3.0+dfsg1.upstream/3.3.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libfreerdp/codec/include/bitmap.c')
-rw-r--r-- | libfreerdp/codec/include/bitmap.c | 449 |
1 files changed, 449 insertions, 0 deletions
diff --git a/libfreerdp/codec/include/bitmap.c b/libfreerdp/codec/include/bitmap.c new file mode 100644 index 0000000..af83387 --- /dev/null +++ b/libfreerdp/codec/include/bitmap.c @@ -0,0 +1,449 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RLE Compressed Bitmap Stream + * + * Copyright 2011 Jay Sorg <jay.sorg@gmail.com> + * Copyright 2016 Armin Novak <armin.novak@thincast.com> + * Copyright 2016 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* do not compile the file directly */ + +/** + * Write a foreground/background image to a destination buffer. + */ +static INLINE BYTE* WRITEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, UINT32 rowDelta, + BYTE bitmask, PIXEL fgPel, INT32 cBits) +{ + PIXEL xorPixel; + BYTE mask = 0x01; + + if (cBits > 8) + { + WLog_ERR(TAG, "cBits %d > 8", cBits); + return NULL; + } + + if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits)) + return NULL; + + UNROLL(cBits, { + UINT32 data; + DESTREADPIXEL(xorPixel, pbDest - rowDelta); + + if (bitmask & mask) + data = xorPixel ^ fgPel; + else + data = xorPixel; + + DESTWRITEPIXEL(pbDest, data); + mask = mask << 1; + }); + return pbDest; +} + +/** + * Write a foreground/background image to a destination buffer + * for the first line of compressed data. + */ +static INLINE BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, BYTE bitmask, + PIXEL fgPel, UINT32 cBits) +{ + BYTE mask = 0x01; + + if (cBits > 8) + { + WLog_ERR(TAG, "cBits %d > 8", cBits); + return NULL; + } + + if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits)) + return NULL; + + UNROLL(cBits, { + UINT32 data; + + if (bitmask & mask) + data = fgPel; + else + data = BLACK_PIXEL; + + DESTWRITEPIXEL(pbDest, data); + mask = mask << 1; + }); + return pbDest; +} + +/** + * Decompress an RLE compressed bitmap. + */ +static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BYTE* pbDestBuffer, + UINT32 rowDelta, UINT32 width, UINT32 height) +{ +#if defined(WITH_DEBUG_CODECS) + char sbuffer[128] = { 0 }; +#endif + const BYTE* pbSrc = pbSrcBuffer; + const BYTE* pbEnd; + const BYTE* pbDestEnd; + BYTE* pbDest = pbDestBuffer; + PIXEL temp; + PIXEL fgPel = WHITE_PIXEL; + BOOL fInsertFgPel = FALSE; + BOOL fFirstLine = TRUE; + BYTE bitmask; + PIXEL pixelA, pixelB; + UINT32 runLength; + UINT32 code; + UINT32 advance = 0; + RLEEXTRA + + if ((rowDelta == 0) || (rowDelta < width)) + { + WLog_ERR(TAG, "Invalid arguments: rowDelta=%" PRIu32 " == 0 || < width=%" PRIu32, rowDelta, + width); + return FALSE; + } + + if (!pbSrcBuffer || !pbDestBuffer) + { + WLog_ERR(TAG, "Invalid arguments: pbSrcBuffer=%p, pbDestBuffer=%p", pbSrcBuffer, + pbDestBuffer); + return FALSE; + } + + pbEnd = pbSrcBuffer + cbSrcBuffer; + pbDestEnd = pbDestBuffer + rowDelta * height; + + while (pbSrc < pbEnd) + { + /* Watch out for the end of the first scanline. */ + if (fFirstLine) + { + if ((UINT32)(pbDest - pbDestBuffer) >= rowDelta) + { + fFirstLine = FALSE; + fInsertFgPel = FALSE; + } + } + + /* + Extract the compression order code ID from the compression + order header. + */ + code = ExtractCodeId(*pbSrc); + +#if defined(WITH_DEBUG_CODECS) + WLog_VRB(TAG, "pbSrc=%p code=%s, rem=%" PRIuz, pbSrc, + rle_code_str_buffer(code, sbuffer, sizeof(sbuffer)), pbEnd - pbSrc); +#endif + + /* Handle Background Run Orders. */ + if ((code == REGULAR_BG_RUN) || (code == MEGA_MEGA_BG_RUN)) + { + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; + pbSrc = pbSrc + advance; + + if (fFirstLine) + { + if (fInsertFgPel) + { + if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1)) + return FALSE; + + DESTWRITEPIXEL(pbDest, fgPel); + runLength = runLength - 1; + } + + if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength)) + return FALSE; + + UNROLL(runLength, { DESTWRITEPIXEL(pbDest, BLACK_PIXEL); }); + } + else + { + if (fInsertFgPel) + { + DESTREADPIXEL(temp, pbDest - rowDelta); + + if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1)) + return FALSE; + + DESTWRITEPIXEL(pbDest, temp ^ fgPel); + runLength--; + } + + if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength)) + return FALSE; + + UNROLL(runLength, { + DESTREADPIXEL(temp, pbDest - rowDelta); + DESTWRITEPIXEL(pbDest, temp); + }); + } + + /* A follow-on background run order will need a foreground pel inserted. */ + fInsertFgPel = TRUE; + continue; + } + + /* For any of the other run-types a follow-on background run + order does not need a foreground pel inserted. */ + fInsertFgPel = FALSE; + + switch (code) + { + /* Handle Foreground Run Orders. */ + case REGULAR_FG_RUN: + case MEGA_MEGA_FG_RUN: + case LITE_SET_FG_FG_RUN: + case MEGA_MEGA_SET_FG_RUN: + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; + pbSrc = pbSrc + advance; + + if (code == LITE_SET_FG_FG_RUN || code == MEGA_MEGA_SET_FG_RUN) + { + if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd)) + return FALSE; + SRCREADPIXEL(fgPel, pbSrc); + } + + if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength)) + return FALSE; + + if (fFirstLine) + { + UNROLL(runLength, { DESTWRITEPIXEL(pbDest, fgPel); }); + } + else + { + UNROLL(runLength, { + DESTREADPIXEL(temp, pbDest - rowDelta); + DESTWRITEPIXEL(pbDest, temp ^ fgPel); + }); + } + + break; + + /* Handle Dithered Run Orders. */ + case LITE_DITHERED_RUN: + case MEGA_MEGA_DITHERED_RUN: + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; + pbSrc = pbSrc + advance; + if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd)) + return FALSE; + SRCREADPIXEL(pixelA, pbSrc); + if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd)) + return FALSE; + SRCREADPIXEL(pixelB, pbSrc); + + if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength * 2)) + return FALSE; + + UNROLL(runLength, { + DESTWRITEPIXEL(pbDest, pixelA); + DESTWRITEPIXEL(pbDest, pixelB); + }); + break; + + /* Handle Color Run Orders. */ + case REGULAR_COLOR_RUN: + case MEGA_MEGA_COLOR_RUN: + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; + pbSrc = pbSrc + advance; + if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd)) + return FALSE; + SRCREADPIXEL(pixelA, pbSrc); + + if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength)) + return FALSE; + + UNROLL(runLength, { DESTWRITEPIXEL(pbDest, pixelA); }); + break; + + /* Handle Foreground/Background Image Orders. */ + case REGULAR_FGBG_IMAGE: + case MEGA_MEGA_FGBG_IMAGE: + case LITE_SET_FG_FGBG_IMAGE: + case MEGA_MEGA_SET_FGBG_IMAGE: + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; + pbSrc = pbSrc + advance; + + if (code == LITE_SET_FG_FGBG_IMAGE || code == MEGA_MEGA_SET_FGBG_IMAGE) + { + if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd)) + return FALSE; + SRCREADPIXEL(fgPel, pbSrc); + } + + if (!buffer_within_range(pbSrc, runLength / 8, pbEnd)) + return FALSE; + if (fFirstLine) + { + while (runLength > 8) + { + bitmask = *pbSrc; + pbSrc = pbSrc + 1; + pbDest = WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, 8); + + if (!pbDest) + return FALSE; + + runLength = runLength - 8; + } + } + else + { + while (runLength > 8) + { + bitmask = *pbSrc++; + + pbDest = WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, 8); + + if (!pbDest) + return FALSE; + + runLength = runLength - 8; + } + } + + if (runLength > 0) + { + if (!buffer_within_range(pbSrc, 1, pbEnd)) + return FALSE; + bitmask = *pbSrc++; + + if (fFirstLine) + { + pbDest = + WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, runLength); + } + else + { + pbDest = + WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, runLength); + } + + if (!pbDest) + return FALSE; + } + + break; + + /* Handle Color Image Orders. */ + case REGULAR_COLOR_IMAGE: + case MEGA_MEGA_COLOR_IMAGE: + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; + pbSrc = pbSrc + advance; + if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength)) + return FALSE; + if (!ENSURE_CAPACITY(pbSrc, pbEnd, runLength)) + return FALSE; + + UNROLL(runLength, { + SRCREADPIXEL(temp, pbSrc); + DESTWRITEPIXEL(pbDest, temp); + }); + break; + + /* Handle Special Order 1. */ + case SPECIAL_FGBG_1: + if (!buffer_within_range(pbSrc, 1, pbEnd)) + return FALSE; + pbSrc = pbSrc + 1; + + if (fFirstLine) + { + pbDest = + WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg1, fgPel, 8); + } + else + { + pbDest = + WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg1, fgPel, 8); + } + + if (!pbDest) + return FALSE; + + break; + + /* Handle Special Order 2. */ + case SPECIAL_FGBG_2: + if (!buffer_within_range(pbSrc, 1, pbEnd)) + return FALSE; + pbSrc = pbSrc + 1; + + if (fFirstLine) + { + pbDest = + WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg2, fgPel, 8); + } + else + { + pbDest = + WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg2, fgPel, 8); + } + + if (!pbDest) + return FALSE; + + break; + + /* Handle White Order. */ + case SPECIAL_WHITE: + if (!buffer_within_range(pbSrc, 1, pbEnd)) + return FALSE; + pbSrc = pbSrc + 1; + + if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1)) + return FALSE; + + DESTWRITEPIXEL(pbDest, WHITE_PIXEL); + break; + + /* Handle Black Order. */ + case SPECIAL_BLACK: + if (!buffer_within_range(pbSrc, 1, pbEnd)) + return FALSE; + pbSrc = pbSrc + 1; + + if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1)) + return FALSE; + + DESTWRITEPIXEL(pbDest, BLACK_PIXEL); + break; + + default: + WLog_ERR(TAG, "invalid code 0x%08" PRIx32 ", pbSrcBuffer=%p, pbSrc=%p, pbEnd=%p", + code, pbSrcBuffer, pbSrc, pbEnd); + return FALSE; + } + } + + return TRUE; +} |