summaryrefslogtreecommitdiffstats
path: root/libfreerdp/codec/include/bitmap.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
commita9bcc81f821d7c66f623779fa5147e728eb3c388 (patch)
tree98676963bcdd537ae5908a067a8eb110b93486a6 /libfreerdp/codec/include/bitmap.c
parentInitial commit. (diff)
downloadfreerdp3-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.c449
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;
+}