diff options
Diffstat (limited to 'yuv2rgb.c')
-rw-r--r-- | yuv2rgb.c | 469 |
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; +} |