| // Copyright 2019 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. |
| // ----------------------------------------------------------------------------- |
| // |
| // Image savers |
| |
| #include <cstdint> |
| #include <cstdio> |
| |
| #include "imageio/image_enc.h" |
| #include "src/dsp/math.h" |
| #include "src/utils/csp.h" |
| #include "src/utils/plane.h" |
| #include "src/utils/utils.h" |
| #include "src/utils/vector.h" |
| #include "src/wp2/base.h" |
| #include "src/wp2/format_constants.h" |
| |
| namespace WP2 { |
| |
| static WP2Status WritePPMPAM(const ArgbBuffer& buffer, int alpha, |
| FILE* const fout) { |
| WP2_CHECK_OK(fout != nullptr, WP2_STATUS_NULL_PARAMETER); |
| WP2_CHECK_OK(!buffer.IsEmpty(), WP2_STATUS_NULL_PARAMETER); |
| WP2_CHECK_OK(WP2Formatbpc(buffer.format()) == 8, |
| WP2_STATUS_INVALID_PARAMETER); |
| |
| ArgbBuffer converted_row(alpha ? WP2_RGBA_32 : WP2_RGB_24); |
| const uint8_t bytes_per_px = WP2FormatBpp(converted_row.format()); |
| if (alpha) { |
| fprintf(fout, |
| "P7\nWIDTH %u\nHEIGHT %u\nDEPTH 4\nMAXVAL 255\n" |
| "TUPLTYPE RGB_ALPHA\nENDHDR\n", |
| buffer.width(), buffer.height()); |
| } else { |
| fprintf(fout, "P6\n%u %u\n255\n", buffer.width(), buffer.height()); |
| } |
| for (uint32_t y = 0; y < buffer.height(); ++y) { |
| ArgbBuffer buffer_row(buffer.format()); |
| WP2_CHECK_STATUS(buffer_row.SetView(buffer, {0, y, buffer.width(), 1})); |
| if (converted_row.format() == buffer_row.format()) { |
| WP2_CHECK_STATUS(converted_row.SetView(buffer_row)); |
| } else { |
| WP2_CHECK_STATUS(converted_row.ConvertFrom(buffer_row)); |
| } |
| WP2_CHECK_OK(fwrite(converted_row.GetRow8(0), bytes_per_px, |
| converted_row.width(), fout) == converted_row.width(), |
| WP2_STATUS_BAD_WRITE); |
| } |
| return WP2_STATUS_OK; |
| } |
| |
| WP2Status WritePPM(const ArgbBuffer& buffer, FILE* const fout) { |
| return WritePPMPAM(buffer, 0, fout); |
| } |
| |
| WP2Status WritePAM(const ArgbBuffer& buffer, FILE* const fout) { |
| return WritePPMPAM(buffer, 1, fout); |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Raw PGM |
| |
| static WP2Status SaveRow(const Plane16& src, uint32_t y, FILE* const out, |
| uint32_t shift, int32_t offset, Vector_u8& tmp) { |
| const uint32_t width = src.w_; |
| const int16_t* const row = src.Row(y); |
| WP2_CHECK_ALLOC_OK(tmp.resize(width)); |
| for (uint32_t i = 0; i < width; ++i) { |
| tmp[i] = Clamp<int32_t>((row[i] >> shift) + offset, 0, 255); |
| } |
| WP2_CHECK_OK(fwrite(&tmp[0], width, 1, out) == 1, WP2_STATUS_BAD_WRITE); |
| return WP2_STATUS_OK; |
| } |
| |
| WP2Status WritePGM(const ArgbBuffer& buffer, FILE* const fout, |
| const CSPTransform& transform) { |
| WP2_CHECK_OK(fout != nullptr, WP2_STATUS_NULL_PARAMETER); |
| YUVPlane yuva; |
| const bool has_alpha = buffer.HasTransparency(); |
| const uint32_t width = buffer.width(); |
| const uint32_t height = buffer.height(); |
| WP2_CHECK_STATUS(yuva.Import(buffer, has_alpha, transform, |
| /*resize_if_needed=*/true)); |
| fprintf(fout, "P5\n%u %u\n255\n", width * (has_alpha ? 4 : 3), height); |
| Vector_u8 tmp; |
| const BitDepth bit_depth = transform.GetYuvDepth(); |
| const uint32_t shift = bit_depth.num_bits - kRgbBits; |
| const int32_t offset = bit_depth.is_signed ? 128 : 0; |
| for (uint32_t y = 0; y < height; ++y) { |
| WP2_CHECK_STATUS(SaveRow(yuva.Y, y, fout, shift, offset, tmp)); |
| WP2_CHECK_STATUS(SaveRow(yuva.U, y, fout, shift, offset, tmp)); |
| WP2_CHECK_STATUS(SaveRow(yuva.V, y, fout, shift, offset, tmp)); |
| if (has_alpha) { |
| WP2_CHECK_STATUS(SaveRow(yuva.A, y, fout, 0, 0, tmp)); |
| } |
| } |
| return WP2_STATUS_OK; |
| } |
| |
| } // namespace WP2 |