1 | /* |
2 | * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. Oracle designates this |
8 | * particular file as subject to the "Classpath" exception as provided |
9 | * by Oracle in the LICENSE file that accompanied this code. |
10 | * |
11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | * version 2 for more details (a copy is included in the LICENSE file that |
15 | * accompanied this code). |
16 | * |
17 | * You should have received a copy of the GNU General Public License version |
18 | * 2 along with this work; if not, write to the Free Software Foundation, |
19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
20 | * |
21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 | * or visit www.oracle.com if you need additional information or have any |
23 | * questions. |
24 | */ |
25 | |
26 | |
27 | /* |
28 | * FUNCTION |
29 | * mlib_ImageCreateStruct - create image data structure |
30 | * mlib_ImageCreate - create image data structure and allocate |
31 | * memory for image data |
32 | * mlib_ImageDelete - delete image |
33 | * mlib_ImageCreateSubimage - create sub-image |
34 | * |
35 | * mlib_ImageCreateRowTable - create row starts pointer table |
36 | * mlib_ImageDeleteRowTable - delete row starts pointer table |
37 | * |
38 | * mlib_ImageSetPaddings - set paddings for clipping box borders |
39 | * |
40 | * mlib_ImageSetFormat - set image format |
41 | * |
42 | * SYNOPSIS |
43 | * mlib_image *mlib_ImageCreateStruct(mlib_type type, |
44 | * mlib_s32 channels, |
45 | * mlib_s32 width, |
46 | * mlib_s32 height, |
47 | * mlib_s32 stride, |
48 | * const void *data) |
49 | * |
50 | * mlib_image *mlib_ImageCreate(mlib_type type, |
51 | * mlib_s32 channels, |
52 | * mlib_s32 width, |
53 | * mlib_s32 height) |
54 | * |
55 | * void mlib_ImageDelete(mlib_image *img) |
56 | * |
57 | * mlib_image *mlib_ImageCreateSubimage(mlib_image *img, |
58 | * mlib_s32 x, |
59 | * mlib_s32 y, |
60 | * mlib_s32 w, |
61 | * mlib_s32 h) |
62 | * |
63 | * void *mlib_ImageCreateRowTable(mlib_image *img) |
64 | * |
65 | * void mlib_ImageDeleteRowTable(mlib_image *img) |
66 | * |
67 | * mlib_status mlib_ImageSetPaddings(mlib_image *img, |
68 | * mlib_u8 left, |
69 | * mlib_u8 top, |
70 | * mlib_u8 right, |
71 | * mlib_u8 bottom) |
72 | * |
73 | * mlib_status mlib_ImageSetFormat(mlib_image *img, |
74 | * mlib_format format) |
75 | * ARGUMENTS |
76 | * img pointer to image data structure |
77 | * type image data type, one of MLIB_BIT, MLIB_BYTE, MLIB_SHORT, |
78 | * MLIB_USHORT, MLIB_INT, MLIB_FLOAT or MLIB_DOUBLE |
79 | * channels number of image channels |
80 | * width image width in pixels |
81 | * height image height in pixels |
82 | * stride linebytes( bytes to next row) of the image |
83 | * data pointer to image data allocated by user |
84 | * x x coordinate of the left border in the source image |
85 | * y y coordinate of the top border in the source image |
86 | * w width of the sub-image |
87 | * h height of the sub-image |
88 | * left clipping box left padding |
89 | * top clipping box top padding |
90 | * right clipping box right padding |
91 | * bottom clipping box bottom padding |
92 | * format image format |
93 | * |
94 | * DESCRIPTION |
95 | * mlib_ImageCreateStruct() creates a mediaLib image data structure |
96 | * using parameter supplied by user. |
97 | * |
98 | * mlib_ImageCreate() creates a mediaLib image data structure and |
99 | * allocates memory space for image data. |
100 | * |
101 | * mlib_ImageDelete() deletes the mediaLib image data structure |
102 | * and frees the memory space of the image data if it is allocated |
103 | * through mlib_ImageCreate(). |
104 | * |
105 | * mlib_ImageCreateSubimage() creates a mediaLib image structure |
106 | * for a sub-image based on a source image. |
107 | * |
108 | * mlib_ImageCreateRowTable() creates row starts pointer table and |
109 | * puts it into mlib_image->state field. |
110 | * |
111 | * mlib_ImageDeleteRowTable() deletes row starts pointer table from |
112 | * image and puts NULL into mlib_image->state field. |
113 | * |
114 | * mlib_ImageSetPaddings() sets new values for the clipping box paddings |
115 | * |
116 | * mlib_ImageSetFormat() sets new value for the image format |
117 | */ |
118 | |
119 | #include <stdlib.h> |
120 | #include "mlib_image.h" |
121 | #include "mlib_ImageRowTable.h" |
122 | #include "mlib_ImageCreate.h" |
123 | #include "safe_math.h" |
124 | |
125 | /***************************************************************/ |
126 | mlib_image* mlib_ImageSet(mlib_image *image, |
127 | mlib_type type, |
128 | mlib_s32 channels, |
129 | mlib_s32 width, |
130 | mlib_s32 height, |
131 | mlib_s32 stride, |
132 | const void *data) |
133 | { |
134 | mlib_s32 wb; /* width in bytes */ |
135 | mlib_s32 mask; /* mask for check of stride */ |
136 | |
137 | if (image == NULL) return NULL; |
138 | |
139 | /* for some ugly functions calling with incorrect parameters */ |
140 | image -> type = type; |
141 | image -> channels = channels; |
142 | image -> width = width; |
143 | image -> height = height; |
144 | image -> stride = stride; |
145 | image -> data = (void *)data; |
146 | image -> state = NULL; |
147 | image -> format = MLIB_FORMAT_UNKNOWN; |
148 | |
149 | image -> paddings[0] = 0; |
150 | image -> paddings[1] = 0; |
151 | image -> paddings[2] = 0; |
152 | image -> paddings[3] = 0; |
153 | |
154 | image -> bitoffset = 0; |
155 | |
156 | if (width <= 0 || height <= 0 || channels < 1 || channels > 4) { |
157 | return NULL; |
158 | } |
159 | |
160 | /* Check if stride == width |
161 | * If it is then image can be treated as a 1-D vector |
162 | */ |
163 | |
164 | if (!SAFE_TO_MULT(width, channels)) { |
165 | return NULL; |
166 | } |
167 | |
168 | wb = width * channels; |
169 | |
170 | switch (type) { |
171 | case MLIB_DOUBLE: |
172 | if (!SAFE_TO_MULT(wb, 8)) { |
173 | return NULL; |
174 | } |
175 | wb *= 8; |
176 | mask = 7; |
177 | break; |
178 | case MLIB_FLOAT: |
179 | case MLIB_INT: |
180 | if (!SAFE_TO_MULT(wb, 4)) { |
181 | return NULL; |
182 | } |
183 | wb *= 4; |
184 | mask = 3; |
185 | break; |
186 | case MLIB_USHORT: |
187 | case MLIB_SHORT: |
188 | if (!SAFE_TO_MULT(wb, 2)) { |
189 | return NULL; |
190 | } |
191 | wb *= 2; |
192 | mask = 1; |
193 | break; |
194 | case MLIB_BYTE: |
195 | // wb is ready |
196 | mask = 0; |
197 | break; |
198 | case MLIB_BIT: |
199 | if (!SAFE_TO_ADD(7, wb)) { |
200 | return NULL; |
201 | } |
202 | wb = (wb + 7) / 8; |
203 | mask = 0; |
204 | break; |
205 | default: |
206 | return NULL; |
207 | } |
208 | |
209 | if (stride & mask) { |
210 | return NULL; |
211 | } |
212 | |
213 | image -> flags = ((width & 0xf) << 8); /* set width field */ |
214 | image -> flags |= ((stride & 0xf) << 16); /* set stride field */ |
215 | image -> flags |= ((height & 0xf) << 12); /* set height field */ |
216 | image -> flags |= (mlib_addr)data & 0xff; |
217 | image -> flags |= MLIB_IMAGE_USERALLOCATED; /* user allocated data */ |
218 | |
219 | if ((stride != wb) || |
220 | ((type == MLIB_BIT) && (stride * 8 != width * channels))) { |
221 | image -> flags |= MLIB_IMAGE_ONEDVECTOR; |
222 | } |
223 | |
224 | image -> flags &= MLIB_IMAGE_ATTRIBUTESET; |
225 | |
226 | return image; |
227 | } |
228 | |
229 | /***************************************************************/ |
230 | JNIEXPORT |
231 | mlib_image* mlib_ImageCreateStruct(mlib_type type, |
232 | mlib_s32 channels, |
233 | mlib_s32 width, |
234 | mlib_s32 height, |
235 | mlib_s32 stride, |
236 | const void *data) |
237 | { |
238 | mlib_image *image; |
239 | if (stride <= 0) { |
240 | return NULL; |
241 | } |
242 | |
243 | image = (mlib_image *)mlib_malloc(sizeof(mlib_image)); |
244 | if (image == NULL) { |
245 | return NULL; |
246 | } |
247 | |
248 | if (mlib_ImageSet(image, type, channels, width, height, stride, data) == NULL) { |
249 | mlib_free(image); |
250 | image = NULL; |
251 | } |
252 | |
253 | return image; |
254 | } |
255 | |
256 | /***************************************************************/ |
257 | JNIEXPORT |
258 | mlib_image* mlib_ImageCreate(mlib_type type, |
259 | mlib_s32 channels, |
260 | mlib_s32 width, |
261 | mlib_s32 height) |
262 | { |
263 | mlib_image *image; |
264 | mlib_s32 wb; /* width in bytes */ |
265 | void *data; |
266 | |
267 | /* sanity check */ |
268 | if (width <= 0 || height <= 0 || channels < 1 || channels > 4) { |
269 | return NULL; |
270 | }; |
271 | |
272 | if (!SAFE_TO_MULT(width, channels)) { |
273 | return NULL; |
274 | } |
275 | |
276 | wb = width * channels; |
277 | |
278 | switch (type) { |
279 | case MLIB_DOUBLE: |
280 | if (!SAFE_TO_MULT(wb, 8)) { |
281 | return NULL; |
282 | } |
283 | wb *= 8; |
284 | break; |
285 | case MLIB_FLOAT: |
286 | case MLIB_INT: |
287 | if (!SAFE_TO_MULT(wb, 4)) { |
288 | return NULL; |
289 | } |
290 | wb *= 4; |
291 | break; |
292 | case MLIB_USHORT: |
293 | case MLIB_SHORT: |
294 | if (!SAFE_TO_MULT(wb, 2)) { |
295 | return NULL; |
296 | } |
297 | wb *= 2; |
298 | break; |
299 | case MLIB_BYTE: |
300 | // wb is ready |
301 | break; |
302 | case MLIB_BIT: |
303 | if (!SAFE_TO_ADD(7, wb)) { |
304 | return NULL; |
305 | } |
306 | wb = (wb + 7) / 8; |
307 | break; |
308 | default: |
309 | return NULL; |
310 | } |
311 | |
312 | if (!SAFE_TO_MULT(wb, height)) { |
313 | return NULL; |
314 | } |
315 | |
316 | data = mlib_malloc(wb * height); |
317 | if (data == NULL) { |
318 | return NULL; |
319 | } |
320 | |
321 | image = (mlib_image *)mlib_malloc(sizeof(mlib_image)); |
322 | if (image == NULL) { |
323 | mlib_free(data); |
324 | return NULL; |
325 | }; |
326 | |
327 | image -> type = type; |
328 | image -> channels = channels; |
329 | image -> width = width; |
330 | image -> height = height; |
331 | image -> stride = wb; |
332 | image -> data = data; |
333 | image -> flags = ((width & 0xf) << 8); /* set width field */ |
334 | image -> flags |= ((height & 0xf) << 12); /* set height field */ |
335 | image -> flags |= ((wb & 0xf) << 16); /* set stride field */ |
336 | image -> flags |= (mlib_addr)data & 0xff; |
337 | image -> format = MLIB_FORMAT_UNKNOWN; |
338 | |
339 | image -> paddings[0] = 0; |
340 | image -> paddings[1] = 0; |
341 | image -> paddings[2] = 0; |
342 | image -> paddings[3] = 0; |
343 | |
344 | image -> bitoffset = 0; |
345 | |
346 | if ((type == MLIB_BIT) && (wb * 8 != width * channels)) { |
347 | image -> flags |= MLIB_IMAGE_ONEDVECTOR; /* not 1-d vector */ |
348 | } |
349 | |
350 | image -> flags &= MLIB_IMAGE_ATTRIBUTESET; |
351 | image -> state = NULL; |
352 | |
353 | return image; |
354 | } |
355 | |
356 | /***************************************************************/ |
357 | JNIEXPORT |
358 | void mlib_ImageDelete(mlib_image *img) |
359 | { |
360 | if (img == NULL) return; |
361 | if ((img -> flags & MLIB_IMAGE_USERALLOCATED) == 0) { |
362 | mlib_free(img -> data); |
363 | } |
364 | |
365 | mlib_ImageDeleteRowTable(img); |
366 | mlib_free(img); |
367 | } |
368 | |
369 | /***************************************************************/ |
370 | mlib_image *mlib_ImageCreateSubimage(mlib_image *img, |
371 | mlib_s32 x, |
372 | mlib_s32 y, |
373 | mlib_s32 w, |
374 | mlib_s32 h) |
375 | { |
376 | mlib_image *subimage; |
377 | mlib_type type; |
378 | mlib_s32 channels; |
379 | mlib_s32 width; /* for parent image */ |
380 | mlib_s32 height; /* for parent image */ |
381 | mlib_s32 stride; |
382 | mlib_s32 bitoffset = 0; |
383 | void *data; |
384 | |
385 | /* sanity check */ |
386 | if (w <= 0 || h <= 0 || img == NULL) return NULL; |
387 | |
388 | type = img -> type; |
389 | channels = img -> channels; |
390 | width = img -> width; |
391 | height = img -> height; |
392 | stride = img -> stride; |
393 | |
394 | /* clip the sub-image with respect to the parent image */ |
395 | if (((x + w) <= 0) || ((y + h) <= 0) || |
396 | (x >= width) || (y >= height)) { |
397 | return NULL; |
398 | } |
399 | else { |
400 | if (x < 0) { |
401 | w += x; /* x is negative */ |
402 | x = 0; |
403 | } |
404 | |
405 | if (y < 0) { |
406 | h += y; /* y is negative */ |
407 | y = 0; |
408 | } |
409 | |
410 | if ((x + w) > width) { |
411 | w = width - x; |
412 | } |
413 | |
414 | if ((y + h) > height) { |
415 | h = height - y; |
416 | } |
417 | } |
418 | |
419 | /* compute sub-image origin */ |
420 | data = (mlib_u8 *)(img -> data) + y * stride; |
421 | |
422 | switch (type) { |
423 | case MLIB_DOUBLE: |
424 | data = (mlib_u8 *)data + x * channels * 8; |
425 | break; |
426 | case MLIB_FLOAT: |
427 | case MLIB_INT: |
428 | data = (mlib_u8 *)data + x * channels * 4; |
429 | break; |
430 | case MLIB_USHORT: |
431 | case MLIB_SHORT: |
432 | data = (mlib_u8 *)data + x * channels * 2; |
433 | break; |
434 | case MLIB_BYTE: |
435 | data = (mlib_u8 *)data + x * channels; |
436 | break; |
437 | case MLIB_BIT: |
438 | bitoffset = img -> bitoffset; |
439 | data = (mlib_u8 *)data + (x * channels + bitoffset) / 8; |
440 | bitoffset = (x * channels + bitoffset) & 7; |
441 | break; |
442 | default: |
443 | return NULL; |
444 | } |
445 | |
446 | subimage = mlib_ImageCreateStruct(type, |
447 | channels, |
448 | w, |
449 | h, |
450 | stride, |
451 | data); |
452 | |
453 | if (subimage != NULL && type == MLIB_BIT) |
454 | subimage -> bitoffset = bitoffset; |
455 | |
456 | return subimage; |
457 | } |
458 | |
459 | /***************************************************************/ |
460 | mlib_image *mlib_ImageSetSubimage(mlib_image *dst, |
461 | const mlib_image *src, |
462 | mlib_s32 x, |
463 | mlib_s32 y, |
464 | mlib_s32 w, |
465 | mlib_s32 h) |
466 | { |
467 | mlib_type type = src -> type; |
468 | mlib_s32 channels = src -> channels; |
469 | mlib_s32 stride = src -> stride; |
470 | mlib_u8 *data = src -> data; |
471 | mlib_s32 bitoffset = 0; |
472 | |
473 | data += y * stride; |
474 | |
475 | switch (type) { |
476 | case MLIB_DOUBLE: |
477 | data += channels * x * 8; |
478 | break; |
479 | case MLIB_FLOAT: |
480 | case MLIB_INT: |
481 | data += channels * x * 4; |
482 | break; |
483 | case MLIB_USHORT: |
484 | case MLIB_SHORT: |
485 | data += channels * x * 2; |
486 | break; |
487 | case MLIB_BYTE: |
488 | data += channels * x; |
489 | break; |
490 | case MLIB_BIT: |
491 | bitoffset = src -> bitoffset + channels * x; |
492 | data += (bitoffset >= 0) ? bitoffset/8 : (bitoffset - 7)/8; /* with rounding toward -Inf */ |
493 | bitoffset &= 7; |
494 | break; |
495 | default: |
496 | return NULL; |
497 | } |
498 | |
499 | if (h > 0) { |
500 | dst = mlib_ImageSet(dst, type, channels, w, h, stride, data); |
501 | } else { |
502 | h = - h; |
503 | dst = mlib_ImageSet(dst, type, channels, w, h, - stride, data + (h - 1)*stride); |
504 | } |
505 | |
506 | if (dst != NULL && type == MLIB_BIT) { |
507 | dst -> bitoffset = bitoffset; |
508 | } |
509 | |
510 | return dst; |
511 | } |
512 | |
513 | /***************************************************************/ |
514 | void *mlib_ImageCreateRowTable(mlib_image *img) |
515 | { |
516 | mlib_u8 **rtable, *tline; |
517 | mlib_s32 i, im_height, im_stride; |
518 | |
519 | if (img == NULL) return NULL; |
520 | if (img -> state) return img -> state; |
521 | |
522 | im_height = mlib_ImageGetHeight(img); |
523 | im_stride = mlib_ImageGetStride(img); |
524 | tline = mlib_ImageGetData(img); |
525 | if (tline == NULL) return NULL; |
526 | rtable = mlib_malloc((3 + im_height)*sizeof(mlib_u8 *)); |
527 | if (rtable == NULL) return NULL; |
528 | |
529 | rtable[0] = 0; |
530 | rtable[1] = (mlib_u8*)((void **)rtable + 1); |
531 | rtable[2 + im_height] = (mlib_u8*)((void **)rtable + 1); |
532 | for (i = 0; i < im_height; i++) { |
533 | rtable[i+2] = tline; |
534 | tline += im_stride; |
535 | } |
536 | |
537 | img -> state = ((void **)rtable + 2); |
538 | return img -> state; |
539 | } |
540 | |
541 | /***************************************************************/ |
542 | void mlib_ImageDeleteRowTable(mlib_image *img) |
543 | { |
544 | void **state; |
545 | |
546 | if (img == NULL) return; |
547 | |
548 | state = img -> state; |
549 | if (!state) return; |
550 | |
551 | mlib_free(state - 2); |
552 | img -> state = 0; |
553 | } |
554 | |
555 | /***************************************************************/ |
556 | mlib_status mlib_ImageSetPaddings(mlib_image *img, |
557 | mlib_u8 left, |
558 | mlib_u8 top, |
559 | mlib_u8 right, |
560 | mlib_u8 bottom) |
561 | { |
562 | if (img == NULL) return MLIB_FAILURE; |
563 | |
564 | if ((left + right) >= img -> width || |
565 | (top + bottom) >= img -> height) return MLIB_OUTOFRANGE; |
566 | |
567 | img -> paddings[0] = left; |
568 | img -> paddings[1] = top; |
569 | img -> paddings[2] = right; |
570 | img -> paddings[3] = bottom; |
571 | |
572 | return MLIB_SUCCESS; |
573 | } |
574 | |
575 | /***************************************************************/ |
576 | mlib_status mlib_ImageSetFormat(mlib_image *img, |
577 | mlib_format format) |
578 | { |
579 | if (img == NULL) return MLIB_FAILURE; |
580 | |
581 | img -> format = format; |
582 | |
583 | return MLIB_SUCCESS; |
584 | } |
585 | |
586 | /***************************************************************/ |
587 | |