Skip to content

Commit

Permalink
More tImagePNG 16-bpc support. All functions except for Save.
Browse files Browse the repository at this point in the history
  • Loading branch information
bluescan committed Jan 27, 2024
1 parent 243957a commit 86d887b
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 13 deletions.
18 changes: 12 additions & 6 deletions Modules/Image/Inc/Image/tImagePNG.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,12 @@ class tImagePNG : public tBaseImage
};

// Saves the tImagePNG to the PNG file specified. The type of filename must be PNG. If tFormat is Auto, this
// function will decide the format. BPP24 if all image pixels are opaque and BPP32 otherwise. Returns the format
// that the file was saved in, or tFormat::Invalid if there was a problem. Since Invalid is 0, you can use an 'if'.
// function will decide the format. If the internal buffer is 8-bpc it will choose between BPP24 and BPP32 depending
// on opacity (BPP24 is all pixels are opaque). In the internal buffer is 16-bpc it chooses between BPP48 and BPP64.
// When tFormat is explicitly one of the BPPNN choices, it may need to convert the data. For example, if the
// internal buffer is 8-bpc and you choose to save BPP48 or BPP64 (both 16-bpc formats), a conversion must take
// place. Returns the format that the file was saved in, or tFormat::Invalid if there was a problem. Since Invalid
// is 0, you can use an 'if' to check success.
tFormat Save(const tString& pngFile, tFormat) const;
tFormat Save(const tString& pngFile, const SaveParams& = SaveParams()) const;

Expand All @@ -129,15 +133,17 @@ class tImagePNG : public tBaseImage
int GetHeight() const { return Height; }
bool IsOpaque() const;

// After this call you are the owner of the pixels and must eventually delete[] them. This tImagePNG object is
// invalid afterwards.
tPixel4b* StealPixels();
// After this call you are the owner of the pixels and must eventually delete[] them. This call only returns the
// stolen pixel array if it was present. If it was, the tImagePNG object will be invalid afterwards.
tPixel4b* StealPixels8();
tPixel4s* StealPixels16();

tFrame* GetFrame(bool steal = true) override;
tPixel4b* GetPixels8() const { return Pixels8; }
tPixel4s* GetPixels16() const { return Pixels16; }

tPixelFormat GetPixelFormatSrc() const override { return IsValid() ? PixelFormatSrc : tPixelFormat::Invalid; }
tPixelFormat GetPixelFormat() const override { return IsValid() ? tPixelFormat::R8G8B8A8 : tPixelFormat::Invalid; }
tPixelFormat GetPixelFormat() const override { return IsValid() ? PixelFormat : tPixelFormat::Invalid; }

// Returns the colour profile of the source file that was loaded. This may not match the current if, say, gamma
// correction was requested on load.
Expand Down
6 changes: 4 additions & 2 deletions Modules/Image/Src/tImageICO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,15 +235,17 @@ tFrame* tImageICO::CreateFrame(const uint8* cursor, int width, int height, int n
// ICO files may have embedded pngs.
if (icon->Header.Size == 0x474e5089)
{
tImagePNG pngImage(cursor, numBytes);
tImagePNG::LoadParams params;
tAssert(params.Flags & tImagePNG::LoadFlag_ForceToBpc8);
tImagePNG pngImage(cursor, numBytes, params);
if (!pngImage.IsValid())
return nullptr;

width = pngImage.GetWidth();
height = pngImage.GetHeight();
tAssert((width > 0) && (height > 0));

tPixel4b* pixels = pngImage.StealPixels();
tPixel4b* pixels = pngImage.StealPixels8();
bool isOpaque = pngImage.IsOpaque();

tFrame* newFrame = new tFrame;
Expand Down
32 changes: 29 additions & 3 deletions Modules/Image/Src/tImagePNG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ tImagePNG::tFormat tImagePNG::Save(const tString& pngFile, const SaveParams& par
case tFormat::Auto: srcBytesPerPixel = IsOpaque() ? 3 : 4; break;
case tFormat::BPP24_RGB_BPC8: srcBytesPerPixel = 3; break;
case tFormat::BPP32_RGBA_BPC8: srcBytesPerPixel = 4; break;
// BPP48_RGB_BPC16, // 48-bit RGB. 3 16-bit components.
// BPP64_RGBA_BPC16, // 64-bit RGBA. 4 16-bit components.
}
if (!srcBytesPerPixel)
return tFormat::Invalid;
Expand Down Expand Up @@ -389,7 +391,8 @@ tImagePNG::tFormat tImagePNG::Save(const tString& pngFile, const SaveParams& par
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE
);

// Optional significant bit (sBIT) chunk.
// The sBIT chunk tells the decoder the number of significant bits in the pixel data. It is optional
// as the data is still stored as either 8 or 16 bits per component,
png_color_8 sigBit;
sigBit.red = 8;
sigBit.green = 8;
Expand Down Expand Up @@ -456,14 +459,24 @@ bool tImagePNG::IsOpaque() const
return false;
}
}
// @wip Else do the 16 bpc.
else if (Pixels16)
{
for (int p = 0; p < (Width*Height); p++)
{
if (Pixels16[p].A < 65535)
return false;
}
}

return true;
}


tPixel4b* tImagePNG::StealPixels()
tPixel4b* tImagePNG::StealPixels8()
{
if (!Pixels8)
return nullptr;

tPixel4b* pixels = Pixels8;
Pixels8 = nullptr;
Width = 0;
Expand All @@ -472,4 +485,17 @@ tPixel4b* tImagePNG::StealPixels()
}


tPixel4s* tImagePNG::StealPixels16()
{
if (!Pixels16)
return nullptr;

tPixel4s* pixels = Pixels16;
Pixels16 = nullptr;
Width = 0;
Height = 0;
return pixels;
}


}
4 changes: 2 additions & 2 deletions UnitTests/Src/TestImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,7 @@ tTestUnit(ImageRotation)
// Test writing rotated images.
tImagePNG aropng("TestData/Images/PNG/RightArrow.png");
int w = aropng.GetWidth(); int h = aropng.GetHeight();
tPicture aroPic(w, h, aropng.StealPixels(), false);
tPicture aroPic(w, h, aropng.StealPixels8(), false);
tRequire(aroPic.IsValid());

tPrintf("Image dimensions before rotate: W:%d H:%d\n", aroPic.GetWidth(), aroPic.GetHeight());
Expand Down Expand Up @@ -891,7 +891,7 @@ tTestUnit(ImageRotation)
tPrintf("Test 'plane' rotation.\n");
tImagePNG planepng("TestData/Images/PNG/plane.png");
w = planepng.GetWidth(); h = planepng.GetHeight();
tPicture planePic(w, h, planepng.StealPixels(), false);
tPicture planePic(w, h, planepng.StealPixels8(), false);
w = planePic.GetWidth();
h = planePic.GetHeight();
planePic.RotateCenter(-tMath::PiOver4, tColour4b::transparent);
Expand Down

0 comments on commit 86d887b

Please sign in to comment.