Error HeifPixelImage::rotate_ccw()

in libheif/pixelimage.cc [539:740]


Error HeifPixelImage::rotate_ccw(int angle_degrees,
                                 std::shared_ptr<HeifPixelImage>& out_img)
{
  // --- create output image (or simply reuse existing image)

  if (angle_degrees == 0) {
    out_img = shared_from_this();
    return Error::Ok;
  }

  int out_width = m_width;
  int out_height = m_height;

  if (angle_degrees == 90 || angle_degrees == 270) {
    std::swap(out_width, out_height);
  }

  out_img = std::make_shared<HeifPixelImage>();
  out_img->create(out_width, out_height, m_colorspace, m_chroma);


  // --- rotate all channels

  for (const auto& plane_pair : m_planes) {
    heif_channel channel = plane_pair.first;
    const ImagePlane& plane = plane_pair.second;

    /*
    if (plane.bit_depth != 8) {
      return Error(heif_error_Unsupported_feature,
                   heif_suberror_Unspecified,
                   "Can currently only rotate images with 8 bits per pixel");
    }
    */

    int out_plane_width = plane.m_width;
    int out_plane_height = plane.m_height;

    if (angle_degrees == 90 || angle_degrees == 270) {
      std::swap(out_plane_width, out_plane_height);
    }

    out_img->add_plane(channel, out_plane_width, out_plane_height, plane.m_bit_depth);


    int w = plane.m_width;
    int h = plane.m_height;

    int in_stride = plane.stride;
    const uint8_t* in_data = plane.mem;

    int out_stride = 0;
    uint8_t* out_data = out_img->get_plane(channel, &out_stride);

    if (plane.m_bit_depth == 8) {

      int convert_result = -1;

      if((this->m_colorspace == heif_colorspace_RGB) && (this->m_chroma == heif_chroma_interleaved_RGBA))
      {
#if HAVE_YUV
        libyuv::RotationModeEnum mode ;
        switch(angle_degrees) 
        {
          case 0  : mode = libyuv::kRotate0  ; break;
          case 90 : mode = libyuv::kRotate270; break;
          case 180: mode = libyuv::kRotate180; break;
          case 270: mode = libyuv::kRotate90 ; break;
        }
        convert_result = libyuv::ARGBRotate(in_data, in_stride, out_data, out_stride, w, h, mode);
#endif
      }

      if(convert_result < 0 ) 
      {
        if (angle_degrees == 270) {
          for (long long x = 0; x < h; x++)
            for (long long y = 0; y < w; y++) {
              if(m_chroma >= heif_chroma_interleaved_RGB ) {
                int channel_num = (m_chroma == heif_chroma_interleaved_RGB) ? 3 : ((m_chroma == heif_chroma_interleaved_RGBA) ? 4 : 1) ;
                for(int channel = 0; channel < channel_num; channel++)
                  out_data[y * out_stride + x*channel_num + channel] = in_data[(h - 1 - x) * in_stride + y*channel_num + channel];
              } 
              else {
                out_data[y * out_stride + x] = in_data[(h - 1 - x) * in_stride + y];
              }
            }
        }
        else if (angle_degrees == 180) {
          for (long long y = 0; y < h; y++)
            for (long long x = 0; x < w; x++) {
              if(m_chroma >= heif_chroma_interleaved_RGB ) {
                int channel_num = (m_chroma == heif_chroma_interleaved_RGB) ? 3 : ((m_chroma == heif_chroma_interleaved_RGBA) ? 4 : 1) ;
                for(int channel = 0; channel < channel_num; channel++)
                  out_data[y * out_stride + x*channel_num + channel] = in_data[(h - 1 - y) * in_stride + (w - 1 - x)*channel_num + channel];
              } 
              else {
                out_data[y * out_stride + x] = in_data[(h - 1 - y) * in_stride + (w - 1 - x)];
              }
            }
        }
        else if (angle_degrees == 90) {
          for (long x = 0; x < h; x++)
            for (long y = 0; y < w; y++) {
              if(m_chroma >= heif_chroma_interleaved_RGB ) {
                int channel_num = (m_chroma == heif_chroma_interleaved_RGB) ? 3 : ((m_chroma == heif_chroma_interleaved_RGBA) ? 4 : 1) ;
                for(int channel = 0; channel < channel_num; channel++)
                  out_data[y * out_stride + x*channel_num + channel] = in_data[x * in_stride + (w - 1 - y)*channel_num + channel];
              } 
              else {
                out_data[y * out_stride + x] = in_data[x * in_stride + (w - 1 - y)];
              }
            }
          }
      }
    }
    else { // 16 bit (TODO: unchecked code)
      if (angle_degrees == 270) {
        for (long long x = 0; x < h; x++)
          for (long long y = 0; y < w; y++) {
            if(m_chroma >= heif_chroma_interleaved_RRGGBB_BE ) {
              int channel_num = 1;
              if((m_chroma == heif_chroma_interleaved_RRGGBB_BE) || (m_chroma == heif_chroma_interleaved_RRGGBB_LE)) { 
                channel_num = 3;
              } 
              else if((m_chroma == heif_chroma_interleaved_RRGGBBAA_BE) || (m_chroma == heif_chroma_interleaved_RRGGBBAA_LE)) {
                channel_num = 4;
              }
              else {
                channel_num = 1;
              }
              for(int channel = 0; channel < channel_num; channel++) {
                out_data[y * out_stride + 2 * x * channel_num + 2 * channel]     = in_data[(h - 1 - x) * in_stride + 2 * y * channel_num + 2 * channel];
                out_data[y * out_stride + 2 * x * channel_num + 2 * channel + 1] = in_data[(h - 1 - x) * in_stride + 2 * y * channel_num + 2 * channel + 1];
              }
            } 
            else {
              out_data[y * out_stride + 2 * x]     = in_data[(h - 1 - x) * in_stride + 2 * y];
              out_data[y * out_stride + 2 * x + 1] = in_data[(h - 1 - x) * in_stride + 2 * y + 1];
            }
          }
      }
      else if (angle_degrees == 180) {
        for (long long y = 0; y < h; y++)
          for (long long x = 0; x < w; x++) {
            if(m_chroma >= heif_chroma_interleaved_RRGGBB_BE ) {
              int channel_num = 1;
              if((m_chroma == heif_chroma_interleaved_RRGGBB_BE) || (m_chroma == heif_chroma_interleaved_RRGGBB_LE)) { 
                channel_num = 3;
              } 
              else if((m_chroma == heif_chroma_interleaved_RRGGBBAA_BE) || (m_chroma == heif_chroma_interleaved_RRGGBBAA_LE)) {
                channel_num = 4;
              }
              else {
                channel_num = 1;
              }
              for(int channel = 0; channel < channel_num; channel++) {
                out_data[y * out_stride + 2 * x * channel_num + 2 * channel]     = in_data[(h - 1 - y) * in_stride + 2 * (w - 1 - x) * channel_num + 2 * channel];
                out_data[y * out_stride + 2 * x * channel_num + 2 * channel + 1] = in_data[(h - 1 - y) * in_stride + 2 * (w - 1 - x) * channel_num + 2 * channel + 1];
              }
            } 
            else {
              out_data[y * out_stride + 2 * x]     = in_data[(h - 1 - y) * in_stride + 2 * (w - 1 - x)];
              out_data[y * out_stride + 2 * x + 1] = in_data[(h - 1 - y) * in_stride + 2 * (w - 1 - x) + 1];
            }
          }
      }
      else if (angle_degrees == 90) {
        for (long long x = 0; x < h; x++)
          for (long long y = 0; y < w; y++) {
            if(m_chroma >= heif_chroma_interleaved_RRGGBB_BE ) {
              int channel_num = 1;
              if((m_chroma == heif_chroma_interleaved_RRGGBB_BE) || (m_chroma == heif_chroma_interleaved_RRGGBB_LE)) { 
                channel_num = 3;
              } 
              else if((m_chroma == heif_chroma_interleaved_RRGGBBAA_BE) || (m_chroma == heif_chroma_interleaved_RRGGBBAA_LE)) {
                channel_num = 4;
              }
              else {
                channel_num = 1;
              }
              for(int channel = 0; channel < channel_num; channel++) {
                out_data[y * out_stride + 2 * x * channel_num + 2 * channel]     = in_data[x * in_stride + 2 * (w - 1 - y) * channel_num + 2 * channel];
                out_data[y * out_stride + 2 * x * channel_num + 2 * channel + 1] = in_data[x * in_stride + 2 * (w - 1 - y) * channel_num + 2 * channel + 1];
              }
            } 
            else {
              out_data[y * out_stride + 2 * x]     = in_data[x * in_stride + 2 * (w - 1 - y)];
              out_data[y * out_stride + 2 * x + 1] = in_data[x * in_stride + 2 * (w - 1 - y) + 1];
            }
          }
      }
    }
  }

  // --- pass the color profiles to the new image

  out_img->set_color_profile_nclx(get_color_profile_nclx());
  out_img->set_color_profile_icc(get_color_profile_icc());

  return Error::Ok;
}