BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / translators / webp / WebPTranslator.cpp
blobd3592e87a883aa1a7dafcb83731b13eb84dc44f9
1 /*
2 * Copyright 2010-2011, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Philippe Houdoin
7 */
10 #include "WebPTranslator.h"
12 #include <BufferIO.h>
13 #include <Catalog.h>
14 #include <Messenger.h>
15 #include <TranslatorRoster.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
21 #include "webp/encode.h"
22 #include "webp/decode.h"
24 #include "ConfigView.h"
25 #include "TranslatorSettings.h"
28 #undef B_TRANSLATION_CONTEXT
29 #define B_TRANSLATION_CONTEXT "WebPTranslator"
32 class FreeAllocation {
33 public:
34 FreeAllocation(void* buffer)
36 fBuffer(buffer)
40 ~FreeAllocation()
42 free(fBuffer);
45 private:
46 void* fBuffer;
51 // The input formats that this translator knows how to read
52 static const translation_format sInputFormats[] = {
54 WEBP_IMAGE_FORMAT,
55 B_TRANSLATOR_BITMAP,
56 WEBP_IN_QUALITY,
57 WEBP_IN_CAPABILITY,
58 "image/webp",
59 "WebP image"
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)"
71 // The output formats that this translator knows how to write
72 static const translation_format sOutputFormats[] = {
74 WEBP_IMAGE_FORMAT,
75 B_TRANSLATOR_BITMAP,
76 WEBP_OUT_QUALITY,
77 WEBP_OUT_CAPABILITY,
78 "image/webp",
79 "WebP image"
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)"
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 },
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);
109 // #pragma mark -
112 WebPTranslator::WebPTranslator()
113 : BaseTranslator(B_TRANSLATE("WebP images"),
114 B_TRANSLATE("WebP image translator"),
115 WEBP_TRANSLATOR_VERSION,
116 sInputFormats, kNumInputFormats,
117 sOutputFormats, kNumOutputFormats,
118 "WebPTranslator_Settings", sDefaultSettings, kNumDefaultSettings,
119 B_TRANSLATOR_BITMAP, WEBP_IMAGE_FORMAT)
124 WebPTranslator::~WebPTranslator()
129 status_t
130 WebPTranslator::DerivedIdentify(BPositionIO* stream,
131 const translation_format* format, BMessage* settings,
132 translator_info* info, uint32 outType)
134 if (!outType)
135 outType = B_TRANSLATOR_BITMAP;
136 if (outType != B_TRANSLATOR_BITMAP)
137 return B_NO_TRANSLATOR;
139 // Check RIFF and 'WEBPVP8 ' signatures...
140 uint32 buf[4];
141 ssize_t size = 16;
142 if (stream->Read(buf, size) != size)
143 return B_IO_ERROR;
145 const uint32 kRIFFMagic = B_HOST_TO_BENDIAN_INT32('RIFF');
146 const uint32 kWEBPMagic = B_HOST_TO_BENDIAN_INT32('WEBP');
147 const uint32 kVP8Magic = B_HOST_TO_BENDIAN_INT32('VP8 ');
148 if (buf[0] != kRIFFMagic || buf[2] != kWEBPMagic || buf[3] != kVP8Magic)
149 return B_ILLEGAL_DATA;
151 info->type = WEBP_IMAGE_FORMAT;
152 info->group = B_TRANSLATOR_BITMAP;
153 info->quality = WEBP_IN_QUALITY;
154 info->capability = WEBP_IN_CAPABILITY;
155 snprintf(info->name, sizeof(info->name), B_TRANSLATE("WebP image"));
156 strcpy(info->MIME, "image/webp");
158 return B_OK;
162 status_t
163 WebPTranslator::DerivedTranslate(BPositionIO* stream,
164 const translator_info* info, BMessage* ioExtension,
165 uint32 outType, BPositionIO* target, int32 baseType)
167 if (baseType == 1)
168 // if stream is in bits format
169 return _TranslateFromBits(stream, ioExtension, outType, target);
170 else if (baseType == 0)
171 // if stream is NOT in bits format
172 return _TranslateFromWebP(stream, ioExtension, outType, target);
173 else
174 // if BaseTranslator dit not properly identify the data as
175 // bits or not bits
176 return B_NO_TRANSLATOR;
180 BView*
181 WebPTranslator::NewConfigView(TranslatorSettings* settings)
183 return new ConfigView(settings);
187 status_t
188 WebPTranslator::_TranslateFromBits(BPositionIO* stream, BMessage* ioExtension,
189 uint32 outType, BPositionIO* target)
191 if (!outType)
192 outType = WEBP_IMAGE_FORMAT;
193 if (outType != WEBP_IMAGE_FORMAT)
194 return B_NO_TRANSLATOR;
196 TranslatorBitmap bitsHeader;
197 status_t status;
199 status = identify_bits_header(stream, NULL, &bitsHeader);
200 if (status != B_OK)
201 return status;
203 if (bitsHeader.colors == B_CMAP8) {
204 // TODO: support whatever colospace by intermediate colorspace conversion
205 printf("Error! Colorspace not supported\n");
206 return B_NO_TRANSLATOR;
209 int32 bitsBytesPerPixel = 0;
210 switch (bitsHeader.colors) {
211 case B_RGB32:
212 case B_RGB32_BIG:
213 case B_RGBA32:
214 case B_RGBA32_BIG:
215 case B_CMY32:
216 case B_CMYA32:
217 case B_CMYK32:
218 bitsBytesPerPixel = 4;
219 break;
221 case B_RGB24:
222 case B_RGB24_BIG:
223 case B_CMY24:
224 bitsBytesPerPixel = 3;
225 break;
227 case B_RGB16:
228 case B_RGB16_BIG:
229 case B_RGBA15:
230 case B_RGBA15_BIG:
231 case B_RGB15:
232 case B_RGB15_BIG:
233 bitsBytesPerPixel = 2;
234 break;
236 case B_CMAP8:
237 case B_GRAY8:
238 bitsBytesPerPixel = 1;
239 break;
241 default:
242 return B_ERROR;
245 if (bitsBytesPerPixel < 3) {
246 // TODO support
247 return B_NO_TRANSLATOR;
250 WebPPicture picture;
251 WebPConfig config;
253 if (!WebPPictureInit(&picture) || !WebPConfigInit(&config)) {
254 printf("Error! Version mismatch!\n");
255 return B_ERROR;
258 WebPPreset preset = (WebPPreset)fSettings->SetGetInt32(WEBP_SETTING_PRESET);
259 config.quality = (float)fSettings->SetGetInt32(WEBP_SETTING_QUALITY);
261 if (!WebPConfigPreset(&config, (WebPPreset)preset, config.quality)) {
262 printf("Error! Could initialize configuration with preset.");
263 return B_ERROR;
266 config.method = fSettings->SetGetInt32(WEBP_SETTING_METHOD);
267 config.preprocessing = fSettings->SetGetBool(WEBP_SETTING_PREPROCESSING);
269 if (!WebPValidateConfig(&config)) {
270 printf("Error! Invalid configuration.\n");
271 return B_ERROR;
274 picture.width = bitsHeader.bounds.IntegerWidth() + 1;
275 picture.height = bitsHeader.bounds.IntegerHeight() + 1;
277 int stride = bitsHeader.rowBytes;
278 int bitsSize = picture.height * stride;
279 uint8* bits = (uint8*)malloc(bitsSize);
280 if (bits == NULL)
281 return B_NO_MEMORY;
283 if (stream->Read(bits, bitsSize) != bitsSize) {
284 free(bits);
285 return B_IO_ERROR;
288 if (!WebPPictureImportBGRA(&picture, bits, stride)) {
289 printf("Error! WebPEncode() failed!\n");
290 free(bits);
291 return B_ERROR;
293 free(bits);
295 picture.writer = _EncodedWriter;
296 picture.custom_ptr = target;
297 picture.stats = NULL;
299 if (!WebPEncode(&config, &picture)) {
300 printf("Error! WebPEncode() failed!\n");
301 status = B_NO_TRANSLATOR;
302 } else
303 status = B_OK;
305 WebPPictureFree(&picture);
306 return status;
310 status_t
311 WebPTranslator::_TranslateFromWebP(BPositionIO* stream, BMessage* ioExtension,
312 uint32 outType, BPositionIO* target)
314 if (!outType)
315 outType = B_TRANSLATOR_BITMAP;
316 if (outType != B_TRANSLATOR_BITMAP)
317 return B_NO_TRANSLATOR;
319 off_t streamLength = 0;
320 stream->GetSize(&streamLength);
322 off_t streamSize = stream->Seek(0, SEEK_END);
323 stream->Seek(0, SEEK_SET);
325 void* streamData = malloc(streamSize);
326 if (streamData == NULL)
327 return B_NO_MEMORY;
329 if (stream->Read(streamData, streamSize) != streamSize) {
330 free(streamData);
331 return B_IO_ERROR;
334 int width, height;
335 uint8* out = WebPDecodeBGRA((const uint8*)streamData, streamSize, &width,
336 &height);
337 free(streamData);
339 if (out == NULL)
340 return B_ILLEGAL_DATA;
342 FreeAllocation _(out);
344 uint32 dataSize = width * 4 * height;
346 TranslatorBitmap bitmapHeader;
347 bitmapHeader.magic = B_TRANSLATOR_BITMAP;
348 bitmapHeader.bounds.Set(0, 0, width - 1, height - 1);
349 bitmapHeader.rowBytes = width * 4;
350 bitmapHeader.colors = B_RGBA32;
351 bitmapHeader.dataSize = width * 4 * height;
353 // write out Be's Bitmap header
354 swap_data(B_UINT32_TYPE, &bitmapHeader, sizeof(TranslatorBitmap),
355 B_SWAP_HOST_TO_BENDIAN);
356 ssize_t bytesWritten = target->Write(&bitmapHeader,
357 sizeof(TranslatorBitmap));
358 if (bytesWritten < B_OK)
359 return bytesWritten;
361 if ((size_t)bytesWritten != sizeof(TranslatorBitmap))
362 return B_IO_ERROR;
364 bool headerOnly = false;
365 if (ioExtension != NULL)
366 ioExtension->FindBool(B_TRANSLATOR_EXT_HEADER_ONLY, &headerOnly);
368 if (headerOnly)
369 return B_OK;
371 uint32 dataLeft = dataSize;
372 uint8* p = out;
373 while (dataLeft) {
374 bytesWritten = target->Write(p, 4);
375 if (bytesWritten < B_OK)
376 return bytesWritten;
378 if (bytesWritten != 4)
379 return B_IO_ERROR;
381 p += 4;
382 dataLeft -= 4;
385 return B_OK;
389 /* static */ int
390 WebPTranslator::_EncodedWriter(const uint8_t* data, size_t dataSize,
391 const WebPPicture* const picture)
393 BPositionIO* target = (BPositionIO*)picture->custom_ptr;
394 return dataSize ? (target->Write(data, dataSize) == (ssize_t)dataSize) : 1;
398 // #pragma mark -
401 BTranslator*
402 make_nth_translator(int32 n, image_id you, uint32 flags, ...)
404 if (n != 0)
405 return NULL;
407 return new WebPTranslator();