1 /* File: loader_webp.c
2    Time-stamp: <2012-12-09 21:19:30 gawen>
3 
4    Copyright (c) 2011 David Hauweele <david@hauweele.net>
5    All rights reserved.
6 
7    Redistribution and use in source and binary forms, with or without
8    modification, are permitted provided that the following conditions
9    are met:
10    1. Redistributions of source code must retain the above copyright
11       notice, this list of conditions and the following disclaimer.
12    2. Redistributions in binary form must reproduce the above copyright
13       notice, this list of conditions and the following disclaimer in the
14       documentation and/or other materials provided with the distribution.
15    3. Neither the name of the University nor the names of its contributors
16       may be used to endorse or promote products derived from this software
17       without specific prior written permission.
18 
19    THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22    ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29    SUCH DAMAGE. */
30 
31 #define _BSD_SOURCE 1
32 
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <fcntl.h>
39 
40 #include <webp/decode.h>
41 #include <webp/encode.h>
42 #include <Imlib2.h>
43 
44 #include "imlib2_common.h"
45 #include "loader.h"
46 
read_file(const char * filename,size_t * size,ImlibProgressFunction progress)47 static uint8_t * read_file(const char *filename, size_t *size,
48                            ImlibProgressFunction progress)
49 {
50   struct stat buf;
51   uint8_t *data = NULL;
52   int fd;
53 
54 #ifndef __EMX__
55   if((fd = open(filename, O_RDONLY)) < 0)
56 #else
57   if((fd = open(filename, O_RDONLY | O_BINARY)) < 0)
58 #endif
59     return NULL;
60 
61   if(fstat(fd, &buf) < 0 ||
62      !(data = malloc(buf.st_size)))
63     goto EXIT;
64 
65   *size = read(fd, data, buf.st_size);
66 
67 EXIT:
68   close(fd);
69   return data;
70 }
71 
load(ImlibImage * im,ImlibProgressFunction progress,char progress_granularity,char immediate_load)72 char load(ImlibImage * im, ImlibProgressFunction progress,
73           char progress_granularity, char immediate_load)
74 {
75   uint8_t *data;
76   size_t size;
77   int w,h;
78   int has_alpha;
79 #if (WEBP_DECODER_ABI_VERSION >= 0x200)
80   WebPBitstreamFeatures features;
81 #endif
82   char ret = 0;
83 
84   if(im->data)
85     return 0;
86 
87   if(!(data = read_file(im->real_file, &size, progress)))
88     return 0;
89 
90 #if (WEBP_DECODER_ABI_VERSION >= 0x200)
91   if(WebPGetFeatures(data, size, &features) != VP8_STATUS_OK)
92     goto EXIT;
93   w = features.width;
94   h = features.height;
95   has_alpha = features.has_alpha;
96 #else /* compatibility with versions <= 0.1.3 */
97   if (!WebPGetInfo(data, size, &w, &h))
98     goto EXIT;
99   has_alpha = 0;
100 #endif
101 
102   if(!im->loader && !im->data) {
103     im->w = w;
104     im->h = h;
105 
106     if(!IMAGE_DIMENSIONS_OK(w, h))
107       goto EXIT;
108 
109     if(!has_alpha)
110       UNSET_FLAGS(im->flags, F_HAS_ALPHA);
111     else
112       SET_FLAGS(im->flags, F_HAS_ALPHA);
113     im->format = strdup("webp");
114   }
115 
116   if((!im->data && im->loader) || immediate_load || progress)
117      im->data = (DATA32*)WebPDecodeBGRA(data, size, &w, &h);
118 
119   if(progress)
120     progress(im, 100, 0, 0, 0, 0);
121 
122   ret = 1;
123 
124 EXIT:
125   free(data);
126   return ret;
127 }
128 
save(ImlibImage * im,ImlibProgressFunction progress,char progress_granularity)129 char save(ImlibImage *im, ImlibProgressFunction progress,
130           char progress_granularity)
131 {
132   ImlibImageTag *tag;
133   uint8_t *data;
134   float fqual;
135   size_t size;
136   int fd;
137   int quality = 75;
138   char ret = 0;
139 
140   if(!im->data)
141     return 0;
142 
143 #ifndef __EMX__
144   if((fd = open(im->real_file, O_WRONLY | O_CREAT,
145                 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) < 0)
146 #else
147   if((fd = open(im->real_file, O_WRONLY | O_CREAT | O_BINARY,
148                 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) < 0)
149 #endif
150     return 0;
151 
152   /* look for tags attached to image to get extra parameters like quality
153      settings etc. - this is the "api" to hint for extra information for
154      saver modules */
155   tag = __imlib_GetTag(im, "compression");
156   if(tag) {
157     int compression = tag->val;
158 
159     if(compression < 0)
160       compression = 0;
161     else if(compression > 9)
162       compression = 9;
163 
164     quality = (9 - compression) * 10;
165     quality = quality * 10 / 9;
166   }
167   tag = __imlib_GetTag(im, "quality");
168   if(tag) {
169     quality = tag->val;
170 
171     if(quality < 1)
172       quality = 1;
173     else if(quality > 100)
174       quality = 100;
175   }
176 
177   fqual = (float)quality;
178 
179   if(!(size = WebPEncodeBGRA((const uint8_t *)im->data, im->w, im->h,
180                              im->w << 2, fqual, &data)))
181     goto EXIT;
182 
183   if(write(fd, data, size) != size)
184     goto EXIT;
185 
186   if(progress)
187     progress(im, 100, 0, 0, 0, 0);
188 
189   ret = 1;
190 
191 EXIT:
192   close(fd);
193   if(data)
194     free(data);
195   return ret;
196 }
197 
formats(ImlibLoader * l)198 void formats(ImlibLoader *l)
199 {
200   int i;
201   char *list_formats[] = { "webp" };
202 
203   l->num_formats = (sizeof(list_formats) / sizeof(char *));
204   l->formats     = malloc(sizeof(char *) * l->num_formats);
205   for(i = 0 ; i < l->num_formats ; i++)
206     l->formats[i] = strdup(list_formats[i]);
207 }
208