/* ***************************************************************************** * utils/picture.c -- libg1m picture utilities. * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey * * This file is part of libg1m. * libg1m is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3.0 of the License, * or (at your option) any later version. * * libg1m is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with libg1m; if not, see . * ************************************************************************** */ #include /* ************************************************************************** */ /* Constants */ /* ************************************************************************** */ /* The dual 2-bit format colors */ static uint32_t dual2b_colors[] = {0xFFFFFF, 0xAAAAAA, 0x777777, 0x000000}; /* prizm colors */ static const uint32_t prizm_colors[16] = { [g1m_color_black] = 0x000000, [g1m_color_blue] = 0x0000ff, [g1m_color_green] = 0x00ff00, [g1m_color_cyan] = 0x00ffff, [g1m_color_red] = 0xff0000, [g1m_color_magenta] = 0xff00ff, [g1m_color_yellow] = 0xffff00, [g1m_color_white] = 0xffffff, /* RESERVED */ }; /* ************************************************************************** */ /* Picture decoding */ /* ************************************************************************** */ /** * g1m_decode_picture: * Decode a picture. * * @arg pixels the pixels to fill. * @arg format the format to use. * @arg raw the raw bytes to decode from. * @arg width the width. * @arg height the height. * @return the error code (0 if ok). */ int g1m_decode_picture(uint32_t **pixels, g1m_pictureformat_t format, const unsigned char *raw, unsigned int width, unsigned int height) { int msk; const unsigned char *o, *g, *b, *r2; size_t off; switch (format) { case g1m_pictureformat_1bit: for (unsigned int y = 0; y < height; y++) { msk = 0x80; for (unsigned int x = 0; x < width; x++) { /* get pixel */ pixels[y][x] = (*raw & msk) ? 0x000000 : 0xFFFFFF; /* go to next */ raw += msk & 1; msk = (msk >> 1) | ((msk & 1) << 7); } if (width & 0x7) raw++; } break; case g1m_pictureformat_1bit_r: for (unsigned int y = 0; y < height; y++) { msk = 0x80; for (unsigned int x = 0; x < width; x++) { /* get pixel */ pixels[y][x] = (*raw & msk) ? 0xFFFFFF : 0x000000; /* go to next */ raw += msk & 1; msk = (msk >> 1) | ((msk & 1) << 7); } if (width & 0x7) raw++; } break; case g1m_pictureformat_4bit_mono: raw = &raw[(height * width / 2) * 2]; case g1m_pictureformat_1bit_packed: msk = 0x80; for (unsigned int y = 0; y < height; y++) for (unsigned int x = 0; x < width; x++) { /* get pixel */ pixels[y][x] = (*raw & msk) ? 0x000000 : 0xFFFFFF; /* go to next */ raw += msk & 1; msk = (msk >> 1) | ((msk & 1) << 7); } break; case g1m_pictureformat_1bit_packed_r: msk = 0x80; for (unsigned int y = 0; y < height; y++) for (unsigned int x = 0; x < width; x++) { /* get pixel */ pixels[y][x] = (*raw & msk) ? 0xFFFFFF : 0x000000; /* go to next */ raw += msk & 1; msk = (msk >> 1) | ((msk & 1) << 7); } break; case g1m_pictureformat_1bit_old: for (unsigned int bx = width - 8; bx != (unsigned int)-8; bx -= 8) for (unsigned int y = height - 1; y != (unsigned int)-1; y--) { msk = 0x80; for (unsigned int x = bx; x < bx + 8; x++) { /* get pixel */ pixels[y][x] = (*raw & msk) ? 0x000000 : 0xFFFFFF; /* go to next */ msk >>= 1; } /* go to next byte */ raw++; } break; case g1m_pictureformat_2bit_dual: msk = 0x80; r2 = &raw[height * width / 8]; for (unsigned int y = 0; y < height; y++) for (unsigned int x = 0; x < width; x++) { /* get pixel */ uint32_t val = (!!(*raw & msk) << 1) | !!(*r2 & msk); pixels[y][x] = dual2b_colors[val]; /* go to next */ raw += msk & 1; r2 += msk & 1; msk = (msk >> 1) | ((msk & 1) << 7); } break; case g1m_pictureformat_4bit_code: msk = 0xF0; for (unsigned int y = 0; y < height; y++) for (unsigned int x = 0; x < width; x++) { /* get pixel */ uint32_t px = *raw & msk; px = px | (px >> 4); pixels[y][x] = prizm_colors[px & 0x0F]; /* go to next */ raw += msk & 1; msk = ~msk & 0xFF; } break; case g1m_pictureformat_4bit_rgb: msk = 0xF0; for (unsigned int y = height - 1; y != (unsigned int)-1; y--) for (unsigned int x = width - 1; x != (unsigned int)-1; x--) { /* get pixel */ uint32_t val = *raw & msk; val |= val >> 4; uint32_t px = 0; if (px & 8) px |= 0xFF0000; if (px & 4) px |= 0x00FF00; if (px & 2) px |= 0x0000FF; pixels[y][x] = px; /* go to next */ raw += msk & 1; msk = ~msk & 0xFF; } break; case g1m_pictureformat_4bit_color:; off = height * width / 8; o = raw; g = &raw[off]; b = &raw[off * 2]; for (unsigned int bx = width - 8; bx != (unsigned int)-8; bx -= 8) for (unsigned int y = height - 1; y != (unsigned int)-1; y--) { msk = 0x80; for (unsigned int x = bx; x < bx + 8; x++) { /* get pixel */ if (*o & msk) pixels[y][x] = 0xFF8C00; /* orange */ else if (*g & msk) pixels[y][x] = 0x00FF00; /* green */ else if (*b & msk) pixels[y][x] = 0x0000FF; /* blue */ else pixels[y][x] = 0xFFFFFF; /* white */ /* go to next */ msk >>= 1; } /* go to next byte */ o++; g++; b++; } break; case g1m_pictureformat_16bit: for (unsigned int y = 0; y < height; y++) for (unsigned int x = 0; x < width; x++) { /* get pixel */ uint32_t one = raw[0], two = raw[1]; uint32_t px = (one >> 3) << (16 + 3); px |= (((one & 7) << 3) | (two >> 5)) << (8 + 2); px |= (two & 31) << 3; pixels[y][x] = px; /* go to next */ raw += 2; } break; default: /* unknown format! */ return (g1m_error_op); } /* everything went well :) */ return (0); } /* ************************************************************************** */ /* Picture encoding */ /* ************************************************************************** */ /** * g1m_encode_picture: * Encode the picture. * * @arg pixels the pixels to encode. * @arg format the format. * @arg raw the destination buffer. * @arg width the picture width. * @arg height the picture height. */ int g1m_encode_picture(const uint32_t **pixels, g1m_pictureformat_t format, unsigned char *raw, unsigned int width, unsigned int height) { int msk; switch (format) { case g1m_pictureformat_1bit: memset(raw, 0, g1m_picturesize_1bit(width, height)); for (unsigned int y = 0; y < height; y++) { msk = 0x80; for (unsigned int x = 0; x < width; x++) { /* get pixel */ if (!pixels[y][x]) *raw |= msk; /* go to next */ raw += msk & 1; msk = (msk >> 1) | ((msk & 1) << 7); } if (width & 0x7) raw++; } break; case g1m_pictureformat_1bit_r: memset(raw, 0, g1m_picturesize_1bit(width, height)); for (unsigned int y = 0; y < height; y++) { msk = 0x80; for (unsigned int x = 0; x < width; x++) { /* get pixel */ if (pixels[y][x]) *raw |= msk; /* go to next */ raw += msk & 1; msk = (msk >> 1) | ((msk & 1) << 7); } if (width & 0x7) raw++; } break; case g1m_pictureformat_1bit_packed: msk = 0x80; for (unsigned int y = 0; y < height; y++) for (unsigned int x = 0; x < width; x++) { /* set pixel */ if (pixels[y][x] & 0xFFFFFF) *raw = msk; /* go to next */ raw += msk & 1; msk = (msk >> 1) | ((msk & 1) << 7); } break; case g1m_pictureformat_4bit_code: msk = 0xF0; for (unsigned int y = 0; y < height; y++) for (unsigned int x = 0; x < width; x++) { /* set pixel */ uint32_t color = 0; color |= !!(0xFF0000 & pixels[y][x]) << 2; color |= !!(0x00FF00 & pixels[y][x]) << 1; color |= !!(0x0000FF & pixels[y][x]); *raw |= color << (msk & 4); /* go to next */ raw += msk & 1; msk = ~msk & 0xFF; } break; case g1m_pictureformat_16bit: for (unsigned int y = 0; y < height; y++) for (unsigned int x = 0; x < width; x++) { /* set pixel */ uint32_t r = (pixels[y][x] & (0x1F << 19)) >> 19; uint32_t g = (pixels[y][x] & (0x3F << 10)) >> 10; uint32_t b = (pixels[y][x] & (0x1F << 3)) >> 3; *raw++ = (r << 3) | (g >> 5); *raw++ = (g << 5) | b; } break; default: /* unknown format! */ return (g1m_error_op); } /* everything went well :) */ return (0); }