1 /*****************************************************************************
2 * This file is part of gfxprim library. *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
19 * Copyright (C) 2009-2011 Jiri "BlueBear" Dluhos *
20 * <jiri.bluebear.dluhos@gmail.com> *
22 * Copyright (C) 2009-2013 Cyril Hrubis <metan@ucw.cz> *
24 *****************************************************************************/
30 #include "GP_Transform.h"
32 #include "GP_GetPutPixel.h"
34 #include "GP_Pixmap.h"
37 static uint32_t get_bpr(uint32_t bpp
, uint32_t w
)
39 uint64_t bits_per_row
= (uint64_t)bpp
* w
;
40 uint8_t padd
= !!(bits_per_row
% 8);
42 if (bits_per_row
/ 8 + padd
> UINT32_MAX
) {
43 GP_WARN("Pixmap too wide %u (overflow detected)", w
);
47 return bits_per_row
/ 8 + padd
;
50 GP_Pixmap
*GP_PixmapAlloc(GP_Size w
, GP_Size h
, GP_PixelType type
)
57 if (!GP_VALID_PIXELTYPE(type
)) {
58 GP_WARN("Invalid pixel type %u", type
);
63 if (w
<= 0 || h
<= 0) {
64 GP_WARN("Trying to allocate pixmap with zero width and/or height");
69 GP_DEBUG(1, "Allocating pixmap %u x %u - %s",
70 w
, h
, GP_PixelTypeName(type
));
72 bpp
= GP_PixelSize(type
);
74 if (!(bpr
= get_bpr(bpp
, w
)))
77 size_t size
= bpr
* h
;
79 if (size
/ h
!= bpr
) {
80 GP_WARN("Pixmap too big %u x %u (owerflow detected)", w
, h
);
84 pixels
= malloc(size
);
85 pixmap
= malloc(sizeof(GP_Pixmap
));
87 if (pixels
== NULL
|| pixmap
== NULL
) {
90 GP_WARN("Malloc failed :(");
95 pixmap
->pixels
= pixels
;
97 pixmap
->bytes_per_row
= bpr
;
103 pixmap
->gamma
= NULL
;
105 pixmap
->pixel_type
= type
;
106 #warning Hmm, bit endianity... Why is not this settled by different pixel types?
107 pixmap
->bit_endian
= GP_PixelTypes
[type
].bit_endian
;
109 /* rotation and mirroring */
110 GP_PixmapSetRotation(pixmap
, 0, 0, 0);
112 pixmap
->free_pixels
= 1;
117 void GP_PixmapFree(GP_Pixmap
*pixmap
)
119 GP_DEBUG(1, "Freeing pixmap (%p)", pixmap
);
124 if (pixmap
->free_pixels
)
125 free(pixmap
->pixels
);
128 GP_GammaRelease(pixmap
->gamma
);
133 GP_Pixmap
*GP_PixmapInit(GP_Pixmap
*pixmap
, GP_Size w
, GP_Size h
,
134 GP_PixelType type
, void *pixels
)
136 uint32_t bpp
= GP_PixelSize(type
);
137 uint32_t bpr
= get_bpr(bpp
, w
);
139 pixmap
->pixels
= pixels
;
141 pixmap
->bytes_per_row
= bpr
;
147 pixmap
->pixel_type
= type
;
148 pixmap
->bit_endian
= 0;
150 pixmap
->gamma
= NULL
;
152 /* rotation and mirroring */
153 GP_PixmapSetRotation(pixmap
, 0, 0, 0);
155 pixmap
->free_pixels
= 0;
160 int GP_PixmapResize(GP_Pixmap
*pixmap
, GP_Size w
, GP_Size h
)
162 uint32_t bpr
= get_bpr(pixmap
->bpp
, w
);
165 pixels
= realloc(pixmap
->pixels
, bpr
* h
);
172 pixmap
->bytes_per_row
= bpr
;
173 pixmap
->pixels
= pixels
;
178 GP_Pixmap
*GP_PixmapCopy(const GP_Pixmap
*src
, int flags
)
186 new = malloc(sizeof(GP_Pixmap
));
187 pixels
= malloc(src
->bytes_per_row
* src
->h
);
189 if (pixels
== NULL
|| new == NULL
) {
192 GP_WARN("Malloc failed :(");
197 new->pixels
= pixels
;
199 if (flags
& GP_COPY_WITH_PIXELS
)
200 memcpy(pixels
, src
->pixels
, src
->bytes_per_row
* src
->h
);
203 new->bytes_per_row
= src
->bytes_per_row
;
209 new->pixel_type
= src
->pixel_type
;
210 new->bit_endian
= src
->bit_endian
;
212 if (flags
& GP_COPY_WITH_ROTATION
)
213 GP_PixmapCopyRotation(src
, new);
215 GP_PixmapSetRotation(new, 0, 0, 0);
217 //TODO: Copy the gamma too
220 new->free_pixels
= 1;
226 GP_Pixmap
*GP_PixmapConvertAlloc(const GP_Pixmap
*src
,
227 GP_PixelType dst_pixel_type
)
229 int w
= GP_PixmapW(src
);
230 int h
= GP_PixmapH(src
);
232 GP_Pixmap
*ret
= GP_PixmapAlloc(w
, h
, dst_pixel_type
);
238 * Fill the buffer with zeroes, otherwise it will
239 * contain random data which will generate mess
240 * when converting image with alpha channel.
242 memset(ret
->pixels
, 0, ret
->bytes_per_row
* ret
->h
);
244 GP_Blit(src
, 0, 0, w
, h
, ret
, 0, 0);
249 GP_Pixmap
*GP_PixmapConvert(const GP_Pixmap
*src
, GP_Pixmap
*dst
)
252 int w
= GP_PixmapW(src
);
253 int h
= GP_PixmapH(src
);
256 * Fill the buffer with zeroes, otherwise it will
257 * contain random data which will generate mess
258 * when converting image with alpha channel.
260 memset(dst
->pixels
, 0, dst
->bytes_per_row
* dst
->h
);
262 GP_Blit(src
, 0, 0, w
, h
, dst
, 0, 0);
267 GP_Pixmap
*GP_SubPixmapAlloc(const GP_Pixmap
*pixmap
,
268 GP_Coord x
, GP_Coord y
, GP_Size w
, GP_Size h
)
270 GP_Pixmap
*res
= malloc(sizeof(GP_Pixmap
));
273 GP_WARN("Malloc failed :(");
278 return GP_SubPixmap(pixmap
, res
, x
, y
, w
, h
);
281 GP_Pixmap
*GP_SubPixmap(const GP_Pixmap
*pixmap
, GP_Pixmap
*subpixmap
,
282 GP_Coord x
, GP_Coord y
, GP_Size w
, GP_Size h
)
284 GP_CHECK(pixmap
, "NULL pixmap");
286 GP_TRANSFORM_RECT(pixmap
, x
, y
, w
, h
);
288 GP_CHECK(pixmap
->w
>= x
+ w
, "Subpixmap w out of original pixmap.");
289 GP_CHECK(pixmap
->h
>= y
+ h
, "Subpixmap h out of original pixmap.");
291 subpixmap
->bpp
= pixmap
->bpp
;
292 subpixmap
->bytes_per_row
= pixmap
->bytes_per_row
;
293 subpixmap
->offset
= (pixmap
->offset
+
294 GP_PixelAddrOffset(x
, pixmap
->pixel_type
)) % 8;
299 subpixmap
->pixel_type
= pixmap
->pixel_type
;
300 subpixmap
->bit_endian
= pixmap
->bit_endian
;
303 subpixmap
->gamma
= pixmap
->gamma
;
305 /* rotation and mirroring */
306 GP_PixmapCopyRotation(pixmap
, subpixmap
);
308 subpixmap
->pixels
= GP_PIXEL_ADDR(pixmap
, x
, y
);
310 subpixmap
->free_pixels
= 0;
315 void GP_PixmapPrintInfo(const GP_Pixmap
*self
)
317 printf("Pixmap info\n");
318 printf("------------\n");
319 printf("Size\t%ux%u\n", self
->w
, self
->h
);
320 printf("BPP\t%u\n", self
->bpp
);
321 printf("BPR\t%u\n", self
->bytes_per_row
);
322 printf("Pixel\t%s (%u)\n", GP_PixelTypeName(self
->pixel_type
),
324 printf("Offset\t%u (only unaligned pixel types)\n", self
->offset
);
325 printf("Flags\taxes_swap=%u x_swap=%u y_swap=%u free_pixels=%u\n",
326 self
->axes_swap
, self
->x_swap
, self
->y_swap
, self
->free_pixels
);
329 GP_GammaPrint(self
->gamma
);
333 * The pixmap rotations consists of two cyclic permutation groups that are
336 * The flags change as follows:
340 * x_swap y_swap axes_swap
346 * And mirrored group:
348 * x_swap y_swap axes_swap
355 void GP_PixmapRotateCW(GP_Pixmap
*pixmap
)
357 pixmap
->axes_swap
= !pixmap
->axes_swap
;
359 if (!pixmap
->x_swap
&& !pixmap
->y_swap
) {
364 if (pixmap
->x_swap
&& !pixmap
->y_swap
) {
369 if (pixmap
->x_swap
&& pixmap
->y_swap
) {
377 void GP_PixmapRotateCCW(GP_Pixmap
*pixmap
)
379 pixmap
->axes_swap
= !pixmap
->axes_swap
;
381 if (!pixmap
->x_swap
&& !pixmap
->y_swap
) {
386 if (pixmap
->x_swap
&& !pixmap
->y_swap
) {
391 if (pixmap
->x_swap
&& pixmap
->y_swap
) {
399 int GP_PixmapEqual(const GP_Pixmap
*pixmap1
, const GP_Pixmap
*pixmap2
)
401 if (pixmap1
->pixel_type
!= pixmap2
->pixel_type
)
404 if (GP_PixmapW(pixmap1
) != GP_PixmapW(pixmap2
))
407 if (GP_PixmapH(pixmap1
) != GP_PixmapH(pixmap2
))
410 GP_Coord x
, y
, w
= GP_PixmapW(pixmap1
), h
= GP_PixmapH(pixmap1
);
412 for (x
= 0; x
< w
; x
++)
413 for (y
= 0; y
< h
; y
++)
414 if (GP_GetPixel(pixmap1
, x
, y
) != GP_GetPixel(pixmap2
, x
, y
))