// Copyright 2021 Benjamin Barenblat // // 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. #include "src/webp.h" #include #include #include #include #include #include #include "third_party/abseil/absl/strings/str_cat.h" #include "third_party/abseil/absl/strings/string_view.h" #include "third_party/abseil/absl/types/span.h" namespace glplanet { std::vector DecodeWebp(absl::Span webp, int x, int y, int width, int height) { size_t bytes = 3 * width * height; std::vector decoded(bytes, '\0'); WebPDecoderConfig config; if (!WebPInitDecoderConfig(&config)) { throw std::runtime_error("failed to initialize WebP decoder"); } config.options.use_cropping = 1; config.options.crop_left = x; config.options.crop_top = y; config.options.crop_width = width; config.options.crop_height = height; config.output.colorspace = MODE_RGB; config.output.is_external_memory = 1; config.output.u.RGBA.rgba = decoded.data(); config.output.u.RGBA.stride = 3 * width; config.output.u.RGBA.size = bytes; int error = WebPDecode(webp.data(), webp.size(), &config); if (error != VP8_STATUS_OK) { static constexpr absl::string_view error_prefix = "failed to decode WebP: "; switch (error) { case VP8_STATUS_OUT_OF_MEMORY: throw std::bad_alloc(); case VP8_STATUS_INVALID_PARAM: throw std::invalid_argument( absl::StrCat(error_prefix, "invalid parameter")); case VP8_STATUS_BITSTREAM_ERROR: throw std::runtime_error(absl::StrCat(error_prefix, "bitstream error")); case VP8_STATUS_UNSUPPORTED_FEATURE: throw std::runtime_error( absl::StrCat(error_prefix, "unsupported feature")); case VP8_STATUS_SUSPENDED: throw std::runtime_error(absl::StrCat(error_prefix, "suspended")); case VP8_STATUS_USER_ABORT: throw std::runtime_error(absl::StrCat(error_prefix, "aborted")); case VP8_STATUS_NOT_ENOUGH_DATA: throw std::runtime_error(absl::StrCat(error_prefix, "not enough data")); default: throw std::runtime_error(absl::StrCat(error_prefix, "unknown error")); } } return decoded; } } // namespace glplanet