diff --git a/test-zrle.c b/test-zrle.c new file mode 100644 index 0000000..3c0214d --- /dev/null +++ b/test-zrle.c @@ -0,0 +1,168 @@ +#include "zrle.h" +#include "rfb-proto.h" + +#include +#include + +int test_pixel32_to_cpixel_3(void) +{ + static uint32_t src[64] = { 0 }; + static uint8_t dst[64 * 3] = { 0 }; + + struct rfb_pixel_format srcfmt = { 0 }, dstfmt = { 0 }; + + srcfmt.depth = 24; + srcfmt.bits_per_pixel = 32; + srcfmt.true_colour_flag = 1; + srcfmt.red_max = 255; + srcfmt.green_max = 255; + srcfmt.blue_max = 255; + srcfmt.red_shift = 24; + srcfmt.green_shift = 16; + srcfmt.blue_shift = 8; + + dstfmt.depth = 24; + dstfmt.bits_per_pixel = 32; + dstfmt.true_colour_flag = 1; + dstfmt.red_max = 255; + dstfmt.green_max = 255; + dstfmt.blue_max = 255; + dstfmt.red_shift = 8; + dstfmt.green_shift = 16; + dstfmt.blue_shift = 24; + + for (int i = 0; i < 64; ++i) + src[i] = 0x12345678; + + pixel32_to_cpixel(dst, &dstfmt, src, &srcfmt, 3, 64); + + for (int i = 0; i < 64; ++i) { + uint8_t r, g, b; + + r = dst[i * 3 + 0]; + g = dst[i * 3 + 1]; + b = dst[i * 3 + 2]; + + if (r != 0x12 || g != 0x34 || b != 0x56) { + printf("pixel32_to_cpixel_3 failed\n"); + return 1; + } + } + + printf("pixel32_to_cpixel_3 ran OK\n"); + return 0; +} + +int test_pixel32_to_cpixel_2(void) +{ + static uint32_t src[64] = { 0 }; + static uint16_t dst[64] = { 0 }; + + struct rfb_pixel_format srcfmt = { 0 }, dstfmt = { 0 }; + + srcfmt.depth = 24; + srcfmt.bits_per_pixel = 32; + srcfmt.true_colour_flag = 1; + srcfmt.red_max = 255; + srcfmt.green_max = 255; + srcfmt.blue_max = 255; + srcfmt.red_shift = 24; + srcfmt.green_shift = 16; + srcfmt.blue_shift = 8; + + dstfmt.depth = 16; + dstfmt.bits_per_pixel = 16; + dstfmt.true_colour_flag = 1; + dstfmt.red_max = 31; + dstfmt.green_max = 63; + dstfmt.blue_max = 31; + dstfmt.red_shift = 11; + dstfmt.green_shift = 5; + dstfmt.blue_shift = 0; + +#if __BYTE_ORDER__ == __BIG_ENDIAN__ + dstfmt.big_endian_flag = 1; +#endif + + for (int i = 0; i < 64; ++i) + src[i] = 0x12345678; + + pixel32_to_cpixel((uint8_t*)dst, &dstfmt, src, &srcfmt, 2, 64); + + for (int i = 0; i < 64; ++i) { + uint8_t r, g, b; + + r = (dst[i] >> 11) & 31; + g = (dst[i] >> 5) & 63; + b = (dst[i] >> 0) & 31; + + if (r != (0x12 >> 3) || g != (0x34 >> 2) || b != (0x56 >> 3)) { + printf("pixel32_to_cpixel_2 failed: %x %x %x\n", r, g, b); + return 1; + } + } + + printf("pixel32_to_cpixel_2 ran OK\n"); + return 0; +} + +int test_pixel32_to_cpixel_1(void) +{ + static uint32_t src[64] = { 0 }; + static uint8_t dst[64] = { 0 }; + + struct rfb_pixel_format srcfmt = { 0 }, dstfmt = { 0 }; + + srcfmt.depth = 24; + srcfmt.bits_per_pixel = 32; + srcfmt.true_colour_flag = 1; + srcfmt.red_max = 255; + srcfmt.green_max = 255; + srcfmt.blue_max = 255; + srcfmt.red_shift = 24; + srcfmt.green_shift = 16; + srcfmt.blue_shift = 8; + + dstfmt.depth = 8; + dstfmt.bits_per_pixel = 8; + dstfmt.true_colour_flag = 1; + dstfmt.red_max = 7; + dstfmt.green_max = 7; + dstfmt.blue_max = 3; + dstfmt.red_shift = 5; + dstfmt.green_shift = 2; + dstfmt.blue_shift = 0; + +#if __BYTE_ORDER__ == __BIG_ENDIAN__ + dstfmt.big_endian_flag = 1; +#endif + + for (int i = 0; i < 64; ++i) + src[i] = 0x98765432; + + pixel32_to_cpixel((uint8_t*)dst, &dstfmt, src, &srcfmt, 1, 64); + + for (int i = 0; i < 64; ++i) { + uint8_t r, g, b; + + r = (dst[i] >> 5) & 7; + g = (dst[i] >> 2) & 7; + b = (dst[i] >> 0) & 3; + + if (r != (0x98 >> 5) || g != (0x76 >> 5) || b != (0x54 >> 6)) { + printf("pixel32_to_cpixel_1 failed: %x %x %x\n", r, g, b); + return 1; + } + } + + printf("pixel32_to_cpixel_1 ran OK\n"); + return 0; +} +int main() +{ + if (test_pixel32_to_cpixel_3()) return 1; + if (test_pixel32_to_cpixel_2()) return 1; + if (test_pixel32_to_cpixel_1()) return 1; + + return 0; +} diff --git a/zrle.c b/zrle.c index 6d66fe6..8904abc 100644 --- a/zrle.c +++ b/zrle.c @@ -34,6 +34,9 @@ void pixel32_to_cpixel(uint8_t *restrict dst, const struct rfb_pixel_format* src_fmt, size_t bytes_per_cpixel, size_t len) { + assert(src_fmt->true_colour_flag); + assert(src_fmt->bits_per_pixel == 32); + assert(src_fmt->depth <= 32); assert(dst_fmt->true_colour_flag); assert(dst_fmt->bits_per_pixel <= 32); assert(dst_fmt->depth <= 24); @@ -79,6 +82,18 @@ void pixel32_to_cpixel(uint8_t *restrict dst, switch (bytes_per_cpixel) { case 3: + if (dst_fmt->bits_per_pixel == 32 && dst_fmt->depth <= 24) { + uint32_t min_dst_shift = dst_red_shift; + if (min_dst_shift > dst_green_shift) + min_dst_shift = dst_green_shift; + if (min_dst_shift > dst_blue_shift) + min_dst_shift = dst_blue_shift; + + dst_red_shift -= min_dst_shift; + dst_green_shift -= min_dst_shift; + dst_blue_shift -= min_dst_shift; + } + dst_endian_correction = dst_fmt->big_endian_flag ? 16 : 0; while (len--) { diff --git a/zrle.h b/zrle.h new file mode 100644 index 0000000..826db33 --- /dev/null +++ b/zrle.h @@ -0,0 +1,15 @@ +#ifndef _ZRLE_H_ +#define _ZRLE_H_ + +#include +#include + +struct rfb_pixel_format; + +void pixel32_to_cpixel(uint8_t *restrict dst, + const struct rfb_pixel_format* dst_fmt, + const uint32_t *restrict src, + const struct rfb_pixel_format* src_fmt, + size_t bytes_per_cpixel, size_t len); + +#endif /* _ZRLE_H_ */