X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=images%2Fimage.c;h=8c0779bb9fbf38a3e4a24faebb043eedee1b8e75;hb=HEAD;hp=e04d839c573f86a4cbc05acc1343b4bb22d12b2b;hpb=35d602a8f8676b8988eca13086c63f2026c1b952;p=libucw.git diff --git a/images/image.c b/images/image.c index e04d839c..8c0779bb 100644 --- a/images/image.c +++ b/images/image.c @@ -9,63 +9,42 @@ #undef LOCAL_DEBUG -#include "lib/lib.h" -#include "lib/mempool.h" -#include "images/images.h" -#include - -#define MAX_IMAGE_BYTES (1 << 30) - -void -image_thread_init(struct image_thread *it) -{ - DBG("image_thread_init()"); - bzero(it, sizeof(*it)); - it->pool = mp_new(1024); -} +#include +#include +#include +#include +#include -void -image_thread_cleanup(struct image_thread *it) -{ - DBG("image_thread_cleanup()"); - mp_delete(it->pool); -} +#include -void -image_thread_err_format(struct image_thread *it, uns code, char *msg, ...) +static inline uint +flags_to_pixel_size(uint flags) { - va_list args; - va_start(args, msg); - it->err_code = code; - it->err_msg = mp_vprintf(it->pool, msg, args); - va_end(args); + uint pixel_size = color_space_channels[flags & IMAGE_COLOR_SPACE]; + if (flags & IMAGE_ALPHA) + pixel_size++; + return pixel_size; } struct image * -image_new(struct image_thread *it, uns cols, uns rows, uns flags, struct mempool *pool) +image_new(struct image_context *ctx, uint cols, uint rows, uint flags, struct mempool *pool) { DBG("image_new(cols=%u rows=%u flags=0x%x pool=%p)", cols, rows, flags, pool); - if (cols > IMAGE_MAX_SIZE || rows > IMAGE_MAX_SIZE) + flags &= IMAGE_NEW_FLAGS; + if (unlikely(!image_dimensions_valid(cols, rows))) { - image_thread_err(it, IMAGE_ERR_INVALID_DIMENSIONS, "Image dimension(s) too large"); + IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_DIMENSIONS, "Invalid image dimensions (%ux%u)", cols, rows); return NULL; } struct image *img; - uns pixel_size, row_size, image_size, align; - switch (flags & IMAGE_COLOR_SPACE) + uint channels, pixel_size, row_pixels_size, row_size, align; + pixel_size = channels = flags_to_pixel_size(flags); + if (!channels || channels > 4) { - case COLOR_SPACE_GRAYSCALE: - pixel_size = 1; - break; - case COLOR_SPACE_RGB: - pixel_size = 3; - break; - default: - ASSERT(0); + IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_PIXEL_FORMAT, "Invalid number of color channels (%u)", channels); + return NULL; } - if (flags & IMAGE_ALPHA) - pixel_size++; - switch (pixel_size) + switch (channels) { case 1: case 2: @@ -85,62 +64,68 @@ image_new(struct image_thread *it, uns cols, uns rows, uns flags, struct mempool align = pixel_size; else align = 1; - row_size = cols * pixel_size; - row_size = ALIGN(row_size, align); + row_pixels_size = cols * pixel_size; + row_size = ALIGN_TO(row_pixels_size, align); u64 image_size_64 = (u64)row_size * rows; - u64 bytes_64 = image_size_64 + (sizeof(struct image) + IMAGE_SSE_ALIGN_SIZE - 1 + sizeof(uns)); - if (bytes_64 > MAX_IMAGE_BYTES) + u64 bytes_64 = image_size_64 + (sizeof(struct image) + IMAGE_SSE_ALIGN_SIZE - 1 + sizeof(uint)); + if (unlikely(bytes_64 > image_max_bytes)) { - image_thread_err(it, IMAGE_ERR_INVALID_DIMENSIONS, "Image does not fit in memory"); + IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_DIMENSIONS, "Image does not fit in memory"); return NULL; } - if (!(image_size = image_size_64)) + if (pool) + img = mp_alloc(pool, bytes_64); + else { - image_thread_err(it, IMAGE_ERR_INVALID_DIMENSIONS, "Zero dimension(s)"); - return NULL; + img = xmalloc(bytes_64); + flags |= IMAGE_NEED_DESTROY; } - img = pool ? mp_alloc(pool, (uns)bytes_64) : xmalloc((uns)bytes_64); bzero(img, sizeof(struct image)); byte *p = (byte *)img + sizeof(struct image); img->pixels = ALIGN_PTR(p, IMAGE_SSE_ALIGN_SIZE); img->flags = flags; + img->channels = channels; img->pixel_size = pixel_size; img->cols = cols; img->rows = rows; img->row_size = row_size; - img->image_size = image_size; + img->row_pixels_size = row_pixels_size; + img->image_size = image_size_64; DBG("img=%p flags=0x%x pixel_size=%u row_size=%u image_size=%u pixels=%p", img, img->flags, img->pixel_size, img->row_size, img->image_size, img->pixels); return img; } struct image * -image_clone(struct image_thread *it, struct image *src, uns flags, struct mempool *pool) +image_clone(struct image_context *ctx, struct image *src, uint flags, struct mempool *pool) { DBG("image_clone(src=%p flags=0x%x pool=%p)", src, src->flags, pool); struct image *img; - flags &= ~IMAGE_CHANNELS_FORMAT; + flags &= IMAGE_NEW_FLAGS & ~IMAGE_CHANNELS_FORMAT; flags |= src->flags & IMAGE_CHANNELS_FORMAT; - if (!(img = image_new(it, src->cols, src->rows, flags, pool))) + if (!(img = image_new(ctx, src->cols, src->rows, flags, pool))) return NULL; + ASSERT(src->channels == img->channels); if (img->image_size) { - if (src->pixel_size != img->pixel_size) + if (src->pixel_size != img->pixel_size) /* conversion between aligned and unaligned RGB */ { - struct image *sec_img = src; + ASSERT(src->channels == 3); +# define IMAGE_WALK_PREFIX(x) walk_##x # define IMAGE_WALK_INLINE +# define IMAGE_WALK_IMAGE img +# define IMAGE_WALK_SEC_IMAGE src # define IMAGE_WALK_DOUBLE -# define IMAGE_WALK_DO_STEP do{ *(u32 *)pos = *(u32 *)sec_pos; }while(0) -# include "images/image-walk.h" +# define IMAGE_WALK_DO_STEP do{ walk_pos[0] = walk_sec_pos[0]; walk_pos[1] = walk_sec_pos[1]; walk_pos[2] = walk_sec_pos[2]; }while(0) +# include } - else if (src->row_size != img->row_size) + else if (src->row_size != img->row_size || ((img->flags | src->flags) & IMAGE_GAPS_PROTECTED)) { byte *s = src->pixels; byte *d = img->pixels; - uns bytes = src->cols * img->pixel_size; - for (uns row = src->rows; row--; ) + for (uint row = src->rows; row--; ) { - memcpy(d, s, bytes); + memcpy(d, s, src->row_pixels_size); d += img->row_size; s += src->row_size; } @@ -155,57 +140,88 @@ void image_destroy(struct image *img) { DBG("image_destroy(img=%p)", img); - xfree((byte *)img); + if (img->flags & IMAGE_NEED_DESTROY) + xfree(img); } void -image_clear(struct image_thread *it UNUSED, struct image *img) +image_clear(struct image_context *ctx UNUSED, struct image *img) { DBG("image_clear(img=%p)", img); if (img->image_size) - bzero(img->pixels, img->image_size); + if (img->flags & IMAGE_GAPS_PROTECTED) + { + byte *p = img->pixels; + uint bytes = img->cols * img->pixel_size; + for (uint row = img->rows; row--; p += img->row_size) + bzero(p, bytes); + } + else + bzero(img->pixels, img->image_size); } -byte * -color_space_to_name(enum color_space cs) +struct image * +image_init_matrix(struct image_context *ctx, struct image *img, byte *pixels, uint cols, uint rows, uint row_size, uint flags) { - return image_channels_format_to_name(cs); + DBG("image_init_matrix(img=%p pixels=%p cols=%u rows=%u row_size=%u flags=0x%x)", img, pixels, cols, rows, row_size, flags); + if (unlikely(!image_dimensions_valid(cols, rows))) + { + IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_DIMENSIONS, "Invalid image dimensions (%ux%u)", cols, rows); + return NULL; + } + img->pixels = pixels; + img->cols = cols; + img->rows = rows; + img->pixel_size = img->channels = flags_to_pixel_size(flags); + img->row_size = row_size; + img->row_pixels_size = cols * img->pixel_size; + img->image_size = rows * row_size; + img->flags = flags & (IMAGE_NEW_FLAGS | IMAGE_GAPS_PROTECTED); + return img; +} + +struct image * +image_init_subimage(struct image_context *ctx UNUSED, struct image *img, struct image *src, uint left, uint top, uint cols, uint rows) +{ + DBG("image_init_subimage(img=%p src=%p left=%u top=%u cols=%u rows=%u)", img, src, left, top, cols, rows); + ASSERT(left + cols <= src->cols && top + rows <= src->rows); + img->pixels = src->pixels + left * src->pixel_size + top * src->row_size; + img->cols = cols; + img->rows = rows; + img->pixel_size = img->channels = src->pixel_size; + img->row_size = src->row_size; + img->row_pixels_size = cols * src->pixel_size; + img->image_size = src->row_size * rows; + img->flags = src->flags & IMAGE_NEW_FLAGS; + img->flags |= IMAGE_GAPS_PROTECTED; + return img; } byte * -image_channels_format_to_name(uns format) +image_channels_format_to_name(uint format, byte *buf) { - switch (format) - { - case COLOR_SPACE_GRAYSCALE: - return "Gray"; - case COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA: - return "GrayAlpha"; - case COLOR_SPACE_RGB: - return "RGB"; - case COLOR_SPACE_RGB | IMAGE_ALPHA: - return "RGBAlpha"; - default: - return NULL; - } + byte *cs_name = color_space_id_to_name(format & IMAGE_COLOR_SPACE); + uint l = strlen(cs_name); + memcpy(buf, cs_name, l + 1); + if (format & IMAGE_ALPHA) + strcpy(buf + l, "+Alpha"); + return buf; } -uns +uint image_name_to_channels_format(byte *name) { - if (!strcasecmp(name, "gray")) - return COLOR_SPACE_GRAYSCALE; - if (!strcasecmp(name, "grayscale")) - return COLOR_SPACE_GRAYSCALE; - if (!strcasecmp(name, "grayalpha")) - return COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA; - if (!strcasecmp(name, "grayscalealpha")) - return COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA; - if (!strcasecmp(name, "rgb")) - return COLOR_SPACE_RGB; - if (!strcasecmp(name, "rgbalpha")) - return COLOR_SPACE_RGB + IMAGE_ALPHA; - if (!strcasecmp(name, "rgba")) - return COLOR_SPACE_RGB + IMAGE_ALPHA; + uint i; + if (i = color_space_name_to_id(name)) + return i; + uint l = strlen(name); + if (l > 6 && !strcasecmp(name + l - 5, "+alpha")) + { + byte buf[l + 1]; + memcpy(buf, name, l - 6); + buf[l - 6] = 0; + if (i = color_space_name_to_id(name)) + return i; + } return 0; }