blob: 2ec3d6732eddbcd8100589727b4656f325ca25ec [file] [log] [blame]
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -----------------------------------------------------------------------------
//
// WebP encode.
//
// Author: Yannis Guyon (yguyon@google.com)
#ifdef HAVE_CONFIG_H
#include "wp2/config.h"
#endif
#include "imageio/image_enc.h"
#include "src/wp2/base.h"
#ifdef WP2_HAVE_WEBP
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <memory>
#include "imageio/imageio_util.h"
#include "src/dsp/math.h"
#include "src/utils/utils.h"
#include "src/wp2/format_constants.h"
#include "webp/encode.h"
#endif
namespace WP2 {
// -----------------------------------------------------------------------------
#if defined(WP2_HAVE_WEBP)
static int WriterFunc(const uint8_t* data, size_t data_size,
const WebPPicture* picture) {
Writer* const writer = reinterpret_cast<Writer*>(picture->custom_ptr);
return writer->Append(data, data_size) ? 1 : 0;
}
WP2Status CompressWebP(const ArgbBuffer& buffer, const WebPConfig& config,
Writer* const output) {
WP2_CHECK_OK(!buffer.IsEmpty(), WP2_STATUS_INVALID_PARAMETER);
WP2_CHECK_OK(output != nullptr, WP2_STATUS_NULL_PARAMETER);
WP2_CHECK_OK(WebPValidateConfig(&config), WP2_STATUS_INVALID_CONFIGURATION);
// Convert WP2::ArgbBuffer to WebPPicture
WebPPicture picture = {};
std::unique_ptr<WebPPicture, decltype(&WebPPictureFree)> picture_releaser(
&picture, WebPPictureFree);
WP2_CHECK_STATUS(ConvertToWebPPicture(buffer, &picture));
picture.writer = WriterFunc;
picture.custom_ptr = reinterpret_cast<void*>(output);
WP2_CHECK_OK(WebPEncode(&config, &picture), WP2_STATUS_INVALID_PARAMETER);
return WP2_STATUS_OK;
}
WP2Status CompressWebP(const ArgbBuffer& buffer, float quality, int effort,
Writer* const output) {
WebPConfig config;
WP2_CHECK_OK(WebPConfigInit(&config), WP2_STATUS_VERSION_MISMATCH);
// Map wp2 'quality' in [lossy:kMaxLossyQuality:kMaxQuality]
// to WebP in [lossy:near-lossless:lossless].
if (quality <= (float)kMaxLossyQuality) {
config.quality = Clamp((quality / kMaxLossyQuality) * 100.f, 0.f, 100.f);
} else {
WP2_CHECK_OK(WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, quality),
WP2_STATUS_VERSION_MISMATCH);
config.lossless = 1;
config.near_lossless =
Clamp<int>(std::lround(((quality - kMaxLossyQuality) /
(kMaxQuality - kMaxLossyQuality)) *
100.f),
0, 100);
config.exact = (config.near_lossless == 100);
config.quality = Clamp(effort / 9.f * 100.f, 0.f, 100.f);
}
config.method = Clamp(DivRound(effort * 6, 9), 0, 6);
WP2_CHECK_STATUS(CompressWebP(buffer, config, output));
return WP2_STATUS_OK;
}
#else
WP2Status CompressWebP(const ArgbBuffer&, float, int, Writer*) {
return WP2_STATUS_UNSUPPORTED_FEATURE;
}
#endif // defined(WP2_HAVE_WEBP)
// -----------------------------------------------------------------------------
} // namespace WP2