1 /*
2 * Copyright 2010-2011, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Philippe Houdoin
7 */
8
9
10 #include "WebPTranslator.h"
11
12 #include <BufferIO.h>
13 #include <Catalog.h>
14 #include <Messenger.h>
15 #include <TranslatorRoster.h>
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include "webp/encode.h"
22 #include "webp/decode.h"
23
24 #include "ConfigView.h"
25 #include "TranslatorSettings.h"
26
27
28 #undef B_TRANSLATION_CONTEXT
29 #define B_TRANSLATION_CONTEXT "WebPTranslator"
30
31
32 class FreeAllocation {
33 public:
FreeAllocation(void * buffer)34 FreeAllocation(void* buffer)
35 :
36 fBuffer(buffer)
37 {
38 }
39
~FreeAllocation()40 ~FreeAllocation()
41 {
42 free(fBuffer);
43 }
44
45 private:
46 void* fBuffer;
47 };
48
49
50
51 // The input formats that this translator knows how to read
52 static const translation_format sInputFormats[] = {
53 {
54 WEBP_IMAGE_FORMAT,
55 B_TRANSLATOR_BITMAP,
56 WEBP_IN_QUALITY,
57 WEBP_IN_CAPABILITY,
58 "image/webp",
59 "WebP image"
60 },
61 {
62 B_TRANSLATOR_BITMAP,
63 B_TRANSLATOR_BITMAP,
64 BITS_IN_QUALITY,
65 BITS_IN_CAPABILITY,
66 "image/x-be-bitmap",
67 "Be Bitmap Format (WebPTranslator)"
68 },
69 };
70
71 // The output formats that this translator knows how to write
72 static const translation_format sOutputFormats[] = {
73 {
74 WEBP_IMAGE_FORMAT,
75 B_TRANSLATOR_BITMAP,
76 WEBP_OUT_QUALITY,
77 WEBP_OUT_CAPABILITY,
78 "image/webp",
79 "WebP image"
80 },
81 {
82 B_TRANSLATOR_BITMAP,
83 B_TRANSLATOR_BITMAP,
84 BITS_OUT_QUALITY,
85 BITS_OUT_CAPABILITY,
86 "image/x-be-bitmap",
87 "Be Bitmap Format (WebPTranslator)"
88 },
89 };
90
91 // Default settings for the Translator
92 static const TranSetting sDefaultSettings[] = {
93 { B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false },
94 { B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false },
95 { WEBP_SETTING_QUALITY, TRAN_SETTING_INT32, 60 },
96 { WEBP_SETTING_PRESET, TRAN_SETTING_INT32, 0 },
97 { WEBP_SETTING_METHOD, TRAN_SETTING_INT32, 2 },
98 { WEBP_SETTING_PREPROCESSING, TRAN_SETTING_BOOL, false },
99 };
100
101 const uint32 kNumInputFormats = sizeof(sInputFormats) /
102 sizeof(translation_format);
103 const uint32 kNumOutputFormats = sizeof(sOutputFormats) /
104 sizeof(translation_format);
105 const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) /
106 sizeof(TranSetting);
107
108
109 // #pragma mark -
110
111
WebPTranslator()112 WebPTranslator::WebPTranslator()
113 :
114 BaseTranslator(B_TRANSLATE("WebP images"),
115 B_TRANSLATE("WebP image translator"),
116 WEBP_TRANSLATOR_VERSION,
117 sInputFormats, kNumInputFormats,
118 sOutputFormats, kNumOutputFormats,
119 "WebPTranslator_Settings", sDefaultSettings, kNumDefaultSettings,
120 B_TRANSLATOR_BITMAP, WEBP_IMAGE_FORMAT)
121 {
122 }
123
124
~WebPTranslator()125 WebPTranslator::~WebPTranslator()
126 {
127 }
128
129
130 status_t
DerivedIdentify(BPositionIO * stream,const translation_format * format,BMessage * settings,translator_info * info,uint32 outType)131 WebPTranslator::DerivedIdentify(BPositionIO* stream,
132 const translation_format* format, BMessage* settings,
133 translator_info* info, uint32 outType)
134 {
135 if (!outType)
136 outType = B_TRANSLATOR_BITMAP;
137 if (outType != B_TRANSLATOR_BITMAP)
138 return B_NO_TRANSLATOR;
139
140 // Read header and first chunck bytes...
141 uint32 buf[64];
142 ssize_t size = sizeof(buf);
143 if (stream->Read(buf, size) != size)
144 return B_IO_ERROR;
145
146 // Check it's a valid WebP format
147 if (!WebPGetInfo((const uint8_t*)buf, size, NULL, NULL))
148 return B_ILLEGAL_DATA;
149
150 info->type = WEBP_IMAGE_FORMAT;
151 info->group = B_TRANSLATOR_BITMAP;
152 info->quality = WEBP_IN_QUALITY;
153 info->capability = WEBP_IN_CAPABILITY;
154 strlcpy(info->name, B_TRANSLATE("WebP image"), sizeof(info->name));
155 strcpy(info->MIME, "image/webp");
156
157 return B_OK;
158 }
159
160
161 status_t
DerivedTranslate(BPositionIO * stream,const translator_info * info,BMessage * ioExtension,uint32 outType,BPositionIO * target,int32 baseType)162 WebPTranslator::DerivedTranslate(BPositionIO* stream,
163 const translator_info* info, BMessage* ioExtension, uint32 outType,
164 BPositionIO* target, int32 baseType)
165 {
166 if (baseType == 1)
167 // if stream is in bits format
168 return _TranslateFromBits(stream, ioExtension, outType, target);
169 else if (baseType == 0)
170 // if stream is NOT in bits format
171 return _TranslateFromWebP(stream, ioExtension, outType, target);
172 else
173 // if BaseTranslator dit not properly identify the data as
174 // bits or not bits
175 return B_NO_TRANSLATOR;
176 }
177
178
179 BView*
NewConfigView(TranslatorSettings * settings)180 WebPTranslator::NewConfigView(TranslatorSettings* settings)
181 {
182 return new ConfigView(settings);
183 }
184
185
186 status_t
_TranslateFromBits(BPositionIO * stream,BMessage * ioExtension,uint32 outType,BPositionIO * target)187 WebPTranslator::_TranslateFromBits(BPositionIO* stream, BMessage* ioExtension,
188 uint32 outType, BPositionIO* target)
189 {
190 if (!outType)
191 outType = WEBP_IMAGE_FORMAT;
192 if (outType != WEBP_IMAGE_FORMAT)
193 return B_NO_TRANSLATOR;
194
195 TranslatorBitmap bitsHeader;
196 status_t status;
197
198 status = identify_bits_header(stream, NULL, &bitsHeader);
199 if (status != B_OK)
200 return status;
201
202 if (bitsHeader.colors == B_CMAP8) {
203 // TODO: support whatever colospace by intermediate colorspace conversion
204 printf("Error! Colorspace not supported\n");
205 return B_NO_TRANSLATOR;
206 }
207
208 int32 bitsBytesPerPixel = 0;
209 switch (bitsHeader.colors) {
210 case B_RGB32:
211 case B_RGB32_BIG:
212 case B_RGBA32:
213 case B_RGBA32_BIG:
214 case B_CMY32:
215 case B_CMYA32:
216 case B_CMYK32:
217 bitsBytesPerPixel = 4;
218 break;
219
220 case B_RGB24:
221 case B_RGB24_BIG:
222 case B_CMY24:
223 bitsBytesPerPixel = 3;
224 break;
225
226 case B_RGB16:
227 case B_RGB16_BIG:
228 case B_RGBA15:
229 case B_RGBA15_BIG:
230 case B_RGB15:
231 case B_RGB15_BIG:
232 bitsBytesPerPixel = 2;
233 break;
234
235 case B_CMAP8:
236 case B_GRAY8:
237 bitsBytesPerPixel = 1;
238 break;
239
240 default:
241 return B_ERROR;
242 }
243
244 if (bitsBytesPerPixel < 3) {
245 // TODO support
246 return B_NO_TRANSLATOR;
247 }
248
249 WebPPicture picture;
250 WebPConfig config;
251
252 if (!WebPPictureInit(&picture) || !WebPConfigInit(&config)) {
253 printf("Error! Version mismatch!\n");
254 return B_ERROR;
255 }
256
257 WebPPreset preset = (WebPPreset)fSettings->SetGetInt32(WEBP_SETTING_PRESET);
258 config.quality = (float)fSettings->SetGetInt32(WEBP_SETTING_QUALITY);
259
260 if (!WebPConfigPreset(&config, (WebPPreset)preset, config.quality)) {
261 printf("Error! Could initialize configuration with preset.");
262 return B_ERROR;
263 }
264
265 config.method = fSettings->SetGetInt32(WEBP_SETTING_METHOD);
266 config.preprocessing = fSettings->SetGetBool(WEBP_SETTING_PREPROCESSING);
267
268 if (!WebPValidateConfig(&config)) {
269 printf("Error! Invalid configuration.\n");
270 return B_ERROR;
271 }
272
273 picture.width = bitsHeader.bounds.IntegerWidth() + 1;
274 picture.height = bitsHeader.bounds.IntegerHeight() + 1;
275
276 int stride = bitsHeader.rowBytes;
277 int bitsSize = picture.height * stride;
278 uint8* bits = (uint8*)malloc(bitsSize);
279 if (bits == NULL)
280 return B_NO_MEMORY;
281
282 if (stream->Read(bits, bitsSize) != bitsSize) {
283 free(bits);
284 return B_IO_ERROR;
285 }
286
287 if (!WebPPictureImportBGRA(&picture, bits, stride)) {
288 printf("Error! WebPEncode() failed!\n");
289 free(bits);
290 return B_ERROR;
291 }
292 free(bits);
293
294 picture.writer = _EncodedWriter;
295 picture.custom_ptr = target;
296 picture.stats = NULL;
297
298 if (!WebPEncode(&config, &picture)) {
299 printf("Error! WebPEncode() failed!\n");
300 status = B_NO_TRANSLATOR;
301 } else
302 status = B_OK;
303
304 WebPPictureFree(&picture);
305 return status;
306 }
307
308
309 status_t
_TranslateFromWebP(BPositionIO * stream,BMessage * ioExtension,uint32 outType,BPositionIO * target)310 WebPTranslator::_TranslateFromWebP(BPositionIO* stream, BMessage* ioExtension,
311 uint32 outType, BPositionIO* target)
312 {
313 if (!outType)
314 outType = B_TRANSLATOR_BITMAP;
315 if (outType != B_TRANSLATOR_BITMAP)
316 return B_NO_TRANSLATOR;
317
318 off_t streamLength = 0;
319 stream->GetSize(&streamLength);
320
321 off_t streamSize = stream->Seek(0, SEEK_END);
322 stream->Seek(0, SEEK_SET);
323
324 void* streamData = malloc(streamSize);
325 if (streamData == NULL)
326 return B_NO_MEMORY;
327
328 if (stream->Read(streamData, streamSize) != streamSize) {
329 free(streamData);
330 return B_IO_ERROR;
331 }
332
333 int width, height;
334 uint8* out = WebPDecodeBGRA((const uint8*)streamData, streamSize, &width,
335 &height);
336 free(streamData);
337
338 if (out == NULL)
339 return B_ILLEGAL_DATA;
340
341 FreeAllocation _(out);
342
343 uint32 dataSize = width * 4 * height;
344
345 TranslatorBitmap bitmapHeader;
346 bitmapHeader.magic = B_TRANSLATOR_BITMAP;
347 bitmapHeader.bounds.Set(0, 0, width - 1, height - 1);
348 bitmapHeader.rowBytes = width * 4;
349 bitmapHeader.colors = B_RGBA32;
350 bitmapHeader.dataSize = width * 4 * height;
351
352 // write out Be's Bitmap header
353 swap_data(B_UINT32_TYPE, &bitmapHeader, sizeof(TranslatorBitmap),
354 B_SWAP_HOST_TO_BENDIAN);
355 ssize_t bytesWritten = target->Write(&bitmapHeader,
356 sizeof(TranslatorBitmap));
357 if (bytesWritten < B_OK)
358 return bytesWritten;
359
360 if ((size_t)bytesWritten != sizeof(TranslatorBitmap))
361 return B_IO_ERROR;
362
363 bool headerOnly = false;
364 if (ioExtension != NULL)
365 ioExtension->FindBool(B_TRANSLATOR_EXT_HEADER_ONLY, &headerOnly);
366
367 if (headerOnly)
368 return B_OK;
369
370 uint32 dataLeft = dataSize;
371 uint8* p = out;
372 while (dataLeft) {
373 bytesWritten = target->Write(p, 4);
374 if (bytesWritten < B_OK)
375 return bytesWritten;
376
377 if (bytesWritten != 4)
378 return B_IO_ERROR;
379
380 p += 4;
381 dataLeft -= 4;
382 }
383
384 return B_OK;
385 }
386
387
388 /* static */ int
_EncodedWriter(const uint8_t * data,size_t dataSize,const WebPPicture * const picture)389 WebPTranslator::_EncodedWriter(const uint8_t* data, size_t dataSize,
390 const WebPPicture* const picture)
391 {
392 BPositionIO* target = (BPositionIO*)picture->custom_ptr;
393 return dataSize ? (target->Write(data, dataSize) == (ssize_t)dataSize) : 1;
394 }
395
396
397 // #pragma mark -
398
399
400 BTranslator*
make_nth_translator(int32 n,image_id you,uint32 flags,...)401 make_nth_translator(int32 n, image_id you, uint32 flags, ...)
402 {
403 if (n != 0)
404 return NULL;
405
406 return new WebPTranslator();
407 }
408