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/***************************************************************/
126mlib_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/***************************************************************/
230JNIEXPORT
231mlib_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/***************************************************************/
257JNIEXPORT
258mlib_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/***************************************************************/
357JNIEXPORT
358void 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/***************************************************************/
370mlib_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/***************************************************************/
460mlib_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/***************************************************************/
514void *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/***************************************************************/
542void 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/***************************************************************/
556mlib_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/***************************************************************/
576mlib_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