Skip to content

Commit

Permalink
Merge pull request #23319 from CrystalP/bp-fix-rotated-thumbnails
Browse files Browse the repository at this point in the history
Fix Thumbnails of Rotated Pictures
  • Loading branch information
enen92 committed Jun 24, 2023
2 parents 9a44d07 + 0dfb62c commit a0bcc42
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 40 deletions.
92 changes: 60 additions & 32 deletions xbmc/pictures/Picture.cpp
Expand Up @@ -257,10 +257,11 @@ bool CPicture::CacheTexture(uint8_t *pixels, uint32_t width, uint32_t height, ui
if (ScaleImage(pixels, width, height, pitch, AV_PIX_FMT_BGRA, (uint8_t*)buffer, dest_width,
dest_height, stride, AV_PIX_FMT_BGRA, scalingAlgorithm))
{
if (!orientation || OrientateImage(buffer, dest_width, dest_height, orientation))
if (!orientation ||
OrientateImage(buffer, dest_width, dest_height, orientation, dest_width_aligned))
{
success = CreateThumbnailFromSurface((unsigned char*)buffer, dest_width, dest_height,
stride, dest);
dest_width_aligned * 4, dest);
}
}
delete[] buffer;
Expand Down Expand Up @@ -312,7 +313,9 @@ bool CPicture::CreateTiledThumb(const std::vector<std::string> &files, const std
texture->GetPitch(), AV_PIX_FMT_BGRA, (uint8_t*)scaled, width, height,
width * 4, AV_PIX_FMT_BGRA))
{
if (!texture->GetOrientation() || OrientateImage(scaled, width, height, texture->GetOrientation()))
unsigned int stridePixels{width};
if (!texture->GetOrientation() ||
OrientateImage(scaled, width, height, texture->GetOrientation(), stridePixels))
{
success = true; // Flag that we at least had one successful image processed
// drop into the texture
Expand All @@ -324,7 +327,7 @@ bool CPicture::CreateTiledThumb(const std::vector<std::string> &files, const std
{
memcpy(dest, src, width*4);
dest += imageRes;
src += width;
src += stridePixels;
}
}
}
Expand Down Expand Up @@ -379,32 +382,36 @@ bool CPicture::ScaleImage(uint8_t* in_pixels,
return false;
}

bool CPicture::OrientateImage(uint32_t *&pixels, unsigned int &width, unsigned int &height, int orientation)
bool CPicture::OrientateImage(uint32_t*& pixels,
unsigned int& width,
unsigned int& height,
int orientation,
unsigned int& stridePixels)
{
// ideas for speeding these functions up: http://cgit.freedesktop.org/pixman/tree/pixman/pixman-fast-path.c
bool out = false;
switch (orientation)
{
case 1:
out = FlipHorizontal(pixels, width, height);
out = FlipHorizontal(pixels, width, height, stridePixels);
break;
case 2:
out = Rotate180CCW(pixels, width, height);
out = Rotate180CCW(pixels, width, height, stridePixels);
break;
case 3:
out = FlipVertical(pixels, width, height);
out = FlipVertical(pixels, width, height, stridePixels);
break;
case 4:
out = Transpose(pixels, width, height);
out = Transpose(pixels, width, height, stridePixels);
break;
case 5:
out = Rotate270CCW(pixels, width, height);
out = Rotate270CCW(pixels, width, height, stridePixels);
break;
case 6:
out = TransposeOffAxis(pixels, width, height);
out = TransposeOffAxis(pixels, width, height, stridePixels);
break;
case 7:
out = Rotate90CCW(pixels, width, height);
out = Rotate90CCW(pixels, width, height, stridePixels);
break;
default:
CLog::Log(LOGERROR, "Unknown orientation {}", orientation);
Expand All @@ -415,12 +422,13 @@ bool CPicture::OrientateImage(uint32_t *&pixels, unsigned int &width, unsigned i

bool CPicture::FlipHorizontal(uint32_t*& pixels,
const unsigned int& width,
const unsigned int& height)
const unsigned int& height,
const unsigned int& stridePixels)
{
// this can be done in-place easily enough
for (unsigned int y = 0; y < height; ++y)
{
uint32_t *line = pixels + y * width;
uint32_t* line = pixels + y * stridePixels;
for (unsigned int x = 0; x < width / 2; ++x)
std::swap(line[x], line[width - 1 - x]);
}
Expand All @@ -429,13 +437,14 @@ bool CPicture::FlipHorizontal(uint32_t*& pixels,

bool CPicture::FlipVertical(uint32_t*& pixels,
const unsigned int& width,
const unsigned int& height)
const unsigned int& height,
const unsigned int& stridePixels)
{
// this can be done in-place easily enough
for (unsigned int y = 0; y < height / 2; ++y)
{
uint32_t *line1 = pixels + y * width;
uint32_t *line2 = pixels + (height - 1 - y) * width;
uint32_t* line1 = pixels + y * stridePixels;
uint32_t* line2 = pixels + (height - 1 - y) * stridePixels;
for (unsigned int x = 0; x < width; ++x)
std::swap(*line1++, *line2++);
}
Expand All @@ -444,26 +453,30 @@ bool CPicture::FlipVertical(uint32_t*& pixels,

bool CPicture::Rotate180CCW(uint32_t*& pixels,
const unsigned int& width,
const unsigned int& height)
const unsigned int& height,
const unsigned int& stridePixels)
{
// this can be done in-place easily enough
for (unsigned int y = 0; y < height / 2; ++y)
{
uint32_t *line1 = pixels + y * width;
uint32_t *line2 = pixels + (height - 1 - y) * width + width - 1;
uint32_t* line1 = pixels + y * stridePixels;
uint32_t* line2 = pixels + (height - 1 - y) * stridePixels + width - 1;
for (unsigned int x = 0; x < width; ++x)
std::swap(*line1++, *line2--);
}
if (height % 2)
{ // height is odd, so flip the middle row as well
uint32_t *line = pixels + (height - 1)/2 * width;
uint32_t* line = pixels + (height - 1) / 2 * stridePixels;
for (unsigned int x = 0; x < width / 2; ++x)
std::swap(line[x], line[width - 1 - x]);
}
return true;
}

bool CPicture::Rotate90CCW(uint32_t *&pixels, unsigned int &width, unsigned int &height)
bool CPicture::Rotate90CCW(uint32_t*& pixels,
unsigned int& width,
unsigned int& height,
unsigned int& stridePixels)
{
uint32_t *dest = new uint32_t[width * height * 4];
if (dest)
Expand All @@ -476,18 +489,22 @@ bool CPicture::Rotate90CCW(uint32_t *&pixels, unsigned int &width, unsigned int
for (unsigned int x = 0; x < d_width; x++)
{
*dst++ = *src;
src += width;
src += stridePixels;
}
}
delete[] pixels;
pixels = dest;
std::swap(width, height);
stridePixels = width;
return true;
}
return false;
}

bool CPicture::Rotate270CCW(uint32_t *&pixels, unsigned int &width, unsigned int &height)
bool CPicture::Rotate270CCW(uint32_t*& pixels,
unsigned int& width,
unsigned int& height,
unsigned int& stridePixels)
{
uint32_t *dest = new uint32_t[width * height * 4];
if (!dest)
Expand All @@ -496,22 +513,27 @@ bool CPicture::Rotate270CCW(uint32_t *&pixels, unsigned int &width, unsigned int
unsigned int d_height = width, d_width = height;
for (unsigned int y = 0; y < d_height; y++)
{
const uint32_t *src = pixels + width * (d_width - 1) + y; // y-th col from left, starting at bottom
uint32_t *dst = dest + d_width * y; // y-th row from top, starting at left
const uint32_t* src =
pixels + stridePixels * (d_width - 1) + y; // y-th col from left, starting at bottom
uint32_t* dst = dest + d_width * y; // y-th row from top, starting at left
for (unsigned int x = 0; x < d_width; x++)
{
*dst++ = *src;
src -= width;
src -= stridePixels;
}
}

delete[] pixels;
pixels = dest;
std::swap(width, height);
stridePixels = width;
return true;
}

bool CPicture::Transpose(uint32_t *&pixels, unsigned int &width, unsigned int &height)
bool CPicture::Transpose(uint32_t*& pixels,
unsigned int& width,
unsigned int& height,
unsigned int& stridePixels)
{
uint32_t *dest = new uint32_t[width * height * 4];
if (!dest)
Expand All @@ -525,17 +547,21 @@ bool CPicture::Transpose(uint32_t *&pixels, unsigned int &width, unsigned int &h
for (unsigned int x = 0; x < d_width; x++)
{
*dst++ = *src;
src += width;
src += stridePixels;
}
}

delete[] pixels;
pixels = dest;
std::swap(width, height);
stridePixels = width;
return true;
}

bool CPicture::TransposeOffAxis(uint32_t *&pixels, unsigned int &width, unsigned int &height)
bool CPicture::TransposeOffAxis(uint32_t*& pixels,
unsigned int& width,
unsigned int& height,
unsigned int& stridePixels)
{
uint32_t *dest = new uint32_t[width * height * 4];
if (!dest)
Expand All @@ -544,17 +570,19 @@ bool CPicture::TransposeOffAxis(uint32_t *&pixels, unsigned int &width, unsigned
unsigned int d_height = width, d_width = height;
for (unsigned int y = 0; y < d_height; y++)
{
const uint32_t *src = pixels + width * (d_width - 1) + (d_height - 1 - y); // y-th col from right, starting at bottom
const uint32_t* src = pixels + stridePixels * (d_width - 1) +
(d_height - 1 - y); // y-th col from right, starting at bottom
uint32_t *dst = dest + d_width * y; // y-th row, starting at left
for (unsigned int x = 0; x < d_width; x++)
{
*dst++ = *src;
src -= width;
src -= stridePixels;
}
}

delete[] pixels;
pixels = dest;
std::swap(width, height);
stridePixels = width;
return true;
}
35 changes: 27 additions & 8 deletions xbmc/pictures/Picture.h
Expand Up @@ -79,21 +79,40 @@ class CPicture
CPictureScalingAlgorithm::Algorithm scalingAlgorithm = CPictureScalingAlgorithm::NoAlgorithm);

private:
static bool OrientateImage(uint32_t *&pixels, unsigned int &width, unsigned int &height, int orientation);
static bool OrientateImage(uint32_t*& pixels,
unsigned int& width,
unsigned int& height,
int orientation,
unsigned int& stridePixels);

static bool FlipHorizontal(uint32_t*& pixels,
const unsigned int& width,
const unsigned int& height);
const unsigned int& height,
const unsigned int& stridePixels);
static bool FlipVertical(uint32_t*& pixels,
const unsigned int& width,
const unsigned int& height);
static bool Rotate90CCW(uint32_t *&pixels, unsigned int &width, unsigned int &height);
static bool Rotate270CCW(uint32_t *&pixels, unsigned int &width, unsigned int &height);
const unsigned int& height,
const unsigned int& stridePixels);
static bool Rotate90CCW(uint32_t*& pixels,
unsigned int& width,
unsigned int& height,
unsigned int& stridePixels);
static bool Rotate270CCW(uint32_t*& pixels,
unsigned int& width,
unsigned int& height,
unsigned int& stridePixels);
static bool Rotate180CCW(uint32_t*& pixels,
const unsigned int& width,
const unsigned int& height);
static bool Transpose(uint32_t *&pixels, unsigned int &width, unsigned int &height);
static bool TransposeOffAxis(uint32_t *&pixels, unsigned int &width, unsigned int &height);
const unsigned int& height,
const unsigned int& stridePixels);
static bool Transpose(uint32_t*& pixels,
unsigned int& width,
unsigned int& height,
unsigned int& width_aligned);
static bool TransposeOffAxis(uint32_t*& pixels,
unsigned int& width,
unsigned int& height,
unsigned int& stridePixels);
};

//this class calls CreateThumbnailFromSurface in a CJob, so a png file can be written without halting the render thread
Expand Down

0 comments on commit a0bcc42

Please sign in to comment.