Skip to content

Fix Image Gamma Unsupported By glTF#138

Merged
vnoves merged 1 commit intodevelopfrom
86b7dh14u/FixImageUnsuportedFeatures
Nov 12, 2025
Merged

Fix Image Gamma Unsupported By glTF#138
vnoves merged 1 commit intodevelopfrom
86b7dh14u/FixImageUnsuportedFeatures

Conversation

@vnoves
Copy link
Member

@vnoves vnoves commented Nov 12, 2025

Summary by CodeRabbit

  • New Features
    • Added automatic gamma and ICC profile normalization to the image export process, ensuring cleaner, more consistent sRGB color representation across all exported textures and improved overall texture quality.

@coderabbitai
Copy link

coderabbitai bot commented Nov 12, 2025

Walkthrough

A new CleanGamma method is added to BitmapsUtils to re-encode images to clean sRGB format by removing gamma and ICC profile metadata. ExportImageBuffer is modified to use this new method when processing embedded textures, applying gamma correction before blending operations.

Changes

Cohort / File(s) Summary
New gamma-cleaning utility
Common_glTF_Exporter/Materials/BitmapsUtils.cs
Adds public method CleanGamma(string path, ImageFormat imageFormat) that loads an image, creates a 24bpp RGB target, renders the source into it, saves to memory stream, and returns bytes—effectively removing non-default gamma and ICC profiles.
Image buffer export integration
Common_glTF_Exporter/Utils/GLTFBinaryDataUtils.cs
Modifies ExportImageBuffer to retrieve MIME type via BitmapsUtils.GetMimeType, then process image bytes through new BitmapsUtils.CleanGamma method instead of direct file read, ensuring gamma correction occurs before blending.

Sequence Diagram(s)

sequenceDiagram
    participant EB as ExportImageBuffer
    participant BU as BitmapsUtils
    participant IM as Image Processing
    
    EB->>BU: GetMimeType(filePath)
    BU-->>EB: mimeType
    
    rect rgb(200, 220, 240)
    Note over EB,IM: NEW: Gamma Cleaning Path
    EB->>BU: CleanGamma(filePath, format)
    BU->>IM: Load source image
    BU->>IM: Create 24bpp RGB target
    BU->>IM: Render source → target
    BU->>IM: Save to memory stream
    IM-->>BU: cleaned imageBytes
    BU-->>EB: imageBytes (sRGB, no gamma)
    end
    
    EB->>EB: BlendImageWithColor (on cleaned bytes)
    EB->>EB: Setup buffer/view
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Verify the image re-encoding logic correctly removes gamma without introducing artifacts or unexpected color shifts
  • Ensure the new CleanGamma method handles edge cases (unsupported formats, null paths, corrupted images)
  • Confirm the modified ExportImageBuffer flow maintains backward compatibility with the blending operation

Possibly related PRs

  • Develop #108: Directly related—modifies the same BitmapsUtils and ExportImageBuffer methods for image-handling improvements.
  • Polish texture mapping #107: Related refactoring—updates both BitmapsUtils and ExportImageBuffer to use consistent image-processing utilities.

Poem

🐰 A gamma so clean, a sRGB dream,
No profiles to hide, no metadata gleam!
The image bytes shine without colors askew,
Before blending begins—fresh pixels, brand new! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix Image Gamma Unsupported By glTF' accurately summarizes the main change: adding gamma correction handling for glTF compatibility via the new CleanGamma method and its integration into the export pipeline.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 86b7dh14u/FixImageUnsuportedFeatures

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
Common_glTF_Exporter/Materials/BitmapsUtils.cs (1)

39-53: Consider adding error handling for I/O operations.

File and image operations can fail for various reasons (file not found, corrupted image, insufficient permissions). Consider wrapping the operations in a try-catch block or allowing exceptions to propagate with meaningful context.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3203698 and b58a474.

📒 Files selected for processing (2)
  • Common_glTF_Exporter/Materials/BitmapsUtils.cs (1 hunks)
  • Common_glTF_Exporter/Utils/GLTFBinaryDataUtils.cs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
Common_glTF_Exporter/Utils/GLTFBinaryDataUtils.cs (1)
Common_glTF_Exporter/Materials/BitmapsUtils.cs (3)
  • ImageFormat (14-31)
  • BitmapsUtils (12-164)
  • CleanGamma (39-53)
🔇 Additional comments (1)
Common_glTF_Exporter/Utils/GLTFBinaryDataUtils.cs (1)

214-218: Verify that unconditional gamma cleaning is appropriate for all embedded textures.

The change now applies gamma cleaning to all embedded textures. This adds processing overhead (decode → create new bitmap → draw → re-encode) compared to directly reading file bytes. While this ensures glTF compliance by removing custom gamma/ICC profiles, consider whether:

  1. All textures need this processing, or only those with non-standard gamma/ICC profiles
  2. The performance impact is acceptable for your use case (especially with many/large textures)
  3. This aligns with the intended behavior when textures are already in sRGB

The logic correctly integrates the new CleanGamma method and the approach of cleaning gamma before blending makes sense for glTF compliance.

/// by re-encoding it to a clean sRGB version in memory.
/// </summary>
/// <param name="path">Path to the source image</param>
/// <returns>Byte array of the cleaned image (PNG)</returns>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Update documentation to reflect parameterized format.

The documentation states "Byte array of the cleaned image (PNG)" but the method returns the format specified by the imageFormat parameter, which could be JPEG, BMP, or GIF.

Apply this diff:

-    /// <returns>Byte array of the cleaned image (PNG)</returns>
+    /// <returns>Byte array of the cleaned image in the specified format</returns>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// <returns>Byte array of the cleaned image (PNG)</returns>
/// <returns>Byte array of the cleaned image in the specified format</returns>
🤖 Prompt for AI Agents
In Common_glTF_Exporter/Materials/BitmapsUtils.cs around line 38, the XML
summary/returns documentation incorrectly states the method always returns a PNG
byte array; update the XML comments to reflect that the returned byte array
format is determined by the imageFormat parameter (add/adjust a <param
name="imageFormat"> describing accepted formats and modify the <returns> text to
say it returns a byte array in the specified image format such as PNG, JPEG,
BMP, or GIF). Ensure the doc mentions the imageFormat parameter and that the
return value corresponds to that format.

Comment on lines +39 to +53
public static byte[] CleanGamma(string path, ImageFormat imageFormat)
{
using (var original = new Bitmap(path))
using (var ms = new MemoryStream())
{
// Convert to standard sRGB (System.Drawing assumes sRGB by default)
using (var converted = new Bitmap(original.Width, original.Height, PixelFormat.Format24bppRgb))
using (var g = Graphics.FromImage(converted))
{
g.DrawImage(original, 0, 0, original.Width, original.Height);
converted.Save(ms, imageFormat);
}
return ms.ToArray();
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Alpha channel is lost when using Format24bppRgb.

The method uses PixelFormat.Format24bppRgb which strips the alpha channel from images with transparency. This will break any textures that require transparency (e.g., cutout materials, decals). glTF fully supports texture transparency, so this data should be preserved.

Apply this diff to preserve alpha:

-                using (var converted = new Bitmap(original.Width, original.Height, PixelFormat.Format24bppRgb))
+                using (var converted = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public static byte[] CleanGamma(string path, ImageFormat imageFormat)
{
using (var original = new Bitmap(path))
using (var ms = new MemoryStream())
{
// Convert to standard sRGB (System.Drawing assumes sRGB by default)
using (var converted = new Bitmap(original.Width, original.Height, PixelFormat.Format24bppRgb))
using (var g = Graphics.FromImage(converted))
{
g.DrawImage(original, 0, 0, original.Width, original.Height);
converted.Save(ms, imageFormat);
}
return ms.ToArray();
}
}
public static byte[] CleanGamma(string path, ImageFormat imageFormat)
{
using (var original = new Bitmap(path))
using (var ms = new MemoryStream())
{
// Convert to standard sRGB (System.Drawing assumes sRGB by default)
using (var converted = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb))
using (var g = Graphics.FromImage(converted))
{
g.DrawImage(original, 0, 0, original.Width, original.Height);
converted.Save(ms, imageFormat);
}
return ms.ToArray();
}
}
🤖 Prompt for AI Agents
In Common_glTF_Exporter/Materials/BitmapsUtils.cs around lines 39 to 53, the
current conversion uses PixelFormat.Format24bppRgb which discards the alpha
channel; change the conversion to a 32-bit format that preserves alpha (e.g.,
PixelFormat.Format32bppArgb) and draw the source into that bitmap while ensuring
the Graphics compositing mode preserves alpha (SourceOver/SourceCopy as
appropriate); then save to the MemoryStream with an image format/encoder that
supports alpha (e.g., PNG) or fall back to the provided imageFormat only if it
supports transparency, so transparent pixels are retained for glTF textures.

@vnoves vnoves merged commit e92a6fb into develop Nov 12, 2025
2 checks passed
@vnoves vnoves deleted the 86b7dh14u/FixImageUnsuportedFeatures branch November 26, 2025 14:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant