aboutsummaryrefslogtreecommitdiffstats
path: root/yuv2rgb.c
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2011-02-17 14:27:30 +0100
committerGerd Hoffmann <kraxel@redhat.com>2011-02-17 14:27:30 +0100
commit0c08f2609d818276427d1b99777aadeb406175b0 (patch)
treec83fa3bccc8575759c8327255a37b921a03aace0 /yuv2rgb.c
downloadlibpcd-1.0.1.tar.gz
import 1.0.1 release tarball1.0.1
Diffstat (limited to 'yuv2rgb.c')
-rw-r--r--yuv2rgb.c469
1 files changed, 469 insertions, 0 deletions
diff --git a/yuv2rgb.c b/yuv2rgb.c
new file mode 100644
index 0000000..bc36a64
--- /dev/null
+++ b/yuv2rgb.c
@@ -0,0 +1,469 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pcd.h"
+
+/* ------------------------------------------------------------------------ */
+
+#define RANGE 320
+
+#define RED_NUL 137
+#define BLUE_NUL 156
+
+#define LUN_MUL 360
+#define RED_MUL 512
+#define BLUE_MUL 512
+#define GREEN1_MUL (-RED_MUL/2)
+#define GREEN2_MUL (-BLUE_MUL/6)
+
+#define RED_ADD (-RED_NUL*RED_MUL)
+#define BLUE_ADD (-BLUE_NUL*BLUE_MUL)
+#define GREEN1_ADD (-RED_ADD/2)
+#define GREEN2_ADD (-BLUE_ADD/6)
+
+static int LUT_flag = 0;
+static uint_fast16_t LUT_gray_char[256];
+static uint_fast16_t LUT_gray_int[256];
+static uint_fast16_t LUT_red[256];
+static uint_fast16_t LUT_blue[256];
+static uint_fast16_t LUT_green1[256];
+static uint_fast16_t LUT_green2[256];
+
+int32_t LUT_range[256 + 2 * RANGE];
+
+uint32_t LUT_15_red[256];
+uint32_t LUT_15_green[256];
+uint32_t LUT_15_blue[256];
+
+uint32_t LUT_16_red[256];
+uint32_t LUT_16_green[256];
+uint32_t LUT_16_blue[256];
+
+uint32_t LUT_24_red[256];
+uint32_t LUT_24_green[256];
+uint32_t LUT_24_blue[256];
+
+/* ------------------------------------------------------------------------ */
+
+void
+pcd_get_LUT_init()
+{
+ register int i;
+
+ /* only once needed */
+ if (LUT_flag)
+ return;
+ LUT_flag = 1;
+
+ /* init Lookup tables */
+ for (i = 0; i < 256; i++) {
+ LUT_gray_int[i] = i * LUN_MUL >> 8;
+ LUT_red[i] = (RED_ADD + i * RED_MUL) >> 8;
+ LUT_blue[i] = (BLUE_ADD + i * BLUE_MUL) >> 8;
+ LUT_green1[i] = (GREEN1_ADD + i * GREEN1_MUL) >> 8;
+ LUT_green2[i] = (GREEN2_ADD + i * GREEN2_MUL) >> 8;
+ LUT_gray_char[i] = LUT_gray_int[i] > 255 ? 255 : LUT_gray_int[i];
+
+ LUT_15_red[i] = (i & 0xf8) << 7; /* bits -rrrrr-- -------- */
+ LUT_15_green[i] = (i & 0xf8) << 2; /* bits------gg ggg----- */
+ LUT_15_blue[i] = (i & 0xf8) >> 3; /* bits-------- ---bbbbb */
+
+ LUT_16_red[i] = (i & 0xf8) << 8; /* bits rrrrr--- -------- */
+ LUT_16_green[i] = (i & 0xfc) << 3; /* bits -----ggg ggg----- */
+ LUT_16_blue[i] = (i & 0xf8) >> 3; /* bits -------- ---bbbbb */
+
+ LUT_24_red[i] = i << 16; /* byte -r-- */
+ LUT_24_green[i] = i << 8; /* byte --g- */
+ LUT_24_blue[i] = i; /* byte ---b */
+ }
+ for (i = 0; i < RANGE; i++)
+ LUT_range[i] = 0;
+ for (; i < RANGE + 256; i++)
+ LUT_range[i] = i - RANGE;
+ for (; i < 2 * RANGE + 256; i++)
+ LUT_range[i] = 255;
+}
+
+void
+pcd_set_lookup(struct PCD_IMAGE *img, uint32_t *red,
+ uint32_t *green, uint32_t *blue)
+{
+ img->lut_red = red;
+ img->lut_green = green;
+ img->lut_blue = blue;
+}
+
+/* ------------------------------------------------------------------------ */
+
+#define GET_RED (LUT_range[RANGE + gray + \
+ LUT_red[red[x]]])
+#define GET_GREEN (LUT_range[RANGE + gray + \
+ LUT_green1[red[x]] + \
+ LUT_green2[blue[x]]])
+#define GET_BLUE (LUT_range[RANGE + gray + \
+ LUT_blue[blue[x]]])
+
+static int
+pcd_get_image_line_0(struct PCD_IMAGE *img, int y,
+ unsigned char *dest, int type, int scale)
+{
+ unsigned char red[3072];
+ unsigned char blue[3072];
+ int bytes, maxx;
+
+ switch (type) {
+ case PCD_TYPE_GRAY:
+ bytes = 1;
+ break;
+ case PCD_TYPE_RGB:
+ bytes = 3;
+ break;
+ case PCD_TYPE_BGR:
+ bytes = 3;
+ break;
+ case PCD_TYPE_LUT_SHORT:
+ bytes = 2;
+ break;
+ case PCD_TYPE_LUT_LONG:
+ bytes = 4;
+ break;
+ default:
+ fprintf(stderr, "Oops: invalid type (%i) for output format\n", type);
+ exit(1);
+ }
+
+ if (img->rot & 2) {
+ y = (img->height >> scale) - y - 1;
+ dest += ((img->width >> scale) - 1) * bytes;
+ bytes = -bytes;
+ }
+ if (type != PCD_TYPE_GRAY && !scale) {
+ register int x;
+ register unsigned char *src1, *src2;
+
+ maxx = (img->width >> 1) - 1;
+ if (y & 1) {
+ src1 = img->blue[y >> 1];
+ src2 = img->blue[(y + 1 == img->height ? y : y + 1) >> 1];
+ for (x = 0; x < maxx; x++) {
+ blue[x * 2] = (src1[x] + src2[x] + 1) >> 1;
+ blue[x * 2 + 1] = (src1[x] + src1[x + 1] + src2[x] + src2[x + 1] + 2) >> 2;
+ }
+ blue[x * 2 + 1] = blue[x * 2] = (src1[x] + src2[x] + 1) >> 1;
+
+ src1 = img->red[y >> 1];
+ src2 = img->red[(y + 1 == img->height ? y : y + 1) >> 1];
+ for (x = 0; x < maxx; x++) {
+ red[x * 2] = (src1[x] + src2[x] + 1) >> 1;
+ red[x * 2 + 1] = (src1[x] + src1[x + 1] + src2[x] + src2[x + 1] + 2) >> 2;
+ }
+ red[x * 2 + 1] = red[x * 2] = (src1[x] + src2[x] + 1) >> 1;
+ } else {
+ src1 = img->blue[y >> 1];
+ for (x = 0; x < maxx; x++) {
+ blue[x * 2] = src1[x];
+ blue[x * 2 + 1] = (src1[x] + src1[x + 1] + 1) >> 1;
+ }
+ blue[x * 2 + 1] = blue[x * 2] = src1[x];
+
+ src1 = img->red[y >> 1];
+ for (x = 0; x < maxx; x++) {
+ red[x * 2] = src1[x];
+ red[x * 2 + 1] = (src1[x] + src1[x + 1] + 1) >> 1;
+ }
+ red[x * 2 + 1] = red[x * 2] = src1[x];
+ }
+ }
+ if (type != PCD_TYPE_GRAY && scale) {
+ memcpy(blue, img->blue[y], img->width >> 1);
+ memcpy(red, img->red[y], img->width >> 1);
+ }
+ maxx = img->width >> scale;
+ switch (type) {
+ case PCD_TYPE_GRAY:
+ {
+ register int x;
+ register unsigned char *luma = img->luma[y << scale];
+
+ for (x = 0; x < maxx; x++, dest += bytes)
+ *dest = LUT_gray_char[luma[x << scale]];
+ }
+ break;
+ case PCD_TYPE_RGB:
+ {
+ register int x, gray;
+ register unsigned char *luma = img->luma[y << scale];
+
+ for (x = 0; x < maxx; x++, dest += bytes) {
+ gray = LUT_gray_int[luma[x << scale]];
+ dest[0] = GET_RED;
+ dest[1] = GET_GREEN;
+ dest[2] = GET_BLUE;
+ }
+ }
+ break;
+ case PCD_TYPE_BGR:
+ {
+ register int x, gray;
+ register unsigned char *luma = img->luma[y << scale];
+
+ for (x = 0; x < maxx; x++, dest += bytes) {
+ gray = LUT_gray_int[luma[x << scale]];
+ dest[0] = GET_BLUE;
+ dest[1] = GET_GREEN;
+ dest[2] = GET_RED;
+ }
+ }
+ break;
+ case PCD_TYPE_LUT_SHORT:
+ {
+ register int x, gray;
+ register unsigned char *luma = img->luma[y << scale];
+ uint32_t *lr = img->lut_red;
+ uint32_t *lg = img->lut_green;
+ uint32_t *lb = img->lut_blue;
+
+ for (x = 0; x < maxx; x++, dest += bytes) {
+ gray = LUT_gray_int[luma[x << scale]];
+ *((uint16_t *) dest) =
+ lr[GET_RED] | lg[GET_GREEN] | lb[GET_BLUE];
+ }
+ }
+ break;
+ case PCD_TYPE_LUT_LONG:
+ {
+ register int x, gray;
+ register unsigned char *luma = img->luma[y << scale];
+ uint32_t *lr = img->lut_red;
+ uint32_t *lg = img->lut_green;
+ uint32_t *lb = img->lut_blue;
+
+ for (x = 0; x < maxx; x++, dest += bytes) {
+ gray = LUT_gray_int[luma[x << scale]];
+ *((uint32_t *) dest) =
+ lr[GET_RED] | lg[GET_GREEN] | lb[GET_BLUE];
+ }
+ }
+ break;
+ default:
+ exit(1);
+ }
+ return 0;
+}
+
+static int
+pcd_get_image_line_90(struct PCD_IMAGE *img, int y,
+ unsigned char *dest, int type, int scale)
+{
+ unsigned char red[3072];
+ unsigned char blue[3072];
+ unsigned char **luma = img->luma;
+ int bytes, maxx, y1, y2;
+
+ switch (type) {
+ case PCD_TYPE_GRAY:
+ bytes = 1;
+ break;
+ case PCD_TYPE_RGB:
+ bytes = 3;
+ break;
+ case PCD_TYPE_BGR:
+ bytes = 3;
+ break;
+ case PCD_TYPE_LUT_SHORT:
+ bytes = 2;
+ break;
+ case PCD_TYPE_LUT_LONG:
+ bytes = 4;
+ break;
+ default:
+ fprintf(stderr, "Oops: invalid type (%i) for output format\n", type);
+ exit(1);
+ }
+
+ if (!(img->rot & 2)) {
+ y = (img->width >> scale) - y - 1;
+ } else {
+ dest += ((img->height >> scale) - 1) * bytes;
+ bytes = -bytes;
+ }
+
+ if (type != PCD_TYPE_GRAY && !scale) {
+ register int x;
+ register unsigned char **src;
+
+ y1 = y >> 1;
+ y2 = (y + 1 == img->width ? y : y + 1) >> 1;
+ maxx = (img->height >> 1) - 1;
+
+ if (y & 1) {
+ src = img->blue;
+ for (x = 0; x < maxx; x++) {
+ blue[x * 2] = (src[x][y1] + src[x][y2] + 1) >> 1;
+ blue[x * 2 + 1] = (src[x][y1] + src[x][y2] +
+ src[x + 1][y1] + src[x + 1][y2] + 2) >> 2;
+ }
+ blue[x * 2 + 1] = blue[x * 2] = (src[x][y1] + src[x][y2] + 1) >> 1;
+
+ src = img->red;
+ for (x = 0; x < maxx; x++) {
+ red[x * 2] = (src[x][y1] + src[x][y2] + 1) >> 1;
+ red[x * 2 + 1] = (src[x][y1] + src[x][y2] +
+ src[x + 1][y1] + src[x + 1][y2] + 2) >> 2;
+ }
+ red[x * 2 + 1] = red[x * 2] = (src[x][y1] + src[x][y2] + 1) >> 1;
+ } else {
+ src = img->blue;
+ for (x = 0; x < maxx; x++) {
+ blue[x * 2] = src[x][y1];
+ blue[x * 2 + 1] = (src[x][y1] + src[x + 1][y1] + 1) >> 1;
+ }
+ blue[x * 2 + 1] = blue[x * 2] = src[x][y1];
+
+ src = img->red;
+ for (x = 0; x < maxx; x++) {
+ red[x * 2] = src[x][y1];
+ red[x * 2 + 1] = (src[x][y1] + src[x + 1][y1] + 1) >> 1;
+ }
+ red[x * 2 + 1] = red[x * 2] = src[x][y1];
+ }
+ }
+ if (type != PCD_TYPE_GRAY && scale) {
+ register int x;
+ register unsigned char **src;
+
+ maxx = (img->height >> 1);
+
+ src = img->blue;
+ for (x = 0; x < maxx; x++)
+ blue[x] = src[x][y];
+
+ src = img->red;
+ for (x = 0; x < maxx; x++)
+ red[x] = src[x][y];
+ }
+ maxx = (img->height >> scale);
+ switch (type) {
+ case PCD_TYPE_GRAY:
+ {
+ register int x;
+
+ for (x = 0; x < maxx; x++, dest += bytes)
+ *dest = LUT_gray_char[luma[x << scale][y << scale]];
+ }
+ break;
+ case PCD_TYPE_RGB:
+ {
+ register int x, gray;
+
+ for (x = 0; x < maxx; x++, dest += bytes) {
+ gray = LUT_gray_int[luma[x << scale][y << scale]];
+ dest[0] = GET_RED;
+ dest[1] = GET_GREEN;
+ dest[2] = GET_BLUE;
+ }
+ }
+ break;
+ case PCD_TYPE_BGR:
+ {
+ register int x, gray;
+
+ for (x = 0; x < maxx; x++, dest += bytes) {
+ gray = LUT_gray_int[luma[x << scale][y << scale]];
+ dest[0] = GET_BLUE;
+ dest[1] = GET_GREEN;
+ dest[2] = GET_RED;
+ }
+ }
+ break;
+ case PCD_TYPE_LUT_SHORT:
+ {
+ register int x, gray;
+ uint32_t *lr = img->lut_red;
+ uint32_t *lg = img->lut_green;
+ uint32_t *lb = img->lut_blue;
+
+ for (x = 0; x < maxx; x++, dest += bytes) {
+ gray = LUT_gray_int[luma[x << scale][y << scale]];
+ *((uint16_t *) dest) =
+ lr[GET_RED] | lg[GET_GREEN] | lb[GET_BLUE];
+ }
+ }
+ break;
+ case PCD_TYPE_LUT_LONG:
+ {
+ register int x, gray;
+ uint32_t *lr = img->lut_red;
+ uint32_t *lg = img->lut_green;
+ uint32_t *lb = img->lut_blue;
+
+ for (x = 0; x < maxx; x++, dest += bytes) {
+ gray = LUT_gray_int[luma[x << scale][y << scale]];
+ *((uint32_t *) dest) =
+ lr[GET_RED] | lg[GET_GREEN] | lb[GET_BLUE];
+ }
+ }
+ break;
+ default:
+ exit(1);
+ }
+ return 0;
+}
+
+int
+pcd_get_image_line(struct PCD_IMAGE *img, int y,
+ unsigned char *dest, int type, int scale)
+{
+ if (img->res == 0) {
+ fprintf(stderr, "Oops: invalid res %i, have you called pcd_select()?\n",
+ img->res);
+ exit(1);
+ }
+ if (img->rot & 1)
+ return pcd_get_image_line_90(img, y, dest, type, scale);
+ else
+ return pcd_get_image_line_0(img, y, dest, type, scale);
+}
+
+int
+pcd_get_image(struct PCD_IMAGE *img, unsigned char *dest, int type, int scale)
+{
+ int y, maxx, maxy, bytes;
+
+ if (img->res == 0) {
+ fprintf(stderr, "Oops: invalid res %i, have you called pcd_select()?\n",
+ img->res);
+ exit(1);
+ }
+ switch (type) {
+ case PCD_TYPE_GRAY:
+ bytes = 1;
+ break;
+ case PCD_TYPE_RGB:
+ bytes = 3;
+ break;
+ case PCD_TYPE_BGR:
+ bytes = 3;
+ break;
+ case PCD_TYPE_LUT_SHORT:
+ bytes = 2;
+ break;
+ case PCD_TYPE_LUT_LONG:
+ bytes = 4;
+ break;
+ default:
+ fprintf(stderr, "Oops: invalid type (%i) for output format\n", type);
+ exit(1);
+ }
+ maxx = (img->rot & 1 ? img->height : img->width) >> scale;
+ maxy = (img->rot & 1 ? img->width : img->height) >> scale;
+
+ for (y = 0; y < maxy; y++, dest += bytes * maxx) {
+ ROTOR(y);
+ pcd_get_image_line(img, y, dest, type, scale);
+ }
+ TELL('*');
+
+ return 0;
+}