mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-07 23:41:26 +12:00
Flipping / padding on .JPG and .GIF decoding
* Changes in cellJpgDec and cellGifDec come from cellPngDec.
This commit is contained in:
parent
fe46a45915
commit
713bff01e1
4 changed files with 156 additions and 28 deletions
|
@ -180,29 +180,90 @@ int cellGifDecDecodeData(u32 mainHandle, u32 subHandle, mem8_ptr_t data, const m
|
||||||
|
|
||||||
//Decode GIF file. (TODO: Is there any faster alternative? Can we do it without external libraries?)
|
//Decode GIF file. (TODO: Is there any faster alternative? Can we do it without external libraries?)
|
||||||
int width, height, actual_components;
|
int width, height, actual_components;
|
||||||
std::shared_ptr<unsigned char> image(stbi_load_from_memory(gif, fileSize, &width, &height, &actual_components, 4));
|
auto image = std::unique_ptr<unsigned char,decltype(&::free)>
|
||||||
|
(
|
||||||
|
stbi_load_from_memory(gif.GetPtr(), fileSize, &width, &height, &actual_components, 4),
|
||||||
|
&::free
|
||||||
|
);
|
||||||
|
|
||||||
if (!image)
|
if (!image)
|
||||||
return CELL_GIFDEC_ERROR_STREAM_FORMAT;
|
return CELL_GIFDEC_ERROR_STREAM_FORMAT;
|
||||||
|
|
||||||
uint image_size = width * height * 4;
|
const int bytesPerLine = dataCtrlParam->outputBytesPerLine;
|
||||||
|
const char nComponents = 4;
|
||||||
|
uint image_size = width * height * nComponents;
|
||||||
|
|
||||||
switch((u32)current_outParam.outputColorSpace)
|
switch((u32)current_outParam.outputColorSpace)
|
||||||
{
|
{
|
||||||
case CELL_GIFDEC_RGBA:
|
case CELL_GIFDEC_RGBA:
|
||||||
|
{
|
||||||
|
if (bytesPerLine > width * nComponents) // Check if we need padding
|
||||||
|
{
|
||||||
|
const int linesize = std::min(bytesPerLine, width * nComponents);
|
||||||
|
for (int i = 0; i < height; i++)
|
||||||
|
{
|
||||||
|
const int dstOffset = i * bytesPerLine;
|
||||||
|
const int srcOffset = width * nComponents * i;
|
||||||
|
if (!Memory.CopyFromReal(data.GetAddr() + dstOffset, &image.get()[srcOffset], linesize))
|
||||||
|
{
|
||||||
|
cellGifDec->Error("cellGifDecDecodeData() failed (II)");
|
||||||
|
return CELL_EFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (!Memory.CopyFromReal(data.GetAddr(), image.get(), image_size))
|
if (!Memory.CopyFromReal(data.GetAddr(), image.get(), image_size))
|
||||||
{
|
{
|
||||||
cellGifDec->Error("cellGifDecDecodeData() failed (dataa_addr=0x%x)", data.GetAddr());
|
cellGifDec->Error("cellGifDecDecodeData() failed (III)");
|
||||||
return CELL_EFAULT;
|
return CELL_EFAULT;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CELL_GIFDEC_ARGB:
|
case CELL_GIFDEC_ARGB:
|
||||||
for(uint i = 0; i < image_size; i+=4)
|
|
||||||
{
|
{
|
||||||
data += image.get()[i+3];
|
if (bytesPerLine > width * nComponents) // Check if we need padding
|
||||||
data += image.get()[i+0];
|
{
|
||||||
data += image.get()[i+1];
|
//TODO: find out if we can't do padding without an extra copy
|
||||||
data += image.get()[i+2];
|
const int linesize = std::min(bytesPerLine, width * nComponents);
|
||||||
|
char *output = (char *) malloc(linesize);
|
||||||
|
for (int i = 0; i < height; i++)
|
||||||
|
{
|
||||||
|
const int dstOffset = i * bytesPerLine;
|
||||||
|
const int srcOffset = width * nComponents * i;
|
||||||
|
for (int j = 0; j < linesize; j += nComponents)
|
||||||
|
{
|
||||||
|
output[j + 0] = image.get()[srcOffset + j + 3];
|
||||||
|
output[j + 1] = image.get()[srcOffset + j + 0];
|
||||||
|
output[j + 2] = image.get()[srcOffset + j + 1];
|
||||||
|
output[j + 3] = image.get()[srcOffset + j + 2];
|
||||||
|
}
|
||||||
|
if (!Memory.CopyFromReal(data.GetAddr() + dstOffset, output, linesize))
|
||||||
|
{
|
||||||
|
cellGifDec->Error("cellGifDecDecodeData() failed (IV)");
|
||||||
|
return CELL_EFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(output);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint* dest = (uint*)new char[image_size];
|
||||||
|
uint* source_current = (uint*)&(image.get()[0]);
|
||||||
|
uint* dest_current = dest;
|
||||||
|
for (uint i = 0; i < image_size / nComponents; i++)
|
||||||
|
{
|
||||||
|
uint val = *source_current;
|
||||||
|
*dest_current = (val >> 24) | (val << 8); // set alpha (A8) as leftmost byte
|
||||||
|
source_current++;
|
||||||
|
dest_current++;
|
||||||
|
}
|
||||||
|
// NOTE: AppendRawBytes has diff side-effect vs Memory.CopyFromReal
|
||||||
|
data.AppendRawBytes((u8*)dest, image_size);
|
||||||
|
delete[] dest;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -188,33 +188,95 @@ int cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, mem8_ptr_t data, const m
|
||||||
|
|
||||||
//Decode JPG file. (TODO: Is there any faster alternative? Can we do it without external libraries?)
|
//Decode JPG file. (TODO: Is there any faster alternative? Can we do it without external libraries?)
|
||||||
int width, height, actual_components;
|
int width, height, actual_components;
|
||||||
std::shared_ptr<unsigned char> image(stbi_load_from_memory(jpg, fileSize, &width, &height, &actual_components, 4));
|
auto image = std::unique_ptr<unsigned char,decltype(&::free)>
|
||||||
|
(
|
||||||
|
stbi_load_from_memory(jpg.GetPtr(), fileSize, &width, &height, &actual_components, 4),
|
||||||
|
&::free
|
||||||
|
);
|
||||||
|
|
||||||
if (!image)
|
if (!image)
|
||||||
return CELL_JPGDEC_ERROR_STREAM_FORMAT;
|
return CELL_JPGDEC_ERROR_STREAM_FORMAT;
|
||||||
|
|
||||||
uint image_size = width * height;
|
const bool flip = current_outParam.outputMode == CELL_JPGDEC_BOTTOM_TO_TOP;
|
||||||
|
const int bytesPerLine = dataCtrlParam->outputBytesPerLine;
|
||||||
|
size_t image_size = width * height;
|
||||||
|
|
||||||
switch((u32)current_outParam.outputColorSpace)
|
switch((u32)current_outParam.outputColorSpace)
|
||||||
{
|
{
|
||||||
case CELL_JPG_RGBA:
|
|
||||||
case CELL_JPG_RGB:
|
case CELL_JPG_RGB:
|
||||||
image_size *= current_outParam.outputColorSpace == CELL_JPG_RGBA ? 4 : 3;
|
case CELL_JPG_RGBA:
|
||||||
|
{
|
||||||
|
const char nComponents = current_outParam.outputColorSpace == CELL_JPG_RGBA ? 4 : 3;
|
||||||
|
image_size *= nComponents;
|
||||||
|
if (bytesPerLine > width * nComponents || flip) //check if we need padding
|
||||||
|
{
|
||||||
|
const int linesize = std::min(bytesPerLine, width * nComponents);
|
||||||
|
for (int i = 0; i < height; i++)
|
||||||
|
{
|
||||||
|
const int dstOffset = i * bytesPerLine;
|
||||||
|
const int srcOffset = width * nComponents * (flip ? height - i - 1 : i);
|
||||||
|
if (!Memory.CopyFromReal(data.GetAddr() + dstOffset, &image.get()[srcOffset], linesize))
|
||||||
|
{
|
||||||
|
cellJpgDec->Error("cellJpgDecDecodeData() failed (II)");
|
||||||
|
return CELL_EFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (!Memory.CopyFromReal(data.GetAddr(), image.get(), image_size))
|
if (!Memory.CopyFromReal(data.GetAddr(), image.get(), image_size))
|
||||||
{
|
{
|
||||||
cellJpgDec->Error("cellJpgDecDecodeData() failed (data_addr=0x%x)", data.GetAddr());
|
cellJpgDec->Error("cellJpgDecDecodeData() failed (III)");
|
||||||
return CELL_EFAULT;
|
return CELL_EFAULT;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CELL_JPG_ARGB:
|
case CELL_JPG_ARGB:
|
||||||
image_size *= 4;
|
|
||||||
|
|
||||||
for(u32 i = 0; i < image_size; i+=4)
|
|
||||||
{
|
{
|
||||||
data += image.get()[i+3];
|
const int nComponents = 4;
|
||||||
data += image.get()[i+0];
|
image_size *= nComponents;
|
||||||
data += image.get()[i+1];
|
if (bytesPerLine > width * nComponents || flip) //check if we need padding
|
||||||
data += image.get()[i+2];
|
{
|
||||||
|
//TODO: Find out if we can't do padding without an extra copy
|
||||||
|
const int linesize = std::min(bytesPerLine, width * nComponents);
|
||||||
|
char *output = (char *) malloc(linesize);
|
||||||
|
for (int i = 0; i < height; i++)
|
||||||
|
{
|
||||||
|
const int dstOffset = i * bytesPerLine;
|
||||||
|
const int srcOffset = width * nComponents * (flip ? height - i - 1 : i);
|
||||||
|
for (int j = 0; j < linesize; j += nComponents)
|
||||||
|
{
|
||||||
|
output[j + 0] = image.get()[srcOffset + j + 3];
|
||||||
|
output[j + 1] = image.get()[srcOffset + j + 0];
|
||||||
|
output[j + 2] = image.get()[srcOffset + j + 1];
|
||||||
|
output[j + 3] = image.get()[srcOffset + j + 2];
|
||||||
|
}
|
||||||
|
if (!Memory.CopyFromReal(data.GetAddr() + dstOffset, output, linesize))
|
||||||
|
{
|
||||||
|
cellJpgDec->Error("cellJpgDecDecodeData() failed (IV)");
|
||||||
|
return CELL_EFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(output);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint* dest = (uint*)new char[image_size];
|
||||||
|
uint* source_current = (uint*)&(image.get()[0]);
|
||||||
|
uint* dest_current = dest;
|
||||||
|
for (uint i = 0; i < image_size / nComponents; i++)
|
||||||
|
{
|
||||||
|
uint val = *source_current;
|
||||||
|
*dest_current = (val >> 24) | (val << 8); // set alpha (A8) as leftmost byte
|
||||||
|
source_current++;
|
||||||
|
dest_current++;
|
||||||
|
}
|
||||||
|
// NOTE: AppendRawBytes has diff side-effect vs Memory.CopyFromReal
|
||||||
|
data.AppendRawBytes((u8*)dest, image_size);
|
||||||
|
delete[] dest;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,14 @@ enum CellJpgDecStreamSrcSel
|
||||||
|
|
||||||
enum CellJpgDecDecodeStatus
|
enum CellJpgDecDecodeStatus
|
||||||
{
|
{
|
||||||
CELL_JPGDEC_DEC_STATUS_FINISH = 0, //Decoding finished
|
CELL_JPGDEC_DEC_STATUS_FINISH = 0, // Decoding finished
|
||||||
CELL_JPGDEC_DEC_STATUS_STOP = 1, //Decoding halted
|
CELL_JPGDEC_DEC_STATUS_STOP = 1, // Decoding halted
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CellJpgDecOutputMode
|
||||||
|
{
|
||||||
|
CELL_JPGDEC_TOP_TO_BOTTOM = 0, // Top left to bottom right
|
||||||
|
CELL_JPGDEC_BOTTOM_TO_TOP = 1, // Bottom left to top right
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CellJpgDecInfo
|
struct CellJpgDecInfo
|
||||||
|
|
|
@ -237,12 +237,11 @@ int cellPngDecDecodeData(u32 mainHandle, u32 subHandle, mem8_ptr_t data, const m
|
||||||
|
|
||||||
const bool flip = current_outParam.outputMode == CELL_PNGDEC_BOTTOM_TO_TOP;
|
const bool flip = current_outParam.outputMode == CELL_PNGDEC_BOTTOM_TO_TOP;
|
||||||
const int bytesPerLine = dataCtrlParam->outputBytesPerLine;
|
const int bytesPerLine = dataCtrlParam->outputBytesPerLine;
|
||||||
|
|
||||||
uint image_size = width * height;
|
uint image_size = width * height;
|
||||||
|
|
||||||
switch((u32)current_outParam.outputColorSpace)
|
switch((u32)current_outParam.outputColorSpace)
|
||||||
{
|
{
|
||||||
case CELL_PNGDEC_RGB:
|
case CELL_PNGDEC_RGB:
|
||||||
image_size = width * height;
|
|
||||||
case CELL_PNGDEC_RGBA:
|
case CELL_PNGDEC_RGBA:
|
||||||
{
|
{
|
||||||
const char nComponents = current_outParam.outputColorSpace == CELL_PNGDEC_RGBA ? 4 : 3;
|
const char nComponents = current_outParam.outputColorSpace == CELL_PNGDEC_RGBA ? 4 : 3;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue