]> mj.ucw.cz Git - libucw.git/blob - images/image.c
Debian: A separate package for (most) Perl modules
[libucw.git] / images / image.c
1 /*
2  *      Image Library -- Basic image manipulation
3  *
4  *      (c) 2006 Pavel Charvat <pchar@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #undef LOCAL_DEBUG
11
12 #include <ucw/lib.h>
13 #include <ucw/mempool.h>
14 #include <images/images.h>
15 #include <images/error.h>
16 #include <images/color.h>
17
18 #include <string.h>
19
20 static inline uint
21 flags_to_pixel_size(uint flags)
22 {
23   uint pixel_size = color_space_channels[flags & IMAGE_COLOR_SPACE];
24   if (flags & IMAGE_ALPHA)
25     pixel_size++;
26   return pixel_size;
27 }
28
29 struct image *
30 image_new(struct image_context *ctx, uint cols, uint rows, uint flags, struct mempool *pool)
31 {
32   DBG("image_new(cols=%u rows=%u flags=0x%x pool=%p)", cols, rows, flags, pool);
33   flags &= IMAGE_NEW_FLAGS;
34   if (unlikely(!image_dimensions_valid(cols, rows)))
35     {
36       IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_DIMENSIONS, "Invalid image dimensions (%ux%u)", cols, rows);
37       return NULL;
38     }
39   struct image *img;
40   uint channels, pixel_size, row_pixels_size, row_size, align;
41   pixel_size = channels = flags_to_pixel_size(flags);
42   if (!channels || channels > 4)
43     {
44       IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_PIXEL_FORMAT, "Invalid number of color channels (%u)", channels);
45       return NULL;
46     }
47   switch (channels)
48     {
49       case 1:
50       case 2:
51       case 4:
52         flags |= IMAGE_PIXELS_ALIGNED;
53         break;
54       case 3:
55         if (flags & IMAGE_PIXELS_ALIGNED)
56           pixel_size = 4;
57         break;
58       default:
59         ASSERT(0);
60     }
61   if (flags & IMAGE_SSE_ALIGNED)
62     align = IMAGE_SSE_ALIGN_SIZE;
63   else if (flags & IMAGE_PIXELS_ALIGNED)
64     align = pixel_size;
65   else
66     align = 1;
67   row_pixels_size = cols * pixel_size;
68   row_size = ALIGN_TO(row_pixels_size, align);
69   u64 image_size_64 = (u64)row_size * rows;
70   u64 bytes_64 = image_size_64 + (sizeof(struct image) + IMAGE_SSE_ALIGN_SIZE - 1 + sizeof(uint));
71   if (unlikely(bytes_64 > image_max_bytes))
72     {
73       IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_DIMENSIONS, "Image does not fit in memory");
74       return NULL;
75     }
76   if (pool)
77     img = mp_alloc(pool, bytes_64);
78   else
79     {
80       img = xmalloc(bytes_64);
81       flags |= IMAGE_NEED_DESTROY;
82     }
83   bzero(img, sizeof(struct image));
84   byte *p = (byte *)img + sizeof(struct image);
85   img->pixels = ALIGN_PTR(p, IMAGE_SSE_ALIGN_SIZE);
86   img->flags = flags;
87   img->channels = channels;
88   img->pixel_size = pixel_size;
89   img->cols = cols;
90   img->rows = rows;
91   img->row_size = row_size;
92   img->row_pixels_size = row_pixels_size;
93   img->image_size = image_size_64;
94   DBG("img=%p flags=0x%x pixel_size=%u row_size=%u image_size=%u pixels=%p",
95     img, img->flags, img->pixel_size, img->row_size, img->image_size, img->pixels);
96   return img;
97 }
98
99 struct image *
100 image_clone(struct image_context *ctx, struct image *src, uint flags, struct mempool *pool)
101 {
102   DBG("image_clone(src=%p flags=0x%x pool=%p)", src, src->flags, pool);
103   struct image *img;
104   flags &= IMAGE_NEW_FLAGS & ~IMAGE_CHANNELS_FORMAT;
105   flags |= src->flags & IMAGE_CHANNELS_FORMAT;
106   if (!(img = image_new(ctx, src->cols, src->rows, flags, pool)))
107     return NULL;
108   ASSERT(src->channels == img->channels);
109   if (img->image_size)
110     {
111       if (src->pixel_size != img->pixel_size) /* conversion between aligned and unaligned RGB */
112         {
113           ASSERT(src->channels == 3);
114 #         define IMAGE_WALK_PREFIX(x) walk_##x
115 #         define IMAGE_WALK_INLINE
116 #         define IMAGE_WALK_IMAGE img
117 #         define IMAGE_WALK_SEC_IMAGE src
118 #         define IMAGE_WALK_DOUBLE
119 #         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)
120 #         include <images/image-walk.h>
121         }
122       else if (src->row_size != img->row_size || ((img->flags | src->flags) & IMAGE_GAPS_PROTECTED))
123         {
124           byte *s = src->pixels;
125           byte *d = img->pixels;
126           for (uint row = src->rows; row--; )
127             {
128               memcpy(d, s, src->row_pixels_size);
129               d += img->row_size;
130               s += src->row_size;
131             }
132         }
133       else
134         memcpy(img->pixels, src->pixels, img->image_size);
135     }
136   return img;
137 }
138
139 void
140 image_destroy(struct image *img)
141 {
142   DBG("image_destroy(img=%p)", img);
143   if (img->flags & IMAGE_NEED_DESTROY)
144     xfree(img);
145 }
146
147 void
148 image_clear(struct image_context *ctx UNUSED, struct image *img)
149 {
150   DBG("image_clear(img=%p)", img);
151   if (img->image_size)
152     if (img->flags & IMAGE_GAPS_PROTECTED)
153       {
154         byte *p = img->pixels;
155         uint bytes = img->cols * img->pixel_size;
156         for (uint row = img->rows; row--; p += img->row_size)
157           bzero(p, bytes);
158       }
159     else
160       bzero(img->pixels, img->image_size);
161 }
162
163 struct image *
164 image_init_matrix(struct image_context *ctx, struct image *img, byte *pixels, uint cols, uint rows, uint row_size, uint flags)
165 {
166   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);
167   if (unlikely(!image_dimensions_valid(cols, rows)))
168     {
169       IMAGE_ERROR(ctx, IMAGE_ERROR_INVALID_DIMENSIONS, "Invalid image dimensions (%ux%u)", cols, rows);
170       return NULL;
171     }
172   img->pixels = pixels;
173   img->cols = cols;
174   img->rows = rows;
175   img->pixel_size = img->channels = flags_to_pixel_size(flags);
176   img->row_size = row_size;
177   img->row_pixels_size = cols * img->pixel_size;
178   img->image_size = rows * row_size;
179   img->flags = flags & (IMAGE_NEW_FLAGS | IMAGE_GAPS_PROTECTED);
180   return img;
181 }
182
183 struct image *
184 image_init_subimage(struct image_context *ctx UNUSED, struct image *img, struct image *src, uint left, uint top, uint cols, uint rows)
185 {
186   DBG("image_init_subimage(img=%p src=%p left=%u top=%u cols=%u rows=%u)", img, src, left, top, cols, rows);
187   ASSERT(left + cols <= src->cols && top + rows <= src->rows);
188   img->pixels = src->pixels + left * src->pixel_size + top * src->row_size;
189   img->cols = cols;
190   img->rows = rows;
191   img->pixel_size = img->channels = src->pixel_size;
192   img->row_size = src->row_size;
193   img->row_pixels_size = cols * src->pixel_size;
194   img->image_size = src->row_size * rows;
195   img->flags = src->flags & IMAGE_NEW_FLAGS;
196   img->flags |= IMAGE_GAPS_PROTECTED;
197   return img;
198 }
199
200 byte *
201 image_channels_format_to_name(uint format, byte *buf)
202 {
203   byte *cs_name = color_space_id_to_name(format & IMAGE_COLOR_SPACE);
204   uint l = strlen(cs_name);
205   memcpy(buf, cs_name, l + 1);
206   if (format & IMAGE_ALPHA)
207     strcpy(buf + l, "+Alpha");
208   return buf;
209 }
210
211 uint
212 image_name_to_channels_format(byte *name)
213 {
214   uint i;
215   if (i = color_space_name_to_id(name))
216     return i;
217   uint l = strlen(name);
218   if (l > 6 && !strcasecmp(name + l - 5, "+alpha"))
219     {
220       byte buf[l + 1];
221       memcpy(buf, name, l - 6);
222       buf[l - 6] = 0;
223       if (i = color_space_name_to_id(name))
224         return i;
225     }
226   return 0;
227 }