1/*
2 * Copyright (c) 1997, 2013, 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/***************************************************************/
230mlib_image *mlib_ImageCreateStruct(mlib_type  type,
231                                   mlib_s32   channels,
232                                   mlib_s32   width,
233                                   mlib_s32   height,
234                                   mlib_s32   stride,
235                                   const void *data)
236{
237  mlib_image *image;
238  if (stride <= 0) {
239    return NULL;
240  }
241
242  image = (mlib_image *)mlib_malloc(sizeof(mlib_image));
243  if (image == NULL) {
244    return NULL;
245  }
246
247  if (mlib_ImageSet(image, type, channels, width, height, stride, data) == NULL) {
248    mlib_free(image);
249    image = NULL;
250  }
251
252  return image;
253}
254
255/***************************************************************/
256mlib_image *mlib_ImageCreate(mlib_type type,
257                             mlib_s32  channels,
258                             mlib_s32  width,
259                             mlib_s32  height)
260{
261  mlib_image *image;
262  mlib_s32        wb;                /* width in bytes */
263  void       *data;
264
265/* sanity check */
266  if (width <= 0 || height <= 0 || channels < 1 || channels > 4) {
267    return NULL;
268  };
269
270  if (!SAFE_TO_MULT(width, channels)) {
271    return NULL;
272  }
273
274  wb = width * channels;
275
276  switch (type) {
277    case MLIB_DOUBLE:
278      if (!SAFE_TO_MULT(wb, 8)) {
279        return NULL;
280      }
281      wb *= 8;
282      break;
283    case MLIB_FLOAT:
284    case MLIB_INT:
285      if (!SAFE_TO_MULT(wb, 4)) {
286        return NULL;
287      }
288      wb *= 4;
289      break;
290    case MLIB_USHORT:
291    case MLIB_SHORT:
292      if (!SAFE_TO_MULT(wb, 2)) {
293        return NULL;
294      }
295      wb *= 2;
296      break;
297    case MLIB_BYTE:
298      // wb is ready
299      break;
300    case MLIB_BIT:
301      if (!SAFE_TO_ADD(7, wb)) {
302        return NULL;
303      }
304      wb = (wb + 7) / 8;
305      break;
306    default:
307      return NULL;
308  }
309
310  if (!SAFE_TO_MULT(wb, height)) {
311      return NULL;
312  }
313
314  data = mlib_malloc(wb * height);
315  if (data == NULL) {
316    return NULL;
317  }
318
319  image = (mlib_image *)mlib_malloc(sizeof(mlib_image));
320  if (image == NULL) {
321    mlib_free(data);
322    return NULL;
323  };
324
325  image -> type     = type;
326  image -> channels = channels;
327  image -> width    = width;
328  image -> height   = height;
329  image -> stride   = wb;
330  image -> data     = data;
331  image -> flags    = ((width & 0xf) << 8);        /* set width field */
332  image -> flags   |= ((height & 0xf) << 12);      /* set height field */
333  image -> flags   |= ((wb & 0xf) << 16);          /* set stride field */
334  image -> flags   |= (mlib_addr)data & 0xff;
335  image -> format   = MLIB_FORMAT_UNKNOWN;
336
337  image -> paddings[0] = 0;
338  image -> paddings[1] = 0;
339  image -> paddings[2] = 0;
340  image -> paddings[3] = 0;
341
342  image -> bitoffset = 0;
343
344  if ((type == MLIB_BIT) && (wb * 8 != width * channels)) {
345    image -> flags |= MLIB_IMAGE_ONEDVECTOR;       /* not 1-d vector */
346  }
347
348  image -> flags &= MLIB_IMAGE_ATTRIBUTESET;
349  image -> state  = NULL;
350
351  return image;
352}
353
354/***************************************************************/
355void mlib_ImageDelete(mlib_image *img)
356{
357  if (img == NULL) return;
358  if ((img -> flags & MLIB_IMAGE_USERALLOCATED) == 0) {
359    mlib_free(img -> data);
360  }
361
362  mlib_ImageDeleteRowTable(img);
363  mlib_free(img);
364}
365
366/***************************************************************/
367mlib_image *mlib_ImageCreateSubimage(mlib_image *img,
368                                     mlib_s32   x,
369                                     mlib_s32   y,
370                                     mlib_s32   w,
371                                     mlib_s32   h)
372{
373  mlib_image     *subimage;
374  mlib_type      type;
375  mlib_s32       channels;
376  mlib_s32       width;                 /* for parent image */
377  mlib_s32       height;                /* for parent image */
378  mlib_s32       stride;
379  mlib_s32       bitoffset = 0;
380  void           *data;
381
382/* sanity check */
383  if (w <= 0 || h <= 0 || img == NULL) return NULL;
384
385  type     = img -> type;
386  channels = img -> channels;
387  width    = img -> width;
388  height   = img -> height;
389  stride   = img -> stride;
390
391/* clip the sub-image with respect to the parent image */
392  if (((x + w) <= 0) || ((y + h) <= 0) ||
393      (x >= width) || (y >= height)) {
394    return NULL;
395  }
396  else {
397    if (x < 0) {
398      w += x;                                        /* x is negative */
399      x = 0;
400    }
401
402    if (y < 0) {
403      h += y;                                        /* y is negative */
404      y = 0;
405    }
406
407    if ((x + w) > width) {
408      w = width - x;
409    }
410
411    if ((y + h) > height) {
412      h = height - y;
413    }
414  }
415
416/* compute sub-image origin */
417  data = (mlib_u8 *)(img -> data) + y * stride;
418
419  switch (type) {
420    case MLIB_DOUBLE:
421      data = (mlib_u8 *)data + x * channels * 8;
422      break;
423    case MLIB_FLOAT:
424    case MLIB_INT:
425      data = (mlib_u8 *)data + x * channels * 4;
426      break;
427    case MLIB_USHORT:
428    case MLIB_SHORT:
429      data = (mlib_u8 *)data + x * channels * 2;
430      break;
431    case MLIB_BYTE:
432      data = (mlib_u8 *)data + x * channels;
433      break;
434    case MLIB_BIT:
435      bitoffset = img -> bitoffset;
436      data = (mlib_u8 *)data + (x * channels + bitoffset) / 8;
437      bitoffset = (x * channels + bitoffset) & 7;
438      break;
439    default:
440      return NULL;
441  }
442
443  subimage = mlib_ImageCreateStruct(type,
444                                    channels,
445                                    w,
446                                    h,
447                                    stride,
448                                    data);
449
450  if (subimage != NULL && type == MLIB_BIT)
451    subimage -> bitoffset = bitoffset;
452
453  return subimage;
454}
455
456/***************************************************************/
457mlib_image *mlib_ImageSetSubimage(mlib_image       *dst,
458                                  const mlib_image *src,
459                                  mlib_s32         x,
460                                  mlib_s32         y,
461                                  mlib_s32         w,
462                                  mlib_s32         h)
463{
464  mlib_type  type     = src -> type;
465  mlib_s32   channels = src -> channels;
466  mlib_s32   stride   = src -> stride;
467  mlib_u8    *data    = src -> data;
468  mlib_s32   bitoffset = 0;
469
470  data += y * stride;
471
472  switch (type) {
473    case MLIB_DOUBLE:
474      data += channels * x * 8;
475      break;
476    case MLIB_FLOAT:
477    case MLIB_INT:
478      data += channels * x * 4;
479      break;
480    case MLIB_USHORT:
481    case MLIB_SHORT:
482      data += channels * x * 2;
483      break;
484    case MLIB_BYTE:
485      data += channels * x;
486      break;
487    case MLIB_BIT:
488      bitoffset = src -> bitoffset + channels * x;
489      data += (bitoffset >= 0) ? bitoffset/8 : (bitoffset - 7)/8; /* with rounding toward -Inf */
490      bitoffset &= 7;
491      break;
492    default:
493      return NULL;
494  }
495
496  if (h > 0) {
497    dst = mlib_ImageSet(dst, type, channels, w, h, stride, data);
498  } else {
499    h = - h;
500    dst = mlib_ImageSet(dst, type, channels, w, h, - stride, data + (h - 1)*stride);
501  }
502
503  if (dst != NULL && type == MLIB_BIT) {
504    dst -> bitoffset = bitoffset;
505  }
506
507  return dst;
508}
509
510/***************************************************************/
511void *mlib_ImageCreateRowTable(mlib_image *img)
512{
513  mlib_u8  **rtable, *tline;
514  mlib_s32 i, im_height, im_stride;
515
516  if (img == NULL) return NULL;
517  if (img -> state)  return img -> state;
518
519  im_height = mlib_ImageGetHeight(img);
520  im_stride = mlib_ImageGetStride(img);
521  tline     = mlib_ImageGetData(img);
522  if (tline == NULL) return NULL;
523  rtable    = mlib_malloc((3 + im_height)*sizeof(mlib_u8 *));
524  if (rtable == NULL) return NULL;
525
526  rtable[0] = 0;
527  rtable[1] = (mlib_u8*)((void **)rtable + 1);
528  rtable[2 + im_height] = (mlib_u8*)((void **)rtable + 1);
529  for (i = 0; i < im_height; i++) {
530    rtable[i+2] = tline;
531    tline    += im_stride;
532  }
533
534  img -> state = ((void **)rtable + 2);
535  return img -> state;
536}
537
538/***************************************************************/
539void mlib_ImageDeleteRowTable(mlib_image *img)
540{
541  void **state;
542
543  if (img == NULL) return;
544
545  state = img -> state;
546  if (!state) return;
547
548  mlib_free(state - 2);
549  img -> state = 0;
550}
551
552/***************************************************************/
553mlib_status mlib_ImageSetPaddings(mlib_image *img,
554                                  mlib_u8    left,
555                                  mlib_u8    top,
556                                  mlib_u8    right,
557                                  mlib_u8    bottom)
558{
559  if (img == NULL) return MLIB_FAILURE;
560
561  if ((left + right) >= img -> width ||
562      (top + bottom) >= img -> height) return MLIB_OUTOFRANGE;
563
564  img -> paddings[0] = left;
565  img -> paddings[1] = top;
566  img -> paddings[2] = right;
567  img -> paddings[3] = bottom;
568
569  return MLIB_SUCCESS;
570}
571
572/***************************************************************/
573mlib_status mlib_ImageSetFormat(mlib_image  *img,
574                                mlib_format format)
575{
576  if (img == NULL) return MLIB_FAILURE;
577
578  img -> format = format;
579
580  return MLIB_SUCCESS;
581}
582
583/***************************************************************/
584