-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #29 from LanternEQ/feature/libgdiplus
Rework libgdiplus hacks
- Loading branch information
Showing
2 changed files
with
134 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
using System; | ||
using System.Drawing; | ||
using System.Drawing.Imaging; | ||
using System.IO; | ||
using System.Linq; | ||
|
||
namespace LanternExtractor.Infrastructure | ||
{ | ||
/// <summary> | ||
/// Wrapper over Bitmap with various hacks to make libgdiplus | ||
/// consistently create transparent pngs on MacOS & Linux | ||
/// </summary> | ||
public class EqBmp | ||
{ | ||
private static readonly bool _needsGdipHacks = Environment.OSVersion.Platform == PlatformID.MacOSX || | ||
Environment.OSVersion.Platform == PlatformID.Unix; | ||
private static bool _hasCheckedForPaletteFlagsField; | ||
private static System.Reflection.FieldInfo _paletteFlagsField = null; | ||
|
||
public PixelFormat PixelFormat => _bitmap.PixelFormat; | ||
|
||
private readonly Bitmap _bitmap; | ||
private readonly ColorPalette _palette; | ||
|
||
public EqBmp(Stream stream) | ||
{ | ||
SetPaletteFlagsField(); | ||
|
||
_bitmap = new Bitmap(stream); | ||
_palette = _bitmap.Palette; | ||
} | ||
|
||
public void WritePng(string outputFilePath) | ||
{ | ||
_bitmap.Save(outputFilePath, ImageFormat.Png); | ||
} | ||
|
||
public void MakeMagentaTransparent() | ||
{ | ||
_bitmap.MakeTransparent(Color.Magenta); | ||
if (_needsGdipHacks) | ||
{ | ||
// https://github.com/ mono/libgdiplus/commit/bf9a1440b7bfea704bf2cb771f5c2b5c09e7bcfa | ||
_bitmap.MakeTransparent(Color.FromArgb(0, Color.Magenta)); | ||
} | ||
} | ||
|
||
public void MakePaletteTransparent(int transparentIndex) | ||
{ | ||
if (_needsGdipHacks) | ||
{ | ||
// https://github.com/mono/libgdiplus/issues/702 | ||
_paletteFlagsField?.SetValue(_palette, _palette.Flags | (int)PaletteFlags.HasAlpha); | ||
} | ||
|
||
var transparentColor = GetTransparentPaletteColor(); | ||
_palette.Entries[transparentIndex] = transparentColor; | ||
_bitmap.Palette = _palette; | ||
|
||
if (_needsGdipHacks) | ||
{ | ||
// Due to a bug with the libgdiplus implementation of System.Drawing, setting a color palette | ||
// entry to transparent does not work. The workaround is to ensure that the transparent | ||
// key is unique and then use MakeTransparent() | ||
_bitmap.MakeTransparent(transparentColor); | ||
} | ||
} | ||
|
||
private Color GetTransparentPaletteColor() | ||
{ | ||
var transparencyColor = Color.FromArgb(0, 0, 0, 0); | ||
|
||
if (!_needsGdipHacks) | ||
{ | ||
return transparencyColor; | ||
} | ||
|
||
var random = new Random(); | ||
var foundUnique = false; | ||
|
||
while (!foundUnique) | ||
{ | ||
foundUnique = _palette.Entries.All(e => e != transparencyColor); | ||
transparencyColor = Color.FromArgb(0, random.Next(256), random.Next(256), random.Next(256)); | ||
} | ||
|
||
return transparencyColor; | ||
} | ||
|
||
// https://github.com/Robmaister/SharpFont/blob/422bdab059dd8e594b4b061a3b53152e71342ce2/Source/SharpFont.GDI/FTBitmapExtensions.cs | ||
// https://github.com/Robmaister/SharpFont/pull/136 | ||
private static void SetPaletteFlagsField() | ||
{ | ||
if (!_needsGdipHacks || _hasCheckedForPaletteFlagsField) | ||
{ | ||
return; | ||
} | ||
|
||
_hasCheckedForPaletteFlagsField = true; | ||
|
||
// The field needed may be named "flags" or "_flags", dependin on the version of Mono. To be thorough, check for the first Name that contains "lags". | ||
var fields = typeof(ColorPalette).GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); | ||
|
||
for (int i = 0; i < fields.Length; i++) | ||
{ | ||
if (fields[i].Name.Contains("lags")) | ||
{ | ||
_paletteFlagsField = fields[i]; | ||
break; | ||
} | ||
} | ||
} | ||
|
||
enum PaletteFlags | ||
{ | ||
HasAlpha = 0x0001, | ||
GrayScale = 0x0002, | ||
HalfTone = 0x0004, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters