preliminary improvements to multimedia-picture plugin
This commit is contained in:
parent
6802fe19ea
commit
3183a87127
@ -19,8 +19,12 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using MBS.Framework;
|
||||
using MBS.Framework.UserInterface;
|
||||
using MBS.Framework.UserInterface.Layouts;
|
||||
using UniversalEditor.ObjectModels.Multimedia.Picture;
|
||||
|
||||
namespace UniversalEditor.Editors.Multimedia.Picture
|
||||
{
|
||||
partial class PictureEditor
|
||||
@ -38,5 +42,41 @@ namespace UniversalEditor.Editors.Multimedia.Picture
|
||||
this.Layout = new BoxLayout(Orientation.Vertical);
|
||||
this.Controls.Add(da, new BoxLayout.Constraints(true, true));
|
||||
}
|
||||
|
||||
protected override void OnCreated(EventArgs e)
|
||||
{
|
||||
base.OnCreated(e);
|
||||
|
||||
Context.AttachCommandEventHandler("ImageTransformRotateClockwise", ImageTransformRotateClockwise_Click);
|
||||
Context.AttachCommandEventHandler("ImageTransformRotateCounterclockwise", ImageTransformRotateCounterclockwise_Click);
|
||||
Context.AttachCommandEventHandler("ImageTransformRotate180", ImageTransformRotate180_Click);
|
||||
Context.AttachCommandEventHandler("ImageTransformRotateArbitrary", ImageTransformRotateArbitrary_Click);
|
||||
}
|
||||
|
||||
private void ImageTransformRotateClockwise_Click(object sender, EventArgs e)
|
||||
{
|
||||
BeginEdit();
|
||||
(this.ObjectModel as PictureObjectModel).Rotate(90);
|
||||
this.da.Picture = (this.ObjectModel as PictureObjectModel);
|
||||
EndEdit();
|
||||
}
|
||||
private void ImageTransformRotateCounterclockwise_Click(object sender, EventArgs e)
|
||||
{
|
||||
BeginEdit();
|
||||
(this.ObjectModel as PictureObjectModel).Rotate(-90);
|
||||
this.da.Picture = (this.ObjectModel as PictureObjectModel);
|
||||
EndEdit();
|
||||
}
|
||||
private void ImageTransformRotate180_Click(object sender, EventArgs e)
|
||||
{
|
||||
BeginEdit();
|
||||
(this.ObjectModel as PictureObjectModel).Rotate(180);
|
||||
this.da.Picture = (this.ObjectModel as PictureObjectModel);
|
||||
EndEdit();
|
||||
}
|
||||
private void ImageTransformRotateArbitrary_Click(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,13 +37,13 @@ namespace UniversalEditor.Plugins.Multimedia.UserInterface
|
||||
/// <param name="pic">The <see cref="PictureObjectModel" /> containing the image data to convert.</param>
|
||||
public static Image ToImage(this PictureObjectModel pic)
|
||||
{
|
||||
byte[] input = pic.ToByteArray();
|
||||
byte[] input = pic.ToByteArray(PixelFormat.RGBA);
|
||||
byte[] output = new byte[input.Length];
|
||||
for (int i = 0; i < input.Length; i += 4)
|
||||
{
|
||||
byte b = input[i];
|
||||
byte r = input[i];
|
||||
byte g = input[i + 1];
|
||||
byte r = input[i + 2];
|
||||
byte b = input[i + 2];
|
||||
byte a = input[i + 3];
|
||||
|
||||
output[i] = r;
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<Associations>
|
||||
<Association>
|
||||
<Filters>
|
||||
<Filter Title="Chaos Works Engine palette">
|
||||
<Filter Title="Chaos Works Engine palette" ContentType="application/x-chaosworks-spp" HintComparison="FilterThenMagic">
|
||||
<FileNameFilters>
|
||||
<FileNameFilter>*.spp</FileNameFilter>
|
||||
</FileNameFilters>
|
||||
|
||||
@ -154,6 +154,8 @@ namespace UniversalEditor.Plugins.ChaosWorks.DataFormats.Multimedia.PictureColle
|
||||
}
|
||||
br.Accessor.LoadPosition();
|
||||
|
||||
palette = EmbeddedPalette;
|
||||
|
||||
// now that we've loaded the frame definitions and embedded color palette,
|
||||
// we can go back and read the pixel data
|
||||
List<List<byte>> lists = new List<List<byte>>();
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
//
|
||||
// EXRChannel.cs
|
||||
//
|
||||
// Author:
|
||||
// Michael Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2021 Mike Becker's Software
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
namespace UniversalEditor.DataFormats.Multimedia.Picture.EXR
|
||||
{
|
||||
public class EXRChannel
|
||||
{
|
||||
public string Name { get; set; } = null;
|
||||
public EXRPixelType PixelType { get; set; } = EXRPixelType.UInt;
|
||||
public bool IsLinear { get; set; } = false;
|
||||
public int XSampling { get; set; } = 0;
|
||||
public int YSampling { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
//
|
||||
// EXRChromaticities.cs
|
||||
//
|
||||
// Author:
|
||||
// Michael Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2021 Mike Becker's Software
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
namespace UniversalEditor.DataFormats.Multimedia.Picture.EXR
|
||||
{
|
||||
public class EXRChromaticities
|
||||
{
|
||||
public float RedX { get; set; }
|
||||
public float RedY { get; set; }
|
||||
public float GreenX { get; set; }
|
||||
public float GreenY { get; set; }
|
||||
public float BlueX { get; set; }
|
||||
public float BlueY { get; set; }
|
||||
public float WhiteX { get; set; }
|
||||
public float WhiteY { get; set; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
//
|
||||
// EXRCompression.cs
|
||||
//
|
||||
// Author:
|
||||
// Michael Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2021 Mike Becker's Software
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
namespace UniversalEditor.DataFormats.Multimedia.Picture.EXR
|
||||
{
|
||||
public enum EXRCompression
|
||||
{
|
||||
None,
|
||||
RunLengthEncoding,
|
||||
ZipPerScanline,
|
||||
ZipPer16Scanline,
|
||||
PIZWavelet,
|
||||
PXR24Deflate,
|
||||
B44,
|
||||
B44A,
|
||||
DWAA,
|
||||
DWAB
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,431 @@
|
||||
//
|
||||
// EXRBaseDataFormat.cs
|
||||
//
|
||||
// Author:
|
||||
// Michael Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2021 Mike Becker's Software
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MBS.Framework.Drawing;
|
||||
using MBS.Framework.Settings;
|
||||
using UniversalEditor.Accessors;
|
||||
using UniversalEditor.IO;
|
||||
using UniversalEditor.ObjectModels.Multimedia.Picture;
|
||||
|
||||
namespace UniversalEditor.DataFormats.Multimedia.Picture.EXR
|
||||
{
|
||||
public class EXRDataFormat : DataFormat
|
||||
{
|
||||
public EXRDataFormat()
|
||||
{
|
||||
}
|
||||
|
||||
private static DataFormatReference _dfr = null;
|
||||
protected override DataFormatReference MakeReferenceInternal()
|
||||
{
|
||||
if (_dfr == null)
|
||||
{
|
||||
_dfr = base.MakeReferenceInternal();
|
||||
_dfr.Capabilities.Add(typeof(PictureObjectModel), DataFormatCapabilities.All);
|
||||
_dfr.ExportOptions.SettingsGroups[0].Settings.Add(new ChoiceSetting("LineOrder", "_Line order", EXRLineOrder.IncreasingY, new ChoiceSetting.ChoiceSettingValue[]
|
||||
{
|
||||
new ChoiceSetting.ChoiceSettingValue("IncreasingY", "Increasing", EXRLineOrder.IncreasingY),
|
||||
new ChoiceSetting.ChoiceSettingValue("DecreasingY", "Decreasing", EXRLineOrder.DecreasingY),
|
||||
new ChoiceSetting.ChoiceSettingValue("RandomY", "Random", EXRLineOrder.RandomY)
|
||||
}));
|
||||
}
|
||||
return _dfr;
|
||||
}
|
||||
|
||||
public readonly byte[] EXR_SIGNATURE = new byte[] { 0x76, 0x2F, 0x31, 0x01 };
|
||||
|
||||
public Dictionary<string, object> Properties { get; } = new Dictionary<string, object>();
|
||||
public EXRLineOrder LineOrder { get; set; } = EXRLineOrder.IncreasingY;
|
||||
|
||||
protected override void LoadInternal(ref ObjectModel objectModel)
|
||||
{
|
||||
PictureObjectModel pic = (objectModel as PictureObjectModel);
|
||||
if (pic == null)
|
||||
throw new ObjectModelNotSupportedException();
|
||||
|
||||
byte[] signature = Accessor.Reader.ReadBytes(4);
|
||||
if (!signature.Match(EXR_SIGNATURE))
|
||||
throw new InvalidDataFormatException("file does not begin with exr signature");
|
||||
|
||||
byte version = Accessor.Reader.ReadByte();
|
||||
EXRFlags flags = (EXRFlags) Accessor.Reader.ReadUInt24();
|
||||
|
||||
if ((flags & EXRFlags.Multipart) == EXRFlags.Multipart)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// The header component of the single-part file holds a single header (for single-part files).
|
||||
// Each header is a sequence of attributes ended by a null byte.
|
||||
// The file has the same structure as a 1.7 file. That is, the multi-part bit(bit 12) must be 0, and the single null
|
||||
// byte that signals the end of the headers must be omitted. This structure also applies to single-part deep data
|
||||
// files.
|
||||
ReadProperties(Accessor);
|
||||
|
||||
RequireProperty(new string[] { "dataWindow", "displayWindow", "lineOrder", "compression", "channels", "chromaticities" });
|
||||
|
||||
LineOrder = (EXRLineOrder)Properties["lineOrder"];
|
||||
|
||||
Vector2D screenWindowCenter = new Vector2D(0, 0);
|
||||
PreferProperty("screenWindowCenter", ref screenWindowCenter);
|
||||
|
||||
int width = (int)((Rectangle)Properties["dataWindow"]).Width + 1;
|
||||
int height = (int)((Rectangle)Properties["dataWindow"]).Height + 1;
|
||||
pic.Width = width;
|
||||
pic.Height = height;
|
||||
|
||||
int chunkCount = 0;
|
||||
if (Properties.ContainsKey("chunkCount"))
|
||||
{
|
||||
chunkCount = (int)Properties["chunkCount"];
|
||||
}
|
||||
else if (((flags & EXRFlags.Multipart) == EXRFlags.Multipart) || (flags & EXRFlags.NonImage) == EXRFlags.NonImage)
|
||||
{
|
||||
throw new InvalidDataFormatException("multipart or non-image EXR file does not contain a chunkCount attribute");
|
||||
}
|
||||
else
|
||||
{
|
||||
chunkCount = height / 16;
|
||||
}
|
||||
|
||||
ulong[] chunkOffsets = new ulong[chunkCount];
|
||||
for (int i = 0; i < chunkCount; i++)
|
||||
{
|
||||
chunkOffsets[i] = Accessor.Reader.ReadUInt64();
|
||||
}
|
||||
|
||||
int scanlinesPerBlock = 0;
|
||||
|
||||
EXRCompression compressionMethod = (EXRCompression)Properties["compression"];
|
||||
switch (compressionMethod)
|
||||
{
|
||||
case EXRCompression.None:
|
||||
case EXRCompression.RunLengthEncoding:
|
||||
case EXRCompression.ZipPerScanline:
|
||||
{
|
||||
scanlinesPerBlock = 1;
|
||||
break;
|
||||
}
|
||||
case EXRCompression.ZipPer16Scanline:
|
||||
case EXRCompression.PXR24Deflate:
|
||||
{
|
||||
scanlinesPerBlock = 16;
|
||||
break;
|
||||
}
|
||||
case EXRCompression.PIZWavelet:
|
||||
case EXRCompression.B44:
|
||||
case EXRCompression.B44A:
|
||||
{
|
||||
scanlinesPerBlock = 32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EXRChannel[] channels = (EXRChannel[])Properties["channels"];
|
||||
EXRChromaticities chromaticities = (EXRChromaticities)Properties["chromaticities"];
|
||||
|
||||
for (int i = 0; i < chunkCount; i++)
|
||||
{
|
||||
int scanlineOffsetY = Accessor.Reader.ReadInt32();
|
||||
uint compressedLength = Accessor.Reader.ReadUInt32();
|
||||
|
||||
byte[] compressedData = Accessor.Reader.ReadBytes(compressedLength);
|
||||
byte[] decompressedData = (new Compression.Modules.Zlib.ZlibCompressionModule()).Decompress(compressedData);
|
||||
|
||||
MemoryAccessor ma = new MemoryAccessor(decompressedData);
|
||||
|
||||
switch (LineOrder)
|
||||
{
|
||||
case EXRLineOrder.IncreasingY:
|
||||
{
|
||||
for (int y = 0; y < scanlinesPerBlock; y++)
|
||||
{
|
||||
ReadChannels(ma.Reader, pic, channels, scanlineOffsetY + y);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EXRLineOrder.DecreasingY:
|
||||
{
|
||||
for (int y = scanlinesPerBlock - 1; y >= 0; y--)
|
||||
{
|
||||
ReadChannels(ma.Reader, pic, channels, scanlineOffsetY + y);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
System.IO.File.WriteAllBytes(String.Format("/tmp/zlib{0}.dat", scanlineOffsetY), decompressedData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the attribute data in <paramref name="data" /> to a <see cref="Object" /> instance of the appropriate
|
||||
/// type as indicated by <paramref name="dataType" />.
|
||||
///
|
||||
/// This method can be overridden in derived classes to implement support for data types other than those defined in
|
||||
/// the official OpenEXR specifications. To ensure backward compatibility with official OpenEXR implementations, it
|
||||
/// is recommended that you return the value returned from base.ConvertAttributeData(...) if it is not null (i.e., if
|
||||
/// support for that data type is already implemented in the base class).
|
||||
/// </summary>
|
||||
/// <returns>The attribute data.</returns>
|
||||
/// <param name="data">Data.</param>
|
||||
/// <param name="dataType">Data type.</param>
|
||||
protected virtual object ConvertAttributeData(byte[] data, string dataType)
|
||||
{
|
||||
object propertyData = null;
|
||||
MemoryAccessor acc = new MemoryAccessor(data);
|
||||
switch (dataType)
|
||||
{
|
||||
case "chlist":
|
||||
{
|
||||
List<EXRChannel> chlist = new List<EXRChannel>();
|
||||
while (!acc.Reader.EndOfStream)
|
||||
{
|
||||
string name = acc.Reader.ReadNullTerminatedString();
|
||||
if (String.IsNullOrEmpty(name))
|
||||
break;
|
||||
|
||||
EXRChannel channel = new EXRChannel();
|
||||
channel.Name = name;
|
||||
channel.PixelType = (EXRPixelType)acc.Reader.ReadInt32();
|
||||
channel.IsLinear = (acc.Reader.ReadUInt32() == 1);
|
||||
channel.XSampling = acc.Reader.ReadInt32();
|
||||
channel.YSampling = acc.Reader.ReadInt32();
|
||||
chlist.Add(channel);
|
||||
}
|
||||
propertyData = chlist.ToArray();
|
||||
break;
|
||||
}
|
||||
case "chromaticities":
|
||||
{
|
||||
EXRChromaticities chromaticities = new EXRChromaticities();
|
||||
chromaticities.RedX = acc.Reader.ReadSingle();
|
||||
chromaticities.RedY = acc.Reader.ReadSingle();
|
||||
chromaticities.GreenX = acc.Reader.ReadSingle();
|
||||
chromaticities.GreenY = acc.Reader.ReadSingle();
|
||||
chromaticities.BlueX = acc.Reader.ReadSingle();
|
||||
chromaticities.BlueY = acc.Reader.ReadSingle();
|
||||
chromaticities.WhiteX = acc.Reader.ReadSingle();
|
||||
chromaticities.WhiteY = acc.Reader.ReadSingle();
|
||||
propertyData = chromaticities;
|
||||
break;
|
||||
}
|
||||
case "compression":
|
||||
{
|
||||
if (data.Length == 1)
|
||||
{
|
||||
propertyData = (EXRCompression)acc.Reader.ReadByte();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataFormatException("property data size mismatch");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "lineOrder":
|
||||
{
|
||||
if (data.Length == 1)
|
||||
{
|
||||
propertyData = (EXRLineOrder)acc.Reader.ReadByte();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataFormatException("property data size mismatch");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "box2i":
|
||||
{
|
||||
if (data.Length == 16)
|
||||
{
|
||||
uint x = acc.Reader.ReadUInt32();
|
||||
uint y = acc.Reader.ReadUInt32();
|
||||
uint w = acc.Reader.ReadUInt32();
|
||||
uint h = acc.Reader.ReadUInt32();
|
||||
propertyData = new MBS.Framework.Drawing.Rectangle(x, y, w, h);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataFormatException("property data size mismatch");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "v2f":
|
||||
{
|
||||
if (data.Length == 8)
|
||||
{
|
||||
float x = acc.Reader.ReadSingle();
|
||||
float y = acc.Reader.ReadSingle();
|
||||
propertyData = new MBS.Framework.Drawing.Vector2D(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataFormatException("property data size mismatch");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "float":
|
||||
{
|
||||
if (data.Length == 4)
|
||||
{
|
||||
propertyData = acc.Reader.ReadSingle();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataFormatException("property data size mismatch");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return propertyData;
|
||||
}
|
||||
|
||||
private void ReadChannels(Reader reader, PictureObjectModel pic, EXRChannel[] channels, int y)
|
||||
{
|
||||
for (int c = 0; c < channels.Length; c++)
|
||||
{
|
||||
for (int x = 0; x < pic.Width; x++)
|
||||
{
|
||||
Color color = pic.GetPixel(x, y);
|
||||
color.A = 1.0;
|
||||
switch (channels[c].Name)
|
||||
{
|
||||
case "R":
|
||||
{
|
||||
color.R = ReadPixelComponent(reader, channels[c].PixelType);
|
||||
break;
|
||||
}
|
||||
case "G":
|
||||
{
|
||||
color.G = ReadPixelComponent(reader, channels[c].PixelType);
|
||||
break;
|
||||
}
|
||||
case "B":
|
||||
{
|
||||
color.B = ReadPixelComponent(reader, channels[c].PixelType);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Console.Error.WriteLine("channel '{0}' not handled", channels[c].Name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Console.WriteLine("setpixel ({0}, {1}) : {2}", x, y, color.ToString());
|
||||
pic.SetPixel(color, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that a property with the given
|
||||
/// <paramref name="propertyName" /> is preferred to be defined; however,
|
||||
/// if the property is not defined, use the value specified by
|
||||
/// <paramref name="propertyValue" />.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">The name of the property to check.</param>
|
||||
/// <param name="propertyValue">The value to assign property to.</param>
|
||||
/// <typeparam name="T">The expected type of the property.</typeparam>
|
||||
private void PreferProperty<T>(string propertyName, ref T propertyValue)
|
||||
{
|
||||
if (Properties.ContainsKey(propertyName))
|
||||
{
|
||||
object value = Properties[propertyName];
|
||||
if (value is T)
|
||||
{
|
||||
propertyValue = (T)Properties[propertyName];
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error.WriteLine(String.Format("exr: required attribute '{0}' not of type '{1}'; assuming {2}", propertyName, typeof(T).Name, propertyValue));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error.WriteLine(String.Format("exr: required attribute '{0}' not found; assuming {1}", propertyName, propertyValue));
|
||||
}
|
||||
}
|
||||
|
||||
private void RequireProperty(string propertyName)
|
||||
{
|
||||
RequireProperty(new string[] { propertyName });
|
||||
}
|
||||
private void RequireProperty(string[] propertyNames)
|
||||
{
|
||||
for (int i = 0; i < propertyNames.Length; i++)
|
||||
{
|
||||
if (!Properties.ContainsKey(propertyNames[i]))
|
||||
{
|
||||
throw new InvalidDataFormatException(String.Format("exr file does not contain required '{0}' attribute", propertyNames[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private double ReadPixelComponent(Reader reader, EXRPixelType pixelType)
|
||||
{
|
||||
switch (pixelType)
|
||||
{
|
||||
case EXRPixelType.Float:
|
||||
{
|
||||
return (double)reader.ReadSingle();
|
||||
}
|
||||
case EXRPixelType.Half:
|
||||
{
|
||||
ushort value = reader.ReadUInt16();
|
||||
return (double)value;
|
||||
}
|
||||
case EXRPixelType.UInt:
|
||||
{
|
||||
return (double)reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void ReadProperties(Accessor acc)
|
||||
{
|
||||
while (!acc.Reader.EndOfStream)
|
||||
{
|
||||
string propertyName = acc.Reader.ReadNullTerminatedString();
|
||||
if (String.IsNullOrEmpty(propertyName))
|
||||
break;
|
||||
|
||||
string propertyDataType = acc.Reader.ReadNullTerminatedString();
|
||||
uint propertyDataSize = acc.Reader.ReadUInt32();
|
||||
|
||||
object propertyData = null;
|
||||
byte[] propertyDataBytes = acc.Reader.ReadBytes(propertyDataSize);
|
||||
propertyData = ConvertAttributeData(propertyDataBytes, propertyDataType);
|
||||
if (propertyData == null)
|
||||
{
|
||||
propertyData = propertyDataBytes;
|
||||
}
|
||||
Properties[propertyName] = propertyData;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SaveInternal(ObjectModel objectModel)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
//
|
||||
// EXRFlags.cs
|
||||
//
|
||||
// Author:
|
||||
// Michael Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2021 Mike Becker's Software
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
namespace UniversalEditor.DataFormats.Multimedia.Picture.EXR
|
||||
{
|
||||
[Flags()]
|
||||
public enum EXRFlags
|
||||
{
|
||||
/// <summary>
|
||||
/// If set, this is a regular single-part image and the pixels are stored
|
||||
/// as tiles, and <see cref="NonImage" /> and <see cref="Multipart"/>
|
||||
/// flags must NOT be set.
|
||||
///
|
||||
/// This bit is for backwards compatibility with older libraries: it is
|
||||
/// only set when there is one "normal" tiled image in the file.
|
||||
/// </summary>
|
||||
SingleTile = 0x200,
|
||||
/// <summary>
|
||||
/// If set, the maximum length of attribute names, attribute type names,
|
||||
/// and channel names is 255 bytes. If not set, the maximum length is
|
||||
/// 31 bytes.
|
||||
/// </summary>
|
||||
LongName = 0x400,
|
||||
/// <summary>
|
||||
/// If set, there is at least one part which is not a regular scan line
|
||||
/// image or regular tiled image (that is, it is a deep format). If not
|
||||
/// set, all parts are entirely single or multiple scan line or tiled
|
||||
/// images.
|
||||
/// </summary>
|
||||
NonImage = 0x800,
|
||||
/// <summary>
|
||||
/// If set, the file does not contain exactly 1 part and the 'end of
|
||||
/// header' byte must be included at the end of each header part, and
|
||||
/// the part number fields must be added to the chunks. If not set, this
|
||||
/// is not a multi-part file and the 'end of header' byte and part number
|
||||
/// fields in chunks must be omitted. New in 2.0.
|
||||
/// </summary>
|
||||
Multipart = 0x1000
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
//
|
||||
// EXRLineOrder.cs
|
||||
//
|
||||
// Author:
|
||||
// Michael Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2021 Mike Becker's Software
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
namespace UniversalEditor.DataFormats.Multimedia.Picture.EXR
|
||||
{
|
||||
public enum EXRLineOrder
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that scan lines are stored in order of increasing Y
|
||||
/// coordinates.
|
||||
/// </summary>
|
||||
IncreasingY = 0,
|
||||
/// <summary>
|
||||
/// Indicates that scan lines are stored in order of decreasing Y
|
||||
/// coordinates.
|
||||
/// </summary>
|
||||
DecreasingY = 1,
|
||||
/// <summary>
|
||||
/// Indicates that scan lines are stored randomly. The proper order of
|
||||
/// scan lines can be found by reading the offset table, in which scan
|
||||
/// line offsets are stored in order of increasing Y coordinates.
|
||||
/// </summary>
|
||||
RandomY = 2
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
//
|
||||
// EXRPixelType.cs
|
||||
//
|
||||
// Author:
|
||||
// Michael Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2021 Mike Becker's Software
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
namespace UniversalEditor.DataFormats.Multimedia.Picture.EXR
|
||||
{
|
||||
public enum EXRPixelType
|
||||
{
|
||||
UInt = 0,
|
||||
Half = 1,
|
||||
Float = 2
|
||||
}
|
||||
}
|
||||
@ -38,6 +38,8 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap
|
||||
public const int BITMAP_PALETTE_ENTRY_SIZE_24BIT = 3;
|
||||
public const int BITMAP_PALETTE_ENTRY_SIZE_32BIT = 4;
|
||||
|
||||
public BitmapCompression Compression { get; set; } = BitmapCompression.None;
|
||||
|
||||
/// <summary>
|
||||
/// The number of bits-per-pixel. The biBitCount member of the BITMAPINFOHEADER structure determines the
|
||||
/// number of bits that define each pixel and the maximum number of colors in the bitmap.
|
||||
@ -57,6 +59,15 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap
|
||||
new ChoiceSetting.ChoiceSettingValue("Monochrome", "Monochrome", BitmapBitsPerPixel.Monochrome),
|
||||
new ChoiceSetting.ChoiceSettingValue("TrueColor", "True color (24-bit R8G8B8)", BitmapBitsPerPixel.TrueColor)
|
||||
}));
|
||||
dfr.ExportOptions.SettingsGroups[0].Settings.Add(new ChoiceSetting(nameof(Compression), "_Compression", BitmapCompression.None, new ChoiceSetting.ChoiceSettingValue[]
|
||||
{
|
||||
new ChoiceSetting.ChoiceSettingValue("None", "None", BitmapCompression.None),
|
||||
new ChoiceSetting.ChoiceSettingValue("RLE8", "RLE8", BitmapCompression.RLE8),
|
||||
new ChoiceSetting.ChoiceSettingValue("RLE4", "RLE4", BitmapCompression.RLE4),
|
||||
new ChoiceSetting.ChoiceSettingValue("Bitfields", "Bitfields", BitmapCompression.Bitfields),
|
||||
new ChoiceSetting.ChoiceSettingValue("JPEG", "JPEG", BitmapCompression.JPEG),
|
||||
new ChoiceSetting.ChoiceSettingValue("PNG", "PNG", BitmapCompression.PNG)
|
||||
}));
|
||||
return dfr;
|
||||
}
|
||||
|
||||
@ -75,6 +86,9 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap
|
||||
/// <value>The vertical resolution, in pixels-per-meter, of the target device for the bitmap.</value>
|
||||
public int VerticalResolution { get; set; } = 0;
|
||||
|
||||
private const int DIV_5 = 31;
|
||||
private const int DIV_6 = 63;
|
||||
|
||||
protected override void LoadInternal(ref ObjectModel objectModel)
|
||||
{
|
||||
PictureObjectModel pic = (objectModel as PictureObjectModel);
|
||||
@ -262,10 +276,30 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap
|
||||
if (header.Compression == BitmapCompression.Bitfields)
|
||||
{
|
||||
// R5G6B5
|
||||
|
||||
// If the bV5Compression member of the
|
||||
// BITMAPV5HEADER is BI_BITFIELDS, the bmiColors
|
||||
// member contains three DWORD color masks that
|
||||
// specify the red, green, and blue components,
|
||||
// respectively, of each pixel. Each WORD in the
|
||||
// bitmap array represents a single pixel.
|
||||
short value = br.ReadInt16();
|
||||
b = (byte)(8 * value.GetBits(0, 5));
|
||||
g = (byte)(8 * value.GetBits(6, 6));
|
||||
r = (byte)(8 * value.GetBits(11, 5));
|
||||
|
||||
b = (byte)(value & header.Bitfields[0]); // R
|
||||
g = (byte)(value & header.Bitfields[1]); // R
|
||||
r = (byte)(value & header.Bitfields[2]); // R
|
||||
a = (byte)(value & header.Bitfields[3]); // R
|
||||
|
||||
/*
|
||||
b = (byte)(value.GetBits(0, 5));
|
||||
g = (byte)(value.GetBits(6, 5));
|
||||
r = (byte)(value.GetBits(11, 5));
|
||||
a = (byte)(value.GetBits(16, 1));
|
||||
|
||||
b = (byte)(((double)255 / DIV_5) * b);
|
||||
g = (byte)(((double)255 / DIV_5) * g);
|
||||
r = (byte)(((double)255 / DIV_5) * r);
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -276,6 +310,7 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap
|
||||
g = (byte)(8 * value.GetBits(5, 5));
|
||||
r = (byte)(8 * value.GetBits(10, 5));
|
||||
}
|
||||
a = 255;
|
||||
break;
|
||||
}
|
||||
case BitmapBitsPerPixel.TrueColor:
|
||||
@ -314,7 +349,11 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap
|
||||
Color color = Color.FromRGBAByte(r, g, b, a);
|
||||
pic.SetPixel(color, x, y);
|
||||
}
|
||||
br.Align(4);
|
||||
|
||||
if (PixelDepth != BitmapBitsPerPixel.DeepColor)
|
||||
{
|
||||
// br.Align(4);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void SaveInternal(ObjectModel objectModel)
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
//
|
||||
// HDRCompression.cs
|
||||
//
|
||||
// Author:
|
||||
// Michael Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2021 Mike Becker's Software
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
namespace UniversalEditor.DataFormats.Multimedia.Picture.Radiance
|
||||
{
|
||||
public enum HDRCompression
|
||||
{
|
||||
None = 0,
|
||||
RunLengthEncoding = 1,
|
||||
AdaptiveRunLengthEncoding = 2
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,176 @@
|
||||
//
|
||||
// HDRDataFormat.cs
|
||||
//
|
||||
// Author:
|
||||
// Michael Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2021 Mike Becker's Software
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MBS.Framework.Drawing;
|
||||
using MBS.Framework.Settings;
|
||||
using UniversalEditor.ObjectModels.Multimedia.Picture;
|
||||
|
||||
namespace UniversalEditor.DataFormats.Multimedia.Picture.Radiance
|
||||
{
|
||||
public class HDRDataFormat : DataFormat
|
||||
{
|
||||
private static DataFormatReference _dfr = null;
|
||||
protected override DataFormatReference MakeReferenceInternal()
|
||||
{
|
||||
if (_dfr == null)
|
||||
{
|
||||
_dfr = base.MakeReferenceInternal();
|
||||
_dfr.Capabilities.Add(typeof(PictureObjectModel), DataFormatCapabilities.All);
|
||||
_dfr.ExportOptions.SettingsGroups[0].Settings.Add(new ChoiceSetting("Compression", "Compression", HDRCompression.None, new ChoiceSetting.ChoiceSettingValue[]
|
||||
{
|
||||
new ChoiceSetting.ChoiceSettingValue("None", "None", HDRCompression.None),
|
||||
new ChoiceSetting.ChoiceSettingValue("RunLengthEncoding", "Run-length encoding (standard)", HDRCompression.RunLengthEncoding),
|
||||
new ChoiceSetting.ChoiceSettingValue("AdaptiveRunLengthEncoding", "Run-length encoding (adaptive)", HDRCompression.AdaptiveRunLengthEncoding)
|
||||
}));
|
||||
}
|
||||
return _dfr;
|
||||
}
|
||||
|
||||
public HDRCompression Compression { get; set; } = HDRCompression.None;
|
||||
|
||||
protected override void LoadInternal(ref ObjectModel objectModel)
|
||||
{
|
||||
PictureObjectModel pic = (objectModel as PictureObjectModel);
|
||||
if (pic == null)
|
||||
throw new ObjectModelNotSupportedException();
|
||||
|
||||
// pixels are stored one byte each R,G,B plus one byte shared exponent
|
||||
string signature = Accessor.Reader.ReadFixedLengthString(11);
|
||||
if (!signature.Equals("#?RADIANCE\n"))
|
||||
throw new InvalidDataFormatException("file does not begin with '#?RADIANCE\\n'");
|
||||
|
||||
while (!Accessor.Reader.EndOfStream)
|
||||
{
|
||||
string line = ReadLine(Accessor.Reader);
|
||||
if (String.IsNullOrEmpty(line))
|
||||
break;
|
||||
|
||||
string[] parts = line.Split(new char[] { '=' });
|
||||
|
||||
}
|
||||
|
||||
int xs = 0, ys = 0;
|
||||
int ydir = 0, xdir = 0;
|
||||
int width = 0, height = 0;
|
||||
|
||||
string args = ReadLine(Accessor.Reader);
|
||||
string[] argsparts = args.Split(new char[] { ' ' });
|
||||
for (int i = 0; i < argsparts.Length; i++)
|
||||
{
|
||||
if (argsparts[i].Equals("-Y"))
|
||||
{
|
||||
ydir = -1;
|
||||
height = Int32.Parse(argsparts[i + 1]);
|
||||
ys = height - 1;
|
||||
i++;
|
||||
}
|
||||
else if (argsparts[i].Equals("+Y"))
|
||||
{
|
||||
ydir = +1;
|
||||
height = Int32.Parse(argsparts[i + 1]);
|
||||
ys = 0;
|
||||
i++;
|
||||
}
|
||||
else if (argsparts[i].Equals("-X"))
|
||||
{
|
||||
xdir = -1;
|
||||
width = Int32.Parse(argsparts[i + 1]);
|
||||
xs = width - 1;
|
||||
i++;
|
||||
}
|
||||
else if (argsparts[i].Equals("+X"))
|
||||
{
|
||||
xdir = +1;
|
||||
width = Int32.Parse(argsparts[i + 1]);
|
||||
xs = 0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
pic.Width = width;
|
||||
pic.Height = height;
|
||||
|
||||
Color lastColor = Color.Empty; // for run-length encoding
|
||||
for (int y = ys; ec(y, height, ydir); y += ydir)
|
||||
{
|
||||
for (int x = xs; ec(x, width, xdir); x += xdir)
|
||||
{
|
||||
byte rz = Accessor.Reader.ReadByte();
|
||||
byte gz = Accessor.Reader.ReadByte();
|
||||
byte bz = Accessor.Reader.ReadByte();
|
||||
byte exponent = Accessor.Reader.ReadByte();
|
||||
|
||||
if (rz == 255 && gz == 255 && bz == 255)
|
||||
{
|
||||
// run length encoding, exponent is run count
|
||||
for (int i = 0; i < exponent; i++)
|
||||
{
|
||||
pic.SetPixel(lastColor, x, y);
|
||||
x++;
|
||||
|
||||
if (ec(x, width, xdir))
|
||||
{
|
||||
x = xs;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float r = 0, g = 0, b = 0;
|
||||
if (exponent != 0)
|
||||
{
|
||||
float f = MBS.Framework.MathExtensions.ldexp(1.0f, exponent - (int)(128 + 8));
|
||||
r = rz * f;
|
||||
g = gz * f;
|
||||
b = bz * f;
|
||||
}
|
||||
|
||||
Color color = Color.FromRGBASingle(r, g, b);
|
||||
pic.SetPixel(color, x, y);
|
||||
lastColor = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ec(int val, int max, int pixelDir)
|
||||
{
|
||||
if (pixelDir == 1)
|
||||
return (val < max);
|
||||
return (val >= 0);
|
||||
}
|
||||
|
||||
private static string ReadLine(IO.Reader reader)
|
||||
{
|
||||
string value = System.Text.Encoding.UTF8.GetString(reader.ReadUntil(new byte[] { 0x0A }));
|
||||
reader.ReadByte(); // clear the 0x0A
|
||||
return value;
|
||||
}
|
||||
|
||||
protected override void SaveInternal(ObjectModel objectModel)
|
||||
{
|
||||
PictureObjectModel pic = (objectModel as PictureObjectModel);
|
||||
if (pic == null)
|
||||
throw new ObjectModelNotSupportedException();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -55,16 +55,14 @@ namespace UniversalEditor.ObjectModels.Multimedia.Picture
|
||||
public List<Color> GenerateColorMap()
|
||||
{
|
||||
List<Color> colorMap = new List<MBS.Framework.Drawing.Color>();
|
||||
for (int index = 0; index < bitmapData.Length; index += 4)
|
||||
for (int x = 0; x < bitmapData.Length; x++)
|
||||
{
|
||||
byte a = bitmapData[index + 0];
|
||||
byte r = bitmapData[index + 1];
|
||||
byte g = bitmapData[index + 2];
|
||||
byte b = bitmapData[index + 3];
|
||||
|
||||
Color color = Color.FromRGBAByte(a, r, g, b);
|
||||
if (!colorMap.Contains(color))
|
||||
colorMap.Add(color);
|
||||
for (int y = 0; y < bitmapData[x].Length; y++)
|
||||
{
|
||||
Color color = bitmapData[x][y];
|
||||
if (!colorMap.Contains(color))
|
||||
colorMap.Add(color);
|
||||
}
|
||||
}
|
||||
return colorMap;
|
||||
}
|
||||
@ -85,7 +83,7 @@ namespace UniversalEditor.ObjectModels.Multimedia.Picture
|
||||
SetPixel(color, (int)lastAddedLocation.X, (int)lastAddedLocation.Y);
|
||||
lastAddedLocation.X++;
|
||||
}
|
||||
[System.Diagnostics.DebuggerNonUserCode]
|
||||
|
||||
public void SetPixel(Color color, int x, int y)
|
||||
{
|
||||
if (x >= mvarWidth || y >= mvarHeight)
|
||||
@ -94,24 +92,16 @@ namespace UniversalEditor.ObjectModels.Multimedia.Picture
|
||||
}
|
||||
|
||||
int index = (x + (y * mvarWidth)) * 4;
|
||||
bitmapData[index] = (byte)(color.R * 255);
|
||||
bitmapData[index + 1] = (byte)(color.G * 255);
|
||||
bitmapData[index + 2] = (byte)(color.B * 255);
|
||||
bitmapData[index + 3] = (byte)(color.A * 255);
|
||||
bitmapData[x][y] = color;
|
||||
|
||||
int realIndex = (int)(index / 4);
|
||||
bitmapDataSet[realIndex] = true;
|
||||
}
|
||||
public void ClearPixel(int x, int y)
|
||||
{
|
||||
int index = (int)((lastAddedLocation.X + (lastAddedLocation.Y * mvarWidth)) * 4);
|
||||
bitmapData[index] = 0;
|
||||
bitmapData[index + 1] = 0;
|
||||
bitmapData[index + 2] = 0;
|
||||
bitmapData[index + 3] = 0;
|
||||
bitmapData[x][y] = Color.Empty;
|
||||
|
||||
int realIndex = (int)(index / 4);
|
||||
bitmapDataSet[realIndex] = false;
|
||||
}
|
||||
public Color GetPixel(int x, int y)
|
||||
{
|
||||
@ -122,14 +112,9 @@ namespace UniversalEditor.ObjectModels.Multimedia.Picture
|
||||
|
||||
int index = (x + (y * mvarWidth)) * 4;
|
||||
int realIndex = (int)(index / 4);
|
||||
if (bitmapDataSet[realIndex])
|
||||
if (!bitmapData[x][y].IsEmpty)
|
||||
{
|
||||
byte a = bitmapData[index + 0];
|
||||
byte r = bitmapData[index + 1];
|
||||
byte g = bitmapData[index + 2];
|
||||
byte b = bitmapData[index + 3];
|
||||
|
||||
Color color = Color.FromRGBAByte(a, r, g, b);
|
||||
Color color = bitmapData[x][y];
|
||||
return color;
|
||||
}
|
||||
return Color.Empty;
|
||||
@ -139,21 +124,32 @@ namespace UniversalEditor.ObjectModels.Multimedia.Picture
|
||||
return GetPixel((int)point.X, (int)point.Y);
|
||||
}
|
||||
|
||||
private byte[] bitmapData = new byte[] { 0, 0, 0, 0 };
|
||||
private bool[] bitmapDataSet = new bool[] { false };
|
||||
private Color[][] bitmapData = new Color[0][];
|
||||
|
||||
public PictureObjectModel()
|
||||
{
|
||||
}
|
||||
public PictureObjectModel(int width, int height)
|
||||
{
|
||||
bitmapData = new byte[(width * height) * 4];
|
||||
bitmapDataSet = new bool[(width * height) * 4];
|
||||
InitializeBitmapData();
|
||||
|
||||
mvarWidth = width;
|
||||
mvarHeight = height;
|
||||
}
|
||||
|
||||
private static void InitializeBitmapData(ref Color[][] array, int width, int height)
|
||||
{
|
||||
array = new Color[width][];
|
||||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
array[i] = new Color[height];
|
||||
}
|
||||
}
|
||||
private void InitializeBitmapData()
|
||||
{
|
||||
InitializeBitmapData(ref bitmapData, Width, Height);
|
||||
}
|
||||
|
||||
private int mvarWidth = 1;
|
||||
public int Width
|
||||
{
|
||||
@ -161,8 +157,7 @@ namespace UniversalEditor.ObjectModels.Multimedia.Picture
|
||||
set
|
||||
{
|
||||
mvarWidth = value;
|
||||
bitmapData = new byte[mvarWidth * mvarHeight * 4];
|
||||
bitmapDataSet = new bool[mvarWidth * mvarHeight];
|
||||
InitializeBitmapData();
|
||||
}
|
||||
}
|
||||
private int mvarHeight = 1;
|
||||
@ -172,8 +167,19 @@ namespace UniversalEditor.ObjectModels.Multimedia.Picture
|
||||
set
|
||||
{
|
||||
mvarHeight = value;
|
||||
bitmapData = new byte[mvarWidth * mvarHeight * 4];
|
||||
bitmapDataSet = new bool[mvarWidth * mvarHeight];
|
||||
InitializeBitmapData();
|
||||
}
|
||||
}
|
||||
|
||||
public Dimension2D Size
|
||||
{
|
||||
get { return new Dimension2D(mvarWidth, mvarHeight); }
|
||||
set
|
||||
{
|
||||
mvarWidth = (int)value.Width;
|
||||
mvarHeight = (int)value.Height;
|
||||
|
||||
InitializeBitmapData();
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,11 +202,10 @@ namespace UniversalEditor.ObjectModels.Multimedia.Picture
|
||||
PictureObjectModel clone = (destination as PictureObjectModel);
|
||||
clone.Width = mvarWidth;
|
||||
clone.Height = mvarHeight;
|
||||
clone.bitmapData = (bitmapData.Clone() as byte[]);
|
||||
clone.bitmapDataSet = (bitmapDataSet.Clone() as bool[]);
|
||||
clone.bitmapData = (bitmapData.Clone() as Color[][]);
|
||||
}
|
||||
|
||||
public byte[] ToByteArray()
|
||||
public byte[] ToByteArray(PixelFormat format)
|
||||
{
|
||||
// memory goes from left to right, top to bottom
|
||||
byte[] data = new byte[mvarWidth * mvarHeight * 4];
|
||||
@ -211,14 +216,32 @@ namespace UniversalEditor.ObjectModels.Multimedia.Picture
|
||||
{
|
||||
int index = (w + (h * mvarWidth)) * 4;
|
||||
int realIndex = (int)(index / 4);
|
||||
if (bitmapDataSet[realIndex])
|
||||
|
||||
switch (format)
|
||||
{
|
||||
data[i + 3] = bitmapData[index + 3];
|
||||
data[i + 2] = bitmapData[index + 0];
|
||||
data[i + 1] = bitmapData[index + 1];
|
||||
data[i + 0] = bitmapData[index + 2];
|
||||
case PixelFormat.BGRA:
|
||||
{
|
||||
// BGRA layout
|
||||
data[i + 0] = bitmapData[w][h].GetBlueByte();
|
||||
data[i + 1] = bitmapData[w][h].GetGreenByte();
|
||||
data[i + 2] = bitmapData[w][h].GetRedByte();
|
||||
data[i + 3] = bitmapData[w][h].GetAlphaByte();
|
||||
|
||||
i += 4;
|
||||
break;
|
||||
}
|
||||
case PixelFormat.RGBA:
|
||||
{
|
||||
// RGBA layout
|
||||
data[i + 0] = bitmapData[w][h].GetRedByte();
|
||||
data[i + 1] = bitmapData[w][h].GetGreenByte();
|
||||
data[i + 2] = bitmapData[w][h].GetBlueByte();
|
||||
data[i + 3] = bitmapData[w][h].GetAlphaByte();
|
||||
|
||||
i += 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
i += 4;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
@ -258,5 +281,93 @@ namespace UniversalEditor.ObjectModels.Multimedia.Picture
|
||||
int stride = 4 * ((Width * bytesPerPixel + 3) / 4);
|
||||
return stride;
|
||||
}
|
||||
|
||||
public void Rotate(int degrees)
|
||||
{
|
||||
int oldheight = Height;
|
||||
int oldwidth = Width;
|
||||
|
||||
// fuck this ain't workin
|
||||
if (degrees % 360 == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
switch (degrees)
|
||||
{
|
||||
case -90:
|
||||
{
|
||||
Color[][] oldpixels = bitmapData;
|
||||
Size = new Dimension2D(Height, Width);
|
||||
|
||||
Color[][] pixels = null;
|
||||
InitializeBitmapData(ref pixels, Width, Height);
|
||||
|
||||
// 1 2 3
|
||||
// 4 5 6
|
||||
|
||||
// =>
|
||||
|
||||
// 3 6
|
||||
// 2 5
|
||||
// 1 4
|
||||
|
||||
int x1 = 0, y1 = 0;
|
||||
for (int y = 0; y < oldheight; y++)
|
||||
{
|
||||
for (int x = oldwidth - 1; x >= 0; x--)
|
||||
{
|
||||
pixels[x1][y1] = oldpixels[x][y];
|
||||
y1++;
|
||||
}
|
||||
y1 = 0;
|
||||
x1++;
|
||||
}
|
||||
|
||||
bitmapData = pixels;
|
||||
break;
|
||||
}
|
||||
case 90:
|
||||
{
|
||||
Color[][] oldpixels = bitmapData;
|
||||
Size = new Dimension2D(Height, Width);
|
||||
|
||||
Color[][] pixels = null;
|
||||
InitializeBitmapData(ref pixels, Width, Height);
|
||||
|
||||
// 1 2 3
|
||||
// 4 5 6
|
||||
|
||||
// =>
|
||||
|
||||
// 3 6
|
||||
// 2 5
|
||||
// 1 4
|
||||
|
||||
int x1 = 0, y1 = 0;
|
||||
for (int y = 0; y < oldheight; y++)
|
||||
{
|
||||
for (int x = oldwidth - 1; x >= 0; x--)
|
||||
{
|
||||
pixels[x1][y1] = oldpixels[x][y];
|
||||
y1++;
|
||||
}
|
||||
y1 = 0;
|
||||
x1++;
|
||||
}
|
||||
|
||||
bitmapData = pixels;
|
||||
break;
|
||||
}
|
||||
case 180:
|
||||
{
|
||||
|
||||
break;
|
||||
}
|
||||
case 270:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
//
|
||||
// PixelFormat.cs
|
||||
//
|
||||
// Author:
|
||||
// Michael Becker <alcexhim@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2021 Mike Becker's Software
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
namespace UniversalEditor.ObjectModels.Multimedia.Picture
|
||||
{
|
||||
public enum PixelFormat
|
||||
{
|
||||
BGRA,
|
||||
RGBA
|
||||
}
|
||||
}
|
||||
@ -344,6 +344,16 @@
|
||||
<Compile Include="DataFormats\Multimedia\Picture\KISS\CELDataFormat.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Picture\KISS\CELImageType.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Palette\KISS\KCFDataFormat.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Picture\EXR\EXRDataFormat.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Picture\EXR\EXRCompression.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Picture\EXR\EXRLineOrder.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Picture\EXR\EXRFlags.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Picture\EXR\EXRChannel.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Picture\EXR\EXRPixelType.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Picture\EXR\EXRChromaticities.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Picture\Radiance\HDRDataFormat.cs" />
|
||||
<Compile Include="DataFormats\Multimedia\Picture\Radiance\HDRCompression.cs" />
|
||||
<Compile Include="ObjectModels\Multimedia\Picture\PixelFormat.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Libraries\UniversalEditor.Compression\UniversalEditor.Compression.csproj">
|
||||
@ -406,6 +416,8 @@
|
||||
<Folder Include="DataFormats\Multimedia\Palette\Adobe\SwatchExchange\" />
|
||||
<Folder Include="DataFormats\Multimedia\Picture\KISS\" />
|
||||
<Folder Include="DataFormats\Multimedia\Palette\KISS\" />
|
||||
<Folder Include="DataFormats\Multimedia\Picture\EXR\" />
|
||||
<Folder Include="DataFormats\Multimedia\Picture\Radiance\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Associations\Playlist\ASX.uexml" />
|
||||
@ -481,6 +493,8 @@
|
||||
<EmbeddedResource Include="Associations\Palette\RIFFPalette.uexml" />
|
||||
<EmbeddedResource Include="Associations\Picture\KISS.uexml" />
|
||||
<EmbeddedResource Include="Associations\Palette\KISS.uexml" />
|
||||
<EmbeddedResource Include="Associations\Picture\EXR.uexml" />
|
||||
<EmbeddedResource Include="Associations\Picture\Radiance.uexml" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user