|
- #include <assert.h>
- #include <math.h>
-
- #include <stdio.h> /**< printf */
- #include <string.h> /**< memset */
-
- #include "sww/color.h"
-
- #include "image.h"
-
- #define STB_IMAGE_IMPLEMENTATION
- #include "stb_image.h"
-
- #define STB_IMAGE_WRITE_IMPLEMENTATION
- #include "stb_image_write.h"
-
- static inline uint32_t CalculateStride(swwImage *o) {
- // NOTE(anjingyu): In fact, only bbp32 is supported now!
- uint32_t bits_per_pixel = o->channels * 8;
- return ((o->width * (bits_per_pixel / 8) + 3) & ~3);
- }
-
- swwImage *swwImage_Create(uint32_t width, uint32_t height, uint32_t channels) {
- assert(channels == 4);
- uint32_t num_bytes = 0;
- swwImage *o = NULL;
-
- o = (swwImage *)malloc(sizeof(swwImage));
- o->width = width;
- o->height = height;
- o->channels = channels;
- o->load_from_file = 0;
- o->stride = CalculateStride(o);
-
- num_bytes = width * o->stride;
- o->buffer = (uint8_t *)malloc(num_bytes);
- memset(o->buffer, 0, num_bytes);
- o->external = 0;
-
- return o;
- }
-
- void swwImage_Destroy(swwImage *o) {
- if (o != NULL) {
- if (o->load_from_file) {
- stbi_image_free(o->buffer);
- } else {
- if (!o->external) {
- free(o->buffer);
- }
- }
- }
-
- free(o);
- }
-
- swwImage *swwImage_Load(const char *filename) {
- int width, height, channels;
-
- swwImage *o = (swwImage *)malloc(sizeof(swwImage));
- o->buffer = (uint8_t *)stbi_load(filename, &width, &height, &channels, 4);
-
- if (o->buffer != NULL) {
- o->width = width;
- o->height = height;
- o->channels = 4;
- o->load_from_file = 1;
- o->stride = CalculateStride(o);
-
- if (channels != 4) {
- printf("[W] The channels of load file(%s) is %d\n", filename, channels);
- }
-
- return o;
- }
-
- free(o);
-
- return NULL;
- }
-
- int swwImage_Save(swwImage *o, const char *filename) {
- assert(o->channels == 4);
- return stbi_write_png(filename, o->width, o->height, o->channels, o->buffer,
- o->width * o->channels);
- }
-
- void swwImage_ClearWithByte(swwImage *o, uint8_t b) {
- int32_t width = o->width;
- int32_t height = o->height;
-
- memset(o->buffer, b, width * height * o->channels);
- }
-
- uint32_t swwImage_GetPixel(swwImage *o, uint32_t x, uint32_t y) {
- uint8_t *p = &o->buffer[4 * (o->width * y + x)];
- return Color_RGBA(p[2], p[1], p[0], p[3]);
- }
-
- void swwImage_SetPixel(swwImage *o, uint32_t x, uint32_t y, uint32_t color) {
- uint8_t *buf = o->buffer;
-
- uint32_t idx = 4 * (o->width * y + x);
- if (Color_HasAlpha(color)) { // do alpha-blend
- uint8_t *tp = buf + idx;
- color = Color_AlphaBlend(Color_RGBA(tp[2], tp[1], tp[0], tp[3]), color);
- }
-
- uint8_t *p = buf + idx;
- p[0] = (uint8_t)(color)&0xff;
- p[1] = (uint8_t)(color >> 8) & 0xff;
- p[2] = (uint8_t)(color >> 16) & 0xff;
- p[3] = (uint8_t)(color >> 24) & 0xff;
- }
-
- #define _SWAP(a, b) (((a) ^ (b)) && ((b) ^= (a) ^= (b), (a) ^= (b)))
-
- void swwImage_FlipH(swwImage *o) {
- uint32_t half_width = o->width / 2;
- uint32_t r, c;
-
- for (r = 0; r < o->height; ++r) {
- // NOTE(donkey): The buffer will be always aligned with 4 bytes
- uint32_t *line = (uint32_t *)o->buffer + (r * o->width);
- for (c = 0; c < half_width; ++c) {
- uint32_t flipped_c = o->width - 1 - c;
- _SWAP(line[c], line[flipped_c]);
- }
- }
- }
-
- void swwImage_FlipV(swwImage *o) {
- uint32_t half_height = o->height / 2;
- uint32_t r, c;
-
- for (r = 0; r < half_height; ++r) {
- // Exchange two line directly, because the stored line by line
- uint32_t *lh = (uint32_t *)o->buffer + (r * o->width);
- uint32_t *ll = (uint32_t *)o->buffer + ((o->height - 1 - r) * o->width);
- for (c = 0; c < o->width; ++c) {
- _SWAP(lh[c], ll[c]);
- }
- }
- }
- #undef _SWAP
-
- /*
- void swwImage_StretchBilerp(swwImage *o, int newWidth, int newHeight)
- {
- uint32_t *oldData = (uint32_t*)o->buffer;
- uint32_t *newData = (uint32_t*)malloc(4 * newWidth * newHeight);
-
- for(int v = 0; v < newHeight; v++)
- {
- for(int u = 0; u < newWidth; u++)
- {
- float fx = (float)(u * width) / newWidth;
- float fy = (float)(v * height) / newHeight;
- int x = (int)fx;
- int y = (int)fy;
- float dx = fx - x;
- float dy = fy - y;
-
- Color<float> c1 = oldData[(y + 0) * width + (x + 0)];
- Color<float> c2 = oldData[(y + 0) * width + (x + 1)];
- Color<float> c3 = oldData[(y + 1) * width + (x + 0)];
- Color<float> c4 = oldData[(y + 1) * width + (x + 1)];
-
- float d1 = (1 - dx) * (1 - dy);
- float d2 = dx * (1 - dy);
- float d3 = (1 - dx) * dy;
- float d4 = dx * dy;
-
- Color<byte> c = d1 * c1 + d2 * c2 + d3 * c3 + d4 * c4;
-
- newData[v * newWidth + u] = c;
- }
- }
-
- width = newWidth;
- height = newHeight;
-
- free(colorBuffer);
- colorBuffer = newData;
- }
- */
-
- void swwImage_RGBA2BGRA(swwImage *o) {
- assert(o && o->buffer);
-
- uint32_t i = 0;
- uint32_t len = o->width * o->height;
- uint32_t *dp = (uint32_t *)o->buffer;
-
- for (; i < len; ++i) {
- dp[i] = (dp[i] & 0xff00ff00) | ((dp[i] >> 16) & 0xff) |
- ((dp[i] << 16) & 0x00ff0000);
- }
- }
|