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