Author: phoudoin Date: 2011-03-08 16:27:33 +0100 (Tue, 08 Mar 2011) New Revision: 40869 Changeset: http://dev.haiku-os.org/changeset/40869 Modified: haiku/trunk/src/add-ons/translators/webp/ConfigView.cpp haiku/trunk/src/add-ons/translators/webp/ConfigView.h haiku/trunk/src/add-ons/translators/webp/Jamfile haiku/trunk/src/add-ons/translators/webp/WebPTranslator.cpp haiku/trunk/src/add-ons/translators/webp/WebPTranslator.h Log: Add WebP write support. Modified: haiku/trunk/src/add-ons/translators/webp/ConfigView.cpp =================================================================== --- haiku/trunk/src/add-ons/translators/webp/ConfigView.cpp 2011-03-08 15:26:16 UTC (rev 40868) +++ haiku/trunk/src/add-ons/translators/webp/ConfigView.cpp 2011-03-08 15:27:33 UTC (rev 40869) @@ -1,5 +1,5 @@ /* - * Copyright 2010, Haiku, Inc. All rights reserved. + * Copyright 2010-2011, Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -8,23 +8,54 @@ #include "ConfigView.h" -#include "WebPTranslator.h" +#include <stdio.h> +#include <string.h> + #include <Catalog.h> #include <CheckBox.h> +#include <GridLayoutBuilder.h> #include <GroupLayout.h> #include <GroupLayoutBuilder.h> +#include <MenuField.h> +#include <MenuItem.h> +#include <Message.h> +#include <PopUpMenu.h> +#include <Slider.h> #include <StringView.h> +#include <TextView.h> -#include <stdio.h> -#include <string.h> +#include "webp/encode.h" +#include "TranslatorSettings.h" +#include "WebPTranslator.h" + + #undef B_TRANSLATE_CONTEXT #define B_TRANSLATE_CONTEXT "ConfigView" +static const uint32 kMsgQuality = 'qlty'; +static const uint32 kMsgPreset = 'prst'; +static const uint32 kMsgMethod = 'metd'; +static const uint32 kMsgPreprocessing = 'pprc'; -ConfigView::ConfigView(uint32 flags) - : BView(B_TRANSLATE("WebPTranslator Settings"), flags) +static const struct preset_name { + const char* name; + WebPPreset id; +} kPresetNames[] = { + { B_TRANSLATE("Default"), WEBP_PRESET_DEFAULT }, + { B_TRANSLATE("Picture"), WEBP_PRESET_PICTURE }, + { B_TRANSLATE("Photo"), WEBP_PRESET_PHOTO }, + { B_TRANSLATE("Drawing"), WEBP_PRESET_DRAWING }, + { B_TRANSLATE("Icon"), WEBP_PRESET_ICON }, + { B_TRANSLATE("Text"), WEBP_PRESET_TEXT }, + { NULL }, +}; + + +ConfigView::ConfigView(TranslatorSettings* settings, uint32 flags) + : BView(B_TRANSLATE("WebPTranslator Settings"), flags), + fSettings(settings) { SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); @@ -32,45 +63,147 @@ title->SetFont(be_bold_font); char versionString[256]; - sprintf(versionString, B_TRANSLATE("Version %d.%d.%d, %s"), + sprintf(versionString, "v%d.%d.%d", static_cast<int>(B_TRANSLATION_MAJOR_VERSION(WEBP_TRANSLATOR_VERSION)), static_cast<int>(B_TRANSLATION_MINOR_VERSION(WEBP_TRANSLATOR_VERSION)), static_cast<int>(B_TRANSLATION_REVISION_VERSION( - WEBP_TRANSLATOR_VERSION)), __DATE__); + WEBP_TRANSLATOR_VERSION))); + BStringView* version = new BStringView("version", versionString); - BStringView* copyright = new BStringView("copyright", - B_UTF8_COPYRIGHT "2010 Haiku Inc."); + BString copyrightsText; + copyrightsText << B_TRANSLATE(B_UTF8_COPYRIGHT "2010-2011 Haiku Inc.") + << "\n" << B_TRANSLATE("Based on libwebp v0.1," ) + << "\n" << B_TRANSLATE(B_UTF8_COPYRIGHT "2010-2011 Google Inc."); - BStringView* copyright2 = new BStringView("copyright2", - B_TRANSLATE("Based on libwebp v0.1")); + BTextView* copyrights = new BTextView("copyrights"); + copyrights->SetText(copyrightsText); + copyrights->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + copyrights->MakeEditable(false); - BStringView* copyright3 = new BStringView("copyright3", - B_UTF8_COPYRIGHT "2010 Google Inc."); + // output parameters + fPresetsMenu = new BPopUpMenu(B_TRANSLATE("Preset")); + const struct preset_name* preset = kPresetNames; + while (preset->name != NULL) { + BMessage* msg = new BMessage(kMsgPreset); + msg->AddInt32("value", preset->id); + + BMenuItem* item = new BMenuItem(preset->name, msg); + if (fSettings->SetGetInt32(WEBP_SETTING_PRESET) == preset->id) + item->SetMarked(true); + fPresetsMenu->AddItem(item); + + preset++; + } + BMenuField* presetsField = new BMenuField(B_TRANSLATE("Output preset:"), + fPresetsMenu, NULL); + + fQualitySlider = new BSlider("quality", B_TRANSLATE("Output quality:"), + new BMessage(kMsgQuality), 0, 100, B_HORIZONTAL, B_BLOCK_THUMB); + fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM); + fQualitySlider->SetHashMarkCount(10); + fQualitySlider->SetLimitLabels(B_TRANSLATE("Low"), B_TRANSLATE("High")); + fQualitySlider->SetValue(fSettings->SetGetInt32(WEBP_SETTING_QUALITY)); + + fMethodSlider = new BSlider("method", B_TRANSLATE("Compression method:"), + new BMessage(kMsgMethod), 0, 6, B_HORIZONTAL, B_BLOCK_THUMB); + fMethodSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); + fMethodSlider->SetHashMarkCount(7); + fMethodSlider->SetLimitLabels(B_TRANSLATE("Fast"), + B_TRANSLATE("Slower but better")); + fMethodSlider->SetValue(fSettings->SetGetInt32(WEBP_SETTING_METHOD)); + + fPreprocessingCheckBox = new BCheckBox("preprocessing", + B_TRANSLATE("Preprocessing filter"), new BMessage(kMsgPreprocessing)); + if (fSettings->SetGetBool(WEBP_SETTING_PREPROCESSING)) + fPreprocessingCheckBox->SetValue(B_CONTROL_ON); + // Build the layout - SetLayout(new BGroupLayout(B_HORIZONTAL)); + SetLayout(new BGroupLayout(B_VERTICAL)); - AddChild(BGroupLayoutBuilder(B_VERTICAL, 7) - .Add(title) + AddChild(BGroupLayoutBuilder(B_VERTICAL) + .Add(BGroupLayoutBuilder(B_HORIZONTAL) + .Add(title) + .Add(version) + .AddGlue() + ) + .Add(copyrights) .AddGlue() - .Add(version) - .Add(copyright) - .AddGlue() - .Add(copyright2) - .Add(copyright3) - .AddGlue() + + // .Add(outputSeparator) + .Add(BGridLayoutBuilder() + .Add(presetsField->CreateLabelLayoutItem(), 0, 0) + .Add(presetsField->CreateMenuBarLayoutItem(), 1, 0) + ) + .Add(fQualitySlider) + .Add(fMethodSlider) + .Add(fPreprocessingCheckBox) + // .AddGlue() .SetInsets(5, 5, 5, 5) ); - - BFont font; - GetFont(&font); - SetExplicitPreferredSize(BSize(font.Size() * 233 / 12, - font.Size() * 200 / 12)); } ConfigView::~ConfigView() { + fSettings->Release(); } + +void +ConfigView::AttachedToWindow() +{ + BView::AttachedToWindow(); + + fPresetsMenu->SetTargetForItems(this); + + fQualitySlider->SetTarget(this); + fMethodSlider->SetTarget(this); + fPreprocessingCheckBox->SetTarget(this); +} + + +void +ConfigView::MessageReceived(BMessage* message) +{ + struct { + const char* name; + uint32 what; + TranSettingType type; + } maps[] = { + { WEBP_SETTING_PRESET, kMsgPreset, TRAN_SETTING_INT32 }, + { WEBP_SETTING_QUALITY, kMsgQuality, TRAN_SETTING_INT32 }, + { WEBP_SETTING_METHOD, kMsgMethod, TRAN_SETTING_INT32 }, + { WEBP_SETTING_PREPROCESSING, kMsgPreprocessing, TRAN_SETTING_BOOL }, + { NULL } + }; + + int i; + for (i = 0; maps[i].name != NULL; i++) { + if (maps[i].what == message->what) + break; + } + + if (maps[i].name == NULL) { + BView::MessageReceived(message); + return; + } + + int32 value; + if (message->FindInt32("value", &value) == B_OK + || message->FindInt32("be:value", &value) == B_OK) { + switch(maps[i].type) { + case TRAN_SETTING_BOOL: + { + bool boolValue = value; + fSettings->SetGetBool(maps[i].name, &boolValue); + break; + } + case TRAN_SETTING_INT32: + fSettings->SetGetInt32(maps[i].name, &value); + break; + } + fSettings->SaveSettings(); + } +} Modified: haiku/trunk/src/add-ons/translators/webp/ConfigView.h =================================================================== --- haiku/trunk/src/add-ons/translators/webp/ConfigView.h 2011-03-08 15:26:16 UTC (rev 40868) +++ haiku/trunk/src/add-ons/translators/webp/ConfigView.h 2011-03-08 15:27:33 UTC (rev 40869) @@ -1,5 +1,5 @@ /* - * Copyright 2010, Haiku. All rights reserved. + * Copyright 2010-2011, Haiku. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -11,11 +11,26 @@ #include <View.h> +class BCheckBox; +class BPopUpMenu; +class BSlider; +class TranslatorSettings; class ConfigView : public BView { public: - ConfigView(uint32 flags = B_WILL_DRAW); + ConfigView(TranslatorSettings* settings, + uint32 flags = B_WILL_DRAW); virtual ~ConfigView(); + + virtual void AttachedToWindow(); + virtual void MessageReceived(BMessage *message); + +private: + TranslatorSettings* fSettings; + BPopUpMenu* fPresetsMenu; + BSlider* fQualitySlider; + BSlider* fMethodSlider; + BCheckBox* fPreprocessingCheckBox; }; Modified: haiku/trunk/src/add-ons/translators/webp/Jamfile =================================================================== --- haiku/trunk/src/add-ons/translators/webp/Jamfile 2011-03-08 15:26:16 UTC (rev 40868) +++ haiku/trunk/src/add-ons/translators/webp/Jamfile 2011-03-08 15:27:33 UTC (rev 40869) @@ -16,6 +16,7 @@ : <libwebp>webpdecode.o + <libwebp>webpencode.o be translation libtranslatorsutils.a $(TARGET_LIBSUPC++) $(HAIKU_LOCALE_LIBS) : true Modified: haiku/trunk/src/add-ons/translators/webp/WebPTranslator.cpp =================================================================== --- haiku/trunk/src/add-ons/translators/webp/WebPTranslator.cpp 2011-03-08 15:26:16 UTC (rev 40868) +++ haiku/trunk/src/add-ons/translators/webp/WebPTranslator.cpp 2011-03-08 15:27:33 UTC (rev 40869) @@ -1,5 +1,5 @@ /* - * Copyright 2010, Haiku, Inc. All rights reserved. + * Copyright 2010-2011, Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -8,10 +8,7 @@ #include "WebPTranslator.h" -#include "ConfigView.h" -#include "webp/decode.h" - #include <BufferIO.h> #include <Catalog.h> #include <Messenger.h> @@ -21,7 +18,13 @@ #include <stdlib.h> #include <string.h> +#include "webp/encode.h" +#include "webp/decode.h" +#include "ConfigView.h" +#include "TranslatorSettings.h" + + #undef B_TRANSLATE_CONTEXT #define B_TRANSLATE_CONTEXT "WebPTranslator" @@ -45,7 +48,7 @@ -// The input formats that this translator supports. +// The input formats that this translator knows how to read static const translation_format sInputFormats[] = { { WEBP_IMAGE_FORMAT, @@ -55,13 +58,29 @@ "image/webp", "WebP image" }, + { + B_TRANSLATOR_BITMAP, + B_TRANSLATOR_BITMAP, + BITS_IN_QUALITY, + BITS_IN_CAPABILITY, + "image/x-be-bitmap", + "Be Bitmap Format (WebPTranslator)" + }, }; -// The output formats that this translator supports. +// The output formats that this translator knows how to write static const translation_format sOutputFormats[] = { { + WEBP_IMAGE_FORMAT, B_TRANSLATOR_BITMAP, + WEBP_OUT_QUALITY, + WEBP_OUT_CAPABILITY, + "image/webp", + "WebP image" + }, + { B_TRANSLATOR_BITMAP, + B_TRANSLATOR_BITMAP, BITS_OUT_QUALITY, BITS_OUT_CAPABILITY, "image/x-be-bitmap", @@ -71,8 +90,12 @@ // Default settings for the Translator static const TranSetting sDefaultSettings[] = { - {B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false}, - {B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false} + { B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false }, + { B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false }, + { WEBP_SETTING_QUALITY, TRAN_SETTING_INT32, 60 }, + { WEBP_SETTING_PRESET, TRAN_SETTING_INT32, 0 }, + { WEBP_SETTING_METHOD, TRAN_SETTING_INT32, 2 }, + { WEBP_SETTING_PREPROCESSING, TRAN_SETTING_BOOL, false }, }; const uint32 kNumInputFormats = sizeof(sInputFormats) / @@ -138,17 +161,163 @@ status_t WebPTranslator::DerivedTranslate(BPositionIO* stream, - const translator_info* info, BMessage* settings, + const translator_info* info, BMessage* ioExtension, uint32 outType, BPositionIO* target, int32 baseType) { + if (baseType == 1) + // if stream is in bits format + return _TranslateFromBits(stream, ioExtension, outType, target); + else if (baseType == 0) + // if stream is NOT in bits format + return _TranslateFromWebP(stream, ioExtension, outType, target); + else + // if BaseTranslator dit not properly identify the data as + // bits or not bits + return B_NO_TRANSLATOR; +} + + +BView* +WebPTranslator::NewConfigView(TranslatorSettings* settings) +{ + return new ConfigView(settings); +} + + +status_t +WebPTranslator::_TranslateFromBits(BPositionIO* stream, BMessage* ioExtension, + uint32 outType, BPositionIO* target) +{ if (!outType) + outType = WEBP_IMAGE_FORMAT; + if (outType != WEBP_IMAGE_FORMAT) + return B_NO_TRANSLATOR; + + TranslatorBitmap bitsHeader; + status_t status; + + status = identify_bits_header(stream, NULL, &bitsHeader); + if (status != B_OK) + return status; + + if (bitsHeader.colors == B_CMAP8) { + // TODO: support whatever colospace by intermediate colorspace conversion + printf("Error! Colorspace not supported\n"); + return B_NO_TRANSLATOR; + } + + int32 bitsBytesPerPixel = 0; + switch (bitsHeader.colors) { + case B_RGB32: + case B_RGB32_BIG: + case B_RGBA32: + case B_RGBA32_BIG: + case B_CMY32: + case B_CMYA32: + case B_CMYK32: + bitsBytesPerPixel = 4; + break; + + case B_RGB24: + case B_RGB24_BIG: + case B_CMY24: + bitsBytesPerPixel = 3; + break; + + case B_RGB16: + case B_RGB16_BIG: + case B_RGBA15: + case B_RGBA15_BIG: + case B_RGB15: + case B_RGB15_BIG: + bitsBytesPerPixel = 2; + break; + + case B_CMAP8: + case B_GRAY8: + bitsBytesPerPixel = 1; + break; + + default: + return B_ERROR; + } + + if (bitsBytesPerPixel < 3) { + // TODO support + return B_NO_TRANSLATOR; + } + + WebPPicture picture; + WebPConfig config; + + if (!WebPPictureInit(&picture) || !WebPConfigInit(&config)) { + printf("Error! Version mismatch!\n"); + return B_ERROR; + } + + WebPPreset preset = (WebPPreset)fSettings->SetGetInt32(WEBP_SETTING_PRESET); + config.quality = (float)fSettings->SetGetInt32(WEBP_SETTING_QUALITY); + + if (!WebPConfigPreset(&config, (WebPPreset)preset, config.quality)) { + printf("Error! Could initialize configuration with preset."); + return B_ERROR; + } + + config.method = fSettings->SetGetInt32(WEBP_SETTING_METHOD); + config.preprocessing = fSettings->SetGetBool(WEBP_SETTING_PREPROCESSING); + + if (!WebPValidateConfig(&config)) { + printf("Error! Invalid configuration.\n"); + return B_ERROR; + } + + picture.width = bitsHeader.bounds.IntegerWidth() + 1; + picture.height = bitsHeader.bounds.IntegerHeight() + 1; + + int stride = bitsHeader.rowBytes; + int bitsSize = picture.height * stride; + uint8* bits = (uint8*)malloc(bitsSize); + if (bits == NULL) + return B_NO_MEMORY; + + if (stream->Read(bits, bitsSize) != bitsSize) { + free(bits); + return B_IO_ERROR; + } + + if (!WebPPictureImportBGRA(&picture, bits, stride)) { + printf("Error! WebPEncode() failed!\n"); + free(bits); + return B_ERROR; + } + free(bits); + + picture.writer = _EncodedWriter; + picture.custom_ptr = target; + picture.stats = NULL; + + if (!WebPEncode(&config, &picture)) { + printf("Error! WebPEncode() failed!\n"); + status = B_NO_TRANSLATOR; + } else + status = B_OK; + + WebPPictureFree(&picture); + return status; +} + + +status_t +WebPTranslator::_TranslateFromWebP(BPositionIO* stream, BMessage* ioExtension, + uint32 outType, BPositionIO* target) +{ + if (!outType) outType = B_TRANSLATOR_BITMAP; - if (outType != B_TRANSLATOR_BITMAP || baseType != 0) + if (outType != B_TRANSLATOR_BITMAP) return B_NO_TRANSLATOR; off_t streamLength = 0; stream->GetSize(&streamLength); - printf(B_TRANSLATE("stream GetSize(): %lld\n"), streamLength); off_t streamSize = stream->Seek(0, SEEK_END); stream->Seek(0, SEEK_SET); @@ -163,7 +332,7 @@ } int width, height; - uint8* out = WebPDecodeRGB((const uint8*)streamData, streamSize, &width, + uint8* out = WebPDecodeBGRA((const uint8*)streamData, streamSize, &width, &height); free(streamData); @@ -172,14 +341,14 @@ FreeAllocation _(out); - uint32 dataSize = width * 3 * height; + uint32 dataSize = width * 4 * height; TranslatorBitmap bitmapHeader; bitmapHeader.magic = B_TRANSLATOR_BITMAP; bitmapHeader.bounds.Set(0, 0, width - 1, height - 1); - bitmapHeader.rowBytes = width * 3; - bitmapHeader.colors = B_RGB24; - bitmapHeader.dataSize = width * 3 * height; + bitmapHeader.rowBytes = width * 4; + bitmapHeader.colors = B_RGBA32; + bitmapHeader.dataSize = width * 4 * height; // write out Be's Bitmap header swap_data(B_UINT32_TYPE, &bitmapHeader, sizeof(TranslatorBitmap), @@ -193,40 +362,36 @@ return B_IO_ERROR; bool headerOnly = false; - if (settings != NULL) - settings->FindBool(B_TRANSLATOR_EXT_HEADER_ONLY, &headerOnly); + if (ioExtension != NULL) + ioExtension->FindBool(B_TRANSLATOR_EXT_HEADER_ONLY, &headerOnly); if (headerOnly) return B_OK; uint32 dataLeft = dataSize; uint8* p = out; - uint8 rgb[3]; while (dataLeft) { - rgb[0] = *(p+2); - rgb[1] = *(p+1); - rgb[2] = *(p); - - bytesWritten = target->Write(rgb, 3); + bytesWritten = target->Write(p, 4); if (bytesWritten < B_OK) return bytesWritten; - if (bytesWritten != 3) + if (bytesWritten != 4) return B_IO_ERROR; - p += 3; - dataLeft -= 3; + p += 4; + dataLeft -= 4; } return B_OK; } - -BView* -WebPTranslator::NewConfigView(TranslatorSettings* settings) +/* static */ int +WebPTranslator::_EncodedWriter(const uint8_t* data, size_t dataSize, + const WebPPicture* const picture) { - return new ConfigView(); + BPositionIO* target = (BPositionIO*)picture->custom_ptr; + return dataSize ? (target->Write(data, dataSize) == (ssize_t)dataSize) : 1; } Modified: haiku/trunk/src/add-ons/translators/webp/WebPTranslator.h =================================================================== --- haiku/trunk/src/add-ons/translators/webp/WebPTranslator.h 2011-03-08 15:26:16 UTC (rev 40868) +++ haiku/trunk/src/add-ons/translators/webp/WebPTranslator.h 2011-03-08 15:27:33 UTC (rev 40869) @@ -21,16 +21,32 @@ #include "BaseTranslator.h" -#define WEBP_TRANSLATOR_VERSION B_TRANSLATION_MAKE_VERSION(0,1,0) +#define WEBP_TRANSLATOR_VERSION B_TRANSLATION_MAKE_VERSION(0,2,0) #define WEBP_IMAGE_FORMAT 'WebP' +#define WEBP_SETTING_QUALITY "quality" +#define WEBP_SETTING_PRESET "preset" +#define WEBP_SETTING_SHARPNESS "sharpness" +#define WEBP_SETTING_METHOD "method" +#define WEBP_SETTING_PREPROCESSING "preprocessing" + + #define WEBP_IN_QUALITY 0.90 #define WEBP_IN_CAPABILITY 0.90 -#define BITS_OUT_QUALITY 1 -#define BITS_OUT_CAPABILITY 0.9 +#define WEBP_OUT_QUALITY 0.90 +#define WEBP_OUT_CAPABILITY 0.5 +#define BITS_IN_QUALITY 0.8 +#define BITS_IN_CAPABILITY 0.6 +#define BITS_OUT_QUALITY 0.5 +#define BITS_OUT_CAPABILITY 0.4 + + +struct WebPPicture; + + class WebPTranslator : public BaseTranslator { public: WebPTranslator(); @@ -52,6 +68,19 @@ // this is protected because the object is deleted by the // Release() function instead of being deleted directly by // the user + +private: + status_t _TranslateFromBits(BPositionIO* stream, + BMessage* settings, uint32 outType, + BPositionIO* target); + + status_t _TranslateFromWebP(BPositionIO* stream, + BMessage* settings, uint32 outType, + BPositionIO* target); + + static int _EncodedWriter(const uint8_t* data, + size_t dataSize, + const WebPPicture* const picture); };