1 /*
2
3 rl2webp -- WebP related functions
4
5 version 0.1, 2013 April 5
6
7 Author: Sandro Furieri a.furieri@lqt.it
8
9 -----------------------------------------------------------------------------
10
11 Version: MPL 1.1/GPL 2.0/LGPL 2.1
12
13 The contents of this file are subject to the Mozilla Public License Version
14 1.1 (the "License"); you may not use this file except in compliance with
15 the License. You may obtain a copy of the License at
16 http://www.mozilla.org/MPL/
17
18 Software distributed under the License is distributed on an "AS IS" basis,
19 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
20 for the specific language governing rights and limitations under the
21 License.
22
23 The Original Code is the SpatiaLite library
24
25 The Initial Developer of the Original Code is Alessandro Furieri
26
27 Portions created by the Initial Developer are Copyright (C) 2008-2013
28 the Initial Developer. All Rights Reserved.
29
30 Alternatively, the contents of this file may be used under the terms of
31 either the GNU General Public License Version 2 or later (the "GPL"), or
32 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 in which case the provisions of the GPL or the LGPL are applicable instead
34 of those above. If you wish to allow use of your version of this file only
35 under the terms of either the GPL or the LGPL, and not to allow others to
36 use your version of this file under the terms of the MPL, indicate your
37 decision by deleting the provisions above and replace them with the notice
38 and other provisions required by the GPL or the LGPL. If you do not delete
39 the provisions above, a recipient may use your version of this file under
40 the terms of any one of the MPL, the GPL or the LGPL.
41
42 */
43
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47
48 #include <webp/decode.h>
49 #include <webp/encode.h>
50
51 #include "config.h"
52
53 #ifdef LOADABLE_EXTENSION
54 #include "rasterlite2/sqlite.h"
55 #endif
56
57 #include "rasterlite2/rasterlite2.h"
58 #include "rasterlite2_private.h"
59
60 static int
check_webp_compatibility(unsigned char sample_type,unsigned char pixel_type,unsigned char num_samples)61 check_webp_compatibility (unsigned char sample_type, unsigned char pixel_type,
62 unsigned char num_samples)
63 {
64 /* checks for WebP compatibility */
65 switch (sample_type)
66 {
67 case RL2_SAMPLE_1_BIT:
68 case RL2_SAMPLE_2_BIT:
69 case RL2_SAMPLE_4_BIT:
70 case RL2_SAMPLE_UINT8:
71 break;
72 default:
73 return RL2_ERROR;
74 };
75 switch (pixel_type)
76 {
77 case RL2_PIXEL_MONOCHROME:
78 case RL2_PIXEL_PALETTE:
79 case RL2_PIXEL_GRAYSCALE:
80 case RL2_PIXEL_RGB:
81 break;
82 default:
83 return RL2_ERROR;
84 };
85 if (pixel_type == RL2_PIXEL_MONOCHROME)
86 {
87 switch (sample_type)
88 {
89 case RL2_SAMPLE_1_BIT:
90 break;
91 default:
92 return RL2_ERROR;
93 };
94 if (num_samples != 1)
95 return RL2_ERROR;
96 }
97 if (pixel_type == RL2_PIXEL_PALETTE)
98 {
99 switch (sample_type)
100 {
101 case RL2_SAMPLE_1_BIT:
102 case RL2_SAMPLE_2_BIT:
103 case RL2_SAMPLE_4_BIT:
104 case RL2_SAMPLE_UINT8:
105 break;
106 default:
107 return RL2_ERROR;
108 };
109 if (num_samples != 1)
110 return RL2_ERROR;
111 }
112 if (pixel_type == RL2_PIXEL_GRAYSCALE)
113 {
114 switch (sample_type)
115 {
116 case RL2_SAMPLE_1_BIT:
117 case RL2_SAMPLE_2_BIT:
118 case RL2_SAMPLE_4_BIT:
119 case RL2_SAMPLE_UINT8:
120 break;
121 default:
122 return RL2_ERROR;
123 };
124 if (num_samples != 1)
125 return RL2_ERROR;
126 }
127 if (pixel_type == RL2_PIXEL_RGB)
128 {
129 switch (sample_type)
130 {
131 case RL2_SAMPLE_UINT8:
132 break;
133 default:
134 return RL2_ERROR;
135 };
136 if (num_samples != 3)
137 return RL2_ERROR;
138 }
139 return RL2_OK;
140 }
141
142 static int
compress_lossy_alpha_webp(rl2PrivRasterPtr rst,unsigned char ** webp,int * webp_size,int quality)143 compress_lossy_alpha_webp (rl2PrivRasterPtr rst, unsigned char **webp,
144 int *webp_size, int quality)
145 {
146 /* compressing a WebP (lossy) image (with ALPHA channel) */
147 int size;
148 unsigned char *output;
149 int rgba_size;
150 unsigned char *rgba;
151
152 *webp = NULL;
153 *webp_size = 0;
154 if (rl2_raster_data_to_RGBA ((rl2RasterPtr) rst, &rgba, &rgba_size) ==
155 RL2_ERROR)
156 return RL2_ERROR;
157 if (quality > 100)
158 quality = 100;
159 if (quality < 0)
160 quality = 75;
161 size =
162 WebPEncodeRGBA (rgba, rst->width, rst->height, rst->width * 4, quality,
163 &output);
164 free (rgba);
165 if (size == 0)
166 return RL2_ERROR;
167 *webp = output;
168 *webp_size = size;
169 return RL2_OK;
170 }
171
172 static int
compress_lossy_webp(rl2RasterPtr ptr,unsigned char ** webp,int * webp_size,int quality)173 compress_lossy_webp (rl2RasterPtr ptr, unsigned char **webp, int *webp_size,
174 int quality)
175 {
176 /* compressing a WebP (lossy) image */
177 int size;
178 unsigned char *output;
179 int rgb_size;
180 unsigned char *rgb;
181 rl2PrivRasterPtr rst = (rl2PrivRasterPtr) ptr;
182 if (rst->maskBuffer != NULL || rst->noData != NULL)
183 return compress_lossy_alpha_webp (rst, webp, webp_size, quality);
184
185 /* no ALPHA channel */
186 *webp = NULL;
187 *webp_size = 0;
188 if (rl2_raster_data_to_RGB (ptr, &rgb, &rgb_size) == RL2_ERROR)
189 return RL2_ERROR;
190 if (quality > 100)
191 quality = 100;
192 if (quality < 0)
193 quality = 75;
194 size =
195 WebPEncodeRGB (rgb, rst->width, rst->height, rst->width * 3, quality,
196 &output);
197 free (rgb);
198 if (size == 0)
199 return RL2_ERROR;
200 *webp = output;
201 *webp_size = size;
202 return RL2_OK;
203 }
204
205 static int
compress_lossless_alpha_webp(rl2PrivRasterPtr rst,unsigned char ** webp,int * webp_size)206 compress_lossless_alpha_webp (rl2PrivRasterPtr rst, unsigned char **webp,
207 int *webp_size)
208 {
209 /* compressing a WebP (lossless) image (with ALPHA channel) */
210 int size;
211 unsigned char *output;
212 int rgba_size;
213 unsigned char *rgba;
214
215 *webp = NULL;
216 *webp_size = 0;
217 if (rl2_raster_data_to_RGBA ((rl2RasterPtr) rst, &rgba, &rgba_size) ==
218 RL2_ERROR)
219 return RL2_ERROR;
220 size =
221 WebPEncodeLosslessRGBA (rgba, rst->width, rst->height, rst->width * 4,
222 &output);
223 free (rgba);
224 if (size == 0)
225 return RL2_ERROR;
226 *webp = output;
227 *webp_size = size;
228 return RL2_OK;
229 }
230
231 static int
compress_lossless_webp(rl2RasterPtr ptr,unsigned char ** webp,int * webp_size)232 compress_lossless_webp (rl2RasterPtr ptr, unsigned char **webp, int *webp_size)
233 {
234 /* compressing a WebP (lossless) image */
235 int size;
236 unsigned char *output;
237 int rgb_size;
238 unsigned char *rgb;
239 rl2PrivRasterPtr rst = (rl2PrivRasterPtr) ptr;
240 if (rst->maskBuffer != NULL || rst->noData != NULL)
241 return compress_lossless_alpha_webp (rst, webp, webp_size);
242
243 /* no ALPHA channel */
244 *webp = NULL;
245 *webp_size = 0;
246 if (rl2_raster_data_to_RGB (ptr, &rgb, &rgb_size) == RL2_ERROR)
247 return RL2_ERROR;
248 size =
249 WebPEncodeLosslessRGB (rgb, rst->width, rst->height, rst->width * 3,
250 &output);
251 free (rgb);
252 if (size == 0)
253 return RL2_ERROR;
254 *webp = output;
255 *webp_size = size;
256 return RL2_OK;
257 }
258
259 RL2_DECLARE int
rl2_section_to_lossy_webp(rl2SectionPtr scn,const char * path,int quality)260 rl2_section_to_lossy_webp (rl2SectionPtr scn, const char *path, int quality)
261 {
262 /* attempting to save a raster section into a WebP (lossy) file */
263 int blob_size;
264 unsigned char *blob;
265 rl2RasterPtr rst;
266 int ret;
267
268 if (scn == NULL)
269 return RL2_ERROR;
270 rst = rl2_get_section_raster (scn);
271 if (rst == NULL)
272 return RL2_ERROR;
273 /* attempting to export as a WebP image */
274 if (rl2_raster_to_lossy_webp (rst, &blob, &blob_size, quality) != RL2_OK)
275 return RL2_ERROR;
276 ret = rl2_blob_to_file (path, blob, blob_size);
277 free (blob);
278 if (ret != RL2_OK)
279 return RL2_ERROR;
280 return RL2_OK;
281 }
282
283 RL2_DECLARE int
rl2_raster_to_lossy_webp(rl2RasterPtr rst,unsigned char ** webp,int * webp_size,int quality)284 rl2_raster_to_lossy_webp (rl2RasterPtr rst, unsigned char **webp,
285 int *webp_size, int quality)
286 {
287 /* creating a WebP image (lossy) from a raster */
288 unsigned char sample_type;
289 unsigned char pixel_type;
290 unsigned char num_samples;
291 unsigned char *blob;
292 int blob_size;
293
294 if (rst == NULL)
295 return RL2_ERROR;
296 if (rl2_get_raster_type (rst, &sample_type, &pixel_type, &num_samples) !=
297 RL2_OK)
298 return RL2_ERROR;
299 if (check_webp_compatibility (sample_type, pixel_type, num_samples) !=
300 RL2_OK)
301 return RL2_ERROR;
302 if (compress_lossy_webp (rst, &blob, &blob_size, quality) != RL2_OK)
303 return RL2_ERROR;
304 *webp = blob;
305 *webp_size = blob_size;
306 return RL2_OK;
307 }
308
309
310 RL2_DECLARE int
rl2_section_to_lossless_webp(rl2SectionPtr scn,const char * path)311 rl2_section_to_lossless_webp (rl2SectionPtr scn, const char *path)
312 {
313 /* attempting to save a raster section into a WebP (lossless) file */
314 int blob_size;
315 unsigned char *blob;
316 rl2RasterPtr rst;
317 int ret;
318
319 if (scn == NULL)
320 return RL2_ERROR;
321 rst = rl2_get_section_raster (scn);
322 if (rst == NULL)
323 return RL2_ERROR;
324 /* attempting to export as a WebP image */
325 if (rl2_raster_to_lossless_webp (rst, &blob, &blob_size) != RL2_OK)
326 return RL2_ERROR;
327 ret = rl2_blob_to_file (path, blob, blob_size);
328 free (blob);
329 if (ret != RL2_OK)
330 return RL2_ERROR;
331 return RL2_OK;
332 }
333
334 RL2_DECLARE int
rl2_raster_to_lossless_webp(rl2RasterPtr rst,unsigned char ** webp,int * webp_size)335 rl2_raster_to_lossless_webp (rl2RasterPtr rst, unsigned char **webp,
336 int *webp_size)
337 {
338 /* creating a WebP image (lossless) from a raster */
339 unsigned char sample_type;
340 unsigned char pixel_type;
341 unsigned char num_samples;
342 unsigned char *blob;
343 int blob_size;
344
345 if (rst == NULL)
346 return RL2_ERROR;
347 if (rl2_get_raster_type (rst, &sample_type, &pixel_type, &num_samples) !=
348 RL2_OK)
349 return RL2_ERROR;
350 if (check_webp_compatibility (sample_type, pixel_type, num_samples) !=
351 RL2_OK)
352 return RL2_ERROR;
353 if (compress_lossless_webp (rst, &blob, &blob_size) != RL2_OK)
354 return RL2_ERROR;
355 *webp = blob;
356 *webp_size = blob_size;
357 return RL2_OK;
358 }
359
360 RL2_DECLARE rl2SectionPtr
rl2_section_from_webp(const char * path)361 rl2_section_from_webp (const char *path)
362 {
363 /* attempting to create a raster section from a WebP file */
364 int blob_size;
365 unsigned char *blob;
366 rl2SectionPtr scn;
367 rl2RasterPtr rst;
368
369 /* attempting to create a raster */
370 if (rl2_blob_from_file (path, &blob, &blob_size) != RL2_OK)
371 return NULL;
372 rst = rl2_raster_from_webp (blob, blob_size);
373 free (blob);
374 if (rst == NULL)
375 return NULL;
376
377 /* creating the raster section */
378 scn =
379 rl2_create_section (path, RL2_COMPRESSION_LOSSY_WEBP,
380 RL2_TILESIZE_UNDEFINED, RL2_TILESIZE_UNDEFINED,
381 rst);
382 return scn;
383 }
384
385 RL2_DECLARE rl2RasterPtr
rl2_raster_from_webp(const unsigned char * webp,int webp_size)386 rl2_raster_from_webp (const unsigned char *webp, int webp_size)
387 {
388 /* attempting to create a raster from a WebP image */
389 rl2RasterPtr rst = NULL;
390 unsigned char *buf;
391 int buf_size;
392 unsigned char *mask;
393 int mask_size;
394 unsigned int width;
395 unsigned int height;
396
397 if (rl2_decode_webp_scaled
398 (1, webp, webp_size, &width, &height, RL2_PIXEL_RGB, &buf, &buf_size,
399 &mask, &mask_size) != RL2_OK)
400 return NULL;
401
402 /* creating the raster */
403 rst =
404 rl2_create_raster (width, height, RL2_SAMPLE_UINT8, RL2_PIXEL_RGB, 3,
405 buf, buf_size, NULL, mask, mask_size, NULL);
406 if (rst == NULL)
407 {
408 free (buf);
409 if (mask != NULL)
410 free (mask);
411 }
412 return rst;
413 }
414
415 RL2_PRIVATE int
rl2_decode_webp_scaled(int scale,const unsigned char * webp,int webp_size,unsigned int * xwidth,unsigned int * xheight,unsigned char pixel_type,unsigned char ** pixels,int * pixels_size,unsigned char ** xmask,int * xmask_size)416 rl2_decode_webp_scaled (int scale, const unsigned char *webp, int webp_size,
417 unsigned int *xwidth, unsigned int *xheight,
418 unsigned char pixel_type, unsigned char **pixels,
419 int *pixels_size, unsigned char **xmask,
420 int *xmask_size)
421 {
422 /* attempting to create a raster from a WebP image - supporting rescaled size */
423 unsigned char *buf = NULL;
424 int buf_size = 0;
425 unsigned char *mask = NULL;
426 int mask_size = 0;
427 unsigned char *p_in;
428 unsigned char *p_out;
429 unsigned char *p_mask;
430 unsigned int width;
431 unsigned int height;
432 unsigned int row;
433 unsigned int col;
434 WebPBitstreamFeatures features;
435 WebPDecoderConfig config;
436
437 if (scale == 1 || scale == 2 || scale == 4 || scale == 8)
438 ;
439 else
440 return RL2_ERROR;
441
442 if (WebPGetFeatures (webp, webp_size, &features) != VP8_STATUS_OK)
443 return RL2_ERROR;
444
445 /* decoder options */
446 WebPInitDecoderConfig (&config);
447 if (scale == 1)
448 {
449 config.options.no_fancy_upsampling = 1;
450 config.options.use_scaling = 0;
451 width = features.width;
452 height = features.height;
453 }
454 else
455 {
456 config.options.no_fancy_upsampling = 1;
457 config.options.use_scaling = 1;
458 width = features.width / scale;
459 height = features.height / scale;
460 config.options.scaled_width = width;
461 config.options.scaled_height = height;
462 }
463 if (features.has_alpha)
464 {
465 config.output.colorspace = MODE_RGBA;
466 buf_size = width * height * 4;
467 buf = malloc (buf_size);
468 if (buf == NULL)
469 goto error;
470 config.output.u.RGBA.rgba = (uint8_t *) buf;
471 config.output.u.RGBA.stride = width * 4;
472 config.output.u.RGBA.size = buf_size;
473 config.output.is_external_memory = 1;
474 }
475 else
476 {
477 config.output.colorspace = MODE_RGB;
478 buf_size = width * height * 3;
479 buf = malloc (buf_size);
480 if (buf == NULL)
481 goto error;
482 config.output.u.RGBA.rgba = (uint8_t *) buf;
483 config.output.u.RGBA.stride = width * 3;
484 config.output.u.RGBA.size = buf_size;
485 config.output.is_external_memory = 1;
486 }
487
488 if (features.has_alpha)
489 {
490 if (WebPDecode (webp, webp_size, &config) != VP8_STATUS_OK)
491 goto error;
492 buf_size = width * height * 3;
493 mask_size = width * height;
494 mask = malloc (mask_size);
495 if (mask == NULL)
496 goto error;
497 p_mask = mask;
498 p_in = buf;
499 p_out = buf;
500 for (row = 0; row < height; row++)
501 {
502 for (col = 0; col < width; col++)
503 {
504 *p_out++ = *p_in++;
505 *p_out++ = *p_in++;
506 *p_out++ = *p_in++;
507 if (*p_in++ < 128)
508 *p_mask++ = 0;
509 else
510 *p_mask++ = 1;
511 }
512 }
513 }
514 else
515 {
516 if (WebPDecode (webp, webp_size, &config) != VP8_STATUS_OK)
517 goto error;
518 mask = NULL;
519 mask_size = 0;
520 }
521
522 if (pixel_type == RL2_PIXEL_GRAYSCALE)
523 {
524 /* returning a GRAYSCALE pixel buffer */
525 unsigned char *gray = NULL;
526 int gray_size = width * height;
527 gray = malloc (gray_size);
528 if (gray == NULL)
529 goto error;
530 p_in = buf;
531 p_out = gray;
532 for (row = 0; row < height; row++)
533 {
534 for (col = 0; col < width; col++)
535 {
536 *p_out++ = *p_in;
537 p_in += 3;
538 }
539 }
540 free (buf);
541 buf = gray;
542 buf_size = gray_size;
543 }
544
545 *xwidth = width;
546 *xheight = height;
547 *pixels = buf;
548 *pixels_size = buf_size;
549 *xmask = mask;
550 *xmask_size = mask_size;
551 return RL2_OK;
552
553 error:
554 if (buf != NULL)
555 free (buf);
556 if (mask != NULL)
557 free (mask);
558 return RL2_ERROR;
559 }
560