2 * Image Library -- Basic image manipulation
4 * (c) 2006 Pavel Charvat <pchar@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU Lesser General Public License.
13 #include "lib/mempool.h"
14 #include "images/images.h"
15 #include "images/error.h"
16 #include "images/color.h"
21 flags_to_pixel_size(uns flags)
24 switch (flags & IMAGE_COLOR_SPACE)
26 case COLOR_SPACE_GRAYSCALE:
35 if (flags & IMAGE_ALPHA)
41 image_new(struct image_context *ctx, uns cols, uns rows, uns flags, struct mempool *pool)
43 DBG("image_new(cols=%u rows=%u flags=0x%x pool=%p)", cols, rows, flags, pool);
44 flags &= IMAGE_NEW_FLAGS;
45 if (unlikely(!image_dimensions_valid(cols, rows)))
47 IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_DIMENSIONS, "Invalid image dimensions (%ux%u)", cols, rows);
51 uns pixel_size, row_pixels_size, row_size, align;
52 pixel_size = flags_to_pixel_size(flags);
58 flags |= IMAGE_PIXELS_ALIGNED;
61 if (flags & IMAGE_PIXELS_ALIGNED)
67 if (flags & IMAGE_SSE_ALIGNED)
68 align = IMAGE_SSE_ALIGN_SIZE;
69 else if (flags & IMAGE_PIXELS_ALIGNED)
73 row_pixels_size = cols * pixel_size;
74 row_size = ALIGN(row_pixels_size, align);
75 u64 image_size_64 = (u64)row_size * rows;
76 u64 bytes_64 = image_size_64 + (sizeof(struct image) + IMAGE_SSE_ALIGN_SIZE - 1 + sizeof(uns));
77 if (unlikely(bytes_64 > image_max_bytes))
79 IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_DIMENSIONS, "Image does not fit in memory");
83 img = mp_alloc(pool, bytes_64);
86 img = xmalloc(bytes_64);
87 flags |= IMAGE_NEED_DESTROY;
89 bzero(img, sizeof(struct image));
90 byte *p = (byte *)img + sizeof(struct image);
91 img->pixels = ALIGN_PTR(p, IMAGE_SSE_ALIGN_SIZE);
93 img->pixel_size = pixel_size;
96 img->row_size = row_size;
97 img->row_pixels_size = row_pixels_size;
98 img->image_size = image_size_64;
99 DBG("img=%p flags=0x%x pixel_size=%u row_size=%u image_size=%u pixels=%p",
100 img, img->flags, img->pixel_size, img->row_size, img->image_size, img->pixels);
105 image_clone(struct image_context *ctx, struct image *src, uns flags, struct mempool *pool)
107 DBG("image_clone(src=%p flags=0x%x pool=%p)", src, src->flags, pool);
109 flags &= IMAGE_NEW_FLAGS & ~IMAGE_CHANNELS_FORMAT;
110 flags |= src->flags & IMAGE_CHANNELS_FORMAT;
111 if (!(img = image_new(ctx, src->cols, src->rows, flags, pool)))
115 if (src->pixel_size != img->pixel_size) /* conversion between aligned and unaligned RGB */
117 # define IMAGE_WALK_PREFIX(x) walk_##x
118 # define IMAGE_WALK_INLINE
119 # define IMAGE_WALK_IMAGE img
120 # define IMAGE_WALK_SEC_IMAGE src
121 # define IMAGE_WALK_DOUBLE
122 # 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)
123 # include "images/image-walk.h"
125 else if (src->row_size != img->row_size || ((img->flags | src->flags) & IMAGE_GAPS_PROTECTED))
127 byte *s = src->pixels;
128 byte *d = img->pixels;
129 for (uns row = src->rows; row--; )
131 memcpy(d, s, src->row_pixels_size);
137 memcpy(img->pixels, src->pixels, img->image_size);
143 image_destroy(struct image *img)
145 DBG("image_destroy(img=%p)", img);
146 if (img->flags & IMAGE_NEED_DESTROY)
151 image_clear(struct image_context *ctx UNUSED, struct image *img)
153 DBG("image_clear(img=%p)", img);
155 if (img->flags & IMAGE_GAPS_PROTECTED)
157 byte *p = img->pixels;
158 uns bytes = img->cols * img->pixel_size;
159 for (uns row = img->rows; row--; p += img->row_size)
163 bzero(img->pixels, img->image_size);
167 image_init_matrix(struct image_context *ctx, struct image *img, byte *pixels, uns cols, uns rows, uns row_size, uns flags)
169 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);
170 if (unlikely(!image_dimensions_valid(cols, rows)))
172 IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_DIMENSIONS, "Invalid image dimensions (%ux%u)", cols, rows);
175 img->pixels = pixels;
178 img->pixel_size = flags_to_pixel_size(flags);
179 img->row_size = row_size;
180 img->row_pixels_size = cols * img->pixel_size;
181 img->image_size = rows * row_size;
182 img->flags = flags & (IMAGE_NEW_FLAGS | IMAGE_GAPS_PROTECTED);
187 image_init_subimage(struct image_context *ctx UNUSED, struct image *img, struct image *src, uns left, uns top, uns cols, uns rows)
189 DBG("image_init_subimage(img=%p src=%p left=%u top=%u cols=%u rows=%u)", img, src, left, top, cols, rows);
190 ASSERT(left + cols <= src->cols && top + rows <= src->rows);
191 img->pixels = src->pixels + left * src->pixel_size + top * src->row_size;
194 img->pixel_size = src->pixel_size;
195 img->row_size = src->row_size;
196 img->row_pixels_size = cols * src->pixel_size;
197 img->image_size = src->row_size * rows;
198 img->flags = src->flags & IMAGE_NEW_FLAGS;
199 img->flags |= IMAGE_GAPS_PROTECTED;
204 color_space_to_name(uns cs)
206 return image_channels_format_to_name(cs);
210 image_channels_format_to_name(uns format)
214 case COLOR_SPACE_GRAYSCALE:
216 case COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA:
218 case COLOR_SPACE_RGB:
220 case COLOR_SPACE_RGB | IMAGE_ALPHA:
228 image_name_to_channels_format(byte *name)
230 if (!strcasecmp(name, "gray"))
231 return COLOR_SPACE_GRAYSCALE;
232 if (!strcasecmp(name, "grayscale"))
233 return COLOR_SPACE_GRAYSCALE;
234 if (!strcasecmp(name, "grayalpha"))
235 return COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA;
236 if (!strcasecmp(name, "grayscalealpha"))
237 return COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA;
238 if (!strcasecmp(name, "rgb"))
239 return COLOR_SPACE_RGB;
240 if (!strcasecmp(name, "rgbalpha"))
241 return COLOR_SPACE_RGB | IMAGE_ALPHA;
242 if (!strcasecmp(name, "rgba"))
243 return COLOR_SPACE_RGB | IMAGE_ALPHA;