#undef LOCAL_DEBUG
-#include "lib/lib.h"
-#include "lib/mempool.h"
-#include "images/images.h"
-#include <string.h>
-
-#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 <ucw/lib.h>
+#include <ucw/mempool.h>
+#include <images/images.h>
+#include <images/error.h>
+#include <images/color.h>
-void
-image_thread_cleanup(struct image_thread *it)
-{
- DBG("image_thread_cleanup()");
- mp_delete(it->pool);
-}
+#include <string.h>
-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:
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) /* conversion between aligned and unaligned RGB */
{
+ 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{ walk_pos[0] = walk_sec_pos[0]; walk_pos[1] = walk_sec_pos[1]; walk_pos[2] = walk_sec_pos[2]; }while(0)
-# include "images/image-walk.h"
+# include <images/image-walk.h>
}
- 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;
}
image_destroy(struct image *img)
{
DBG("image_destroy(img=%p)", img);
- xfree(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;
}