UltimateZoneBuilder/Source/Core/Data/ImageDataFormat.cs

159 lines
5.8 KiB
C#
Executable file

#region ================== Copyright (c) 2007 Pascal vd Heiden
/*
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
* This program is released under GNU General Public License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#endregion
#region ================== Namespaces
using System.IO;
using CodeImp.DoomBuilder.IO;
#endregion
namespace CodeImp.DoomBuilder.Data
{
internal static class ImageDataFormat
{
// Input guess formats
public const int UNKNOWN = 0; // No clue.
public const int DOOMPICTURE = 1; // Could be Doom Picture format (column list rendered data)
public const int DOOMFLAT = 2; // Could be Doom Flat format (raw 8-bit pixel data)
public const int DOOMCOLORMAP = 3; // Could be Doom Colormap format (raw 8-bit pixel palette mapping)
// File format signatures
private static readonly int[] PNG_SIGNATURE = new[] { 137, 80, 78, 71, 13, 10, 26, 10 };
private static readonly int[] GIF_SIGNATURE = new[] { 71, 73, 70 };
private static readonly int[] BMP_SIGNATURE = new[] { 66, 77 };
private static readonly int[] DDS_SIGNATURE = new[] { 68, 68, 83, 32 };
private static readonly int[] JPG_SIGNATURE = new[] { 255, 216, 255 }; //mxd
private static readonly int[] PCX_SIGNATURE = new[] { 10, 5, 1, 8 }; //mxd
// This check image data and returns the appropriate image reader
public static IImageReader GetImageReader(Stream data, int guessformat, Playpal palette)
{
if(data == null) return new UnknownImageReader(); //mxd
// [ZZ] If it's 4096 bytes long, and expected to be a flat, ignore all further checks.
// This is __NOT__ the good way to resolve it, but at least it works somewhat.
// I don't think if much can be done given the fact that Doom graphics are headerless themselves.
// https://forum.zdoom.org/viewtopic.php?p=1047520#p1047520
if (data.Length == 4096 && guessformat == DOOMFLAT)
{
DoomFlatReader flatreader = new DoomFlatReader(palette);
if (flatreader.Validate(data)) return flatreader;
}
// Data long enough to check for signatures?
if (data.Length > 10)
{
// Check for PNG signature
if(CheckSignature(data, PNG_SIGNATURE)) return new FileImageReader(DevilImageType.IL_PNG);
// Check for DDS signature
if(CheckSignature(data, DDS_SIGNATURE)) return new FileImageReader(DevilImageType.IL_DDS);
//mxd. Check for PCX signature
if(CheckSignature(data, PCX_SIGNATURE)) return new FileImageReader(DevilImageType.IL_PCX);
//mxd. Check for JPG signature
if(CheckSignature(data, JPG_SIGNATURE)) return new FileImageReader(DevilImageType.IL_JPG);
//mxd. TGA is VERY special in that it doesn't have a proper signature...
if(CheckTgaSignature(data)) return new FileImageReader(DevilImageType.IL_TGA);
// Check for GIF signature
if(CheckSignature(data, GIF_SIGNATURE)) return new UnknownImageReader(); //mxd. Not supported by (G)ZDoom
// Check for BMP signature
if(CheckSignature(data, BMP_SIGNATURE)) return new UnknownImageReader(); //mxd. Not supported by (G)ZDoom
}
// Could it be a doom picture?
switch(guessformat)
{
case DOOMPICTURE:
// Check if data is valid for a doom picture
data.Seek(0, SeekOrigin.Begin);
DoomPictureReader picreader = new DoomPictureReader(palette);
if(picreader.Validate(data)) return picreader;
break;
case DOOMFLAT:
// Check if data is valid for a doom flat
data.Seek(0, SeekOrigin.Begin);
DoomFlatReader flatreader = new DoomFlatReader(palette);
if(flatreader.Validate(data)) return flatreader;
break;
case DOOMCOLORMAP:
// Check if data is valid for a doom colormap
data.Seek(0, SeekOrigin.Begin);
DoomColormapReader colormapreader = new DoomColormapReader(palette);
if(colormapreader.Validate(data)) return colormapreader;
break;
}
// Format not supported
return new UnknownImageReader();
}
// This checks a signature as byte array
// NOTE: Expects the stream position to be at the start of the
// signature, and expects the stream to be long enough.
private static bool CheckSignature(Stream data, int[] sig)
{
//mxd. Rewind the data first
data.Seek(0, SeekOrigin.Begin);
// Go for all bytes
foreach(int s in sig)
{
// When byte doesnt match the signature, leave
if(data.ReadByte() != s) return false;
}
// Signature matches
return true;
}
//mxd. This tries to guess if a given image is in TGA format...
private static bool CheckTgaSignature(Stream data)
{
// TGA header is 18 bytes long
if(data.Length < 18) return false;
// Rewind the data first
data.Seek(0, SeekOrigin.Begin);
// Read TGA header
int idlength = data.ReadByte(); // Can be 0 or the length of ID string, whatever that is
int colormap = data.ReadByte(); // Can be 0 or 1
if(colormap != 0 && colormap != 1) return false;
int imagetype = data.ReadByte(); // Can be 0, 1, 2, 3, 9, 10, 11
if((imagetype > 3 && imagetype < 9) || imagetype > 11) return false;
data.Position += 9; // Skip some stuff...
int width = data.ReadByte() + (data.ReadByte() << 8);
if(width < 0 || width > 8192) return false;
int height = data.ReadByte() + (data.ReadByte() << 8);
if(height < 0 || height > 8192) return false;
int bitsperpixel = data.ReadByte(); // Can be 8, 16, 24, 32
return (bitsperpixel == 8 || bitsperpixel == 16 || bitsperpixel == 24 || bitsperpixel == 32);
}
}
}