text: // Copyright 2018 The Fuchsia Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "src/ui/lib/yuv/yuv.h"
  
  #include <algorithm>
  #include <cmath>
  
  namespace {
  
  // Convert linear RGB values to sRGB. |in| is a float
  // value between 0 and 1.
  float LinearRgbToSrgb(float in) {
    if (in <= 0.0031308f) {
      return in * 12.92f;
    } else {
      return 1.055f * pow(in, 1.f / 2.4f) - 0.055f;
    }
  }
  
  uint8_t NormalizedFloatToUnsignedByte(float in) {
    int32_t out = static_cast<int32_t>(std::lround(in * 255.0f));
    return static_cast<uint8_t>(std::clamp(out, 0, 255));
  }
  
  }  // namespace
  
  namespace yuv {
  
  // Letting compiler decide whether to inline, for now.
  void YuvToBgra(uint8_t y_raw, uint8_t u_raw, uint8_t v_raw, uint8_t* bgra) {
    // Convert from encoded space to normalized space assuming eItuNarrow.
    int32_t y = static_cast<int32_t>(y_raw) - 16;
    int32_t u = static_cast<int32_t>(u_raw) - 128;
    int32_t v = static_cast<int32_t>(v_raw) - 128;
  
    // Note: Normally, we would clamp here. But some drivers do not clamp in the
    // middle of their implementation, and this function is used for pixel tests.
    float fy = static_cast<float>(y) / 219.0f;
    float fu = static_cast<float>(u) / 224.0f;
    float fv = static_cast<float>(v) / 224.0f;
  
    // Convert from YUV to RGB using the coefficients for eYcbcr709.
    float r = fy + 1.5748f * fv;
    float g = fy - (0.13397432f / 0.7152f) * fu - (0.33480248f / 0.7152f) * fv;
    float b = fy + 1.8556f * fu;
  
    // Convert to sRGB, then store the value as unsigned bytes.
    bgra[0] = NormalizedFloatToUnsignedByte(LinearRgbToSrgb(b));  // blue
    bgra[1] = NormalizedFloatToUnsignedByte(LinearRgbToSrgb(g));  // green
    bgra[2] = NormalizedFloatToUnsignedByte(LinearRgbToSrgb(r));  // red
    bgra[3] = 0xff;                                               // alpha
  }
  
  }  // namespace yuv
  