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;
}