diff --git a/Plugins.UserInterface/UniversalEditor.Plugins.Multimedia.UserInterface/Editors/Multimedia/Picture/PictureEditor.Designer.cs b/Plugins.UserInterface/UniversalEditor.Plugins.Multimedia.UserInterface/Editors/Multimedia/Picture/PictureEditor.Designer.cs
index 7a6a979d..84ed2909 100644
--- a/Plugins.UserInterface/UniversalEditor.Plugins.Multimedia.UserInterface/Editors/Multimedia/Picture/PictureEditor.Designer.cs
+++ b/Plugins.UserInterface/UniversalEditor.Plugins.Multimedia.UserInterface/Editors/Multimedia/Picture/PictureEditor.Designer.cs
@@ -19,8 +19,12 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
+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)
+ {
+
+ }
}
}
diff --git a/Plugins.UserInterface/UniversalEditor.Plugins.Multimedia.UserInterface/PictureObjectModelExtensions.cs b/Plugins.UserInterface/UniversalEditor.Plugins.Multimedia.UserInterface/PictureObjectModelExtensions.cs
index 808a5828..60082f60 100644
--- a/Plugins.UserInterface/UniversalEditor.Plugins.Multimedia.UserInterface/PictureObjectModelExtensions.cs
+++ b/Plugins.UserInterface/UniversalEditor.Plugins.Multimedia.UserInterface/PictureObjectModelExtensions.cs
@@ -37,13 +37,13 @@ namespace UniversalEditor.Plugins.Multimedia.UserInterface
/// The containing the image data to convert.
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;
diff --git a/Plugins/UniversalEditor.Plugins.ChaosWorks/Associations/Multimedia/Palette/SPPDataFormat.uexml b/Plugins/UniversalEditor.Plugins.ChaosWorks/Associations/Multimedia/Palette/SPPDataFormat.uexml
index ee9a26f2..5900f29b 100644
--- a/Plugins/UniversalEditor.Plugins.ChaosWorks/Associations/Multimedia/Palette/SPPDataFormat.uexml
+++ b/Plugins/UniversalEditor.Plugins.ChaosWorks/Associations/Multimedia/Palette/SPPDataFormat.uexml
@@ -3,7 +3,7 @@
-
+
*.spp
diff --git a/Plugins/UniversalEditor.Plugins.ChaosWorks/DataFormats/Multimedia/PictureCollection/CWESpriteDataFormat.cs b/Plugins/UniversalEditor.Plugins.ChaosWorks/DataFormats/Multimedia/PictureCollection/CWESpriteDataFormat.cs
index b3e9677a..036239a3 100644
--- a/Plugins/UniversalEditor.Plugins.ChaosWorks/DataFormats/Multimedia/PictureCollection/CWESpriteDataFormat.cs
+++ b/Plugins/UniversalEditor.Plugins.ChaosWorks/DataFormats/Multimedia/PictureCollection/CWESpriteDataFormat.cs
@@ -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> lists = new List>();
diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRChannel.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRChannel.cs
new file mode 100644
index 00000000..1f87294a
--- /dev/null
+++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRChannel.cs
@@ -0,0 +1,32 @@
+//
+// EXRChannel.cs
+//
+// Author:
+// Michael Becker
+//
+// 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 .
+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;
+ }
+}
diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRChromaticities.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRChromaticities.cs
new file mode 100644
index 00000000..c5b92c84
--- /dev/null
+++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRChromaticities.cs
@@ -0,0 +1,35 @@
+//
+// EXRChromaticities.cs
+//
+// Author:
+// Michael Becker
+//
+// 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 .
+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; }
+ }
+}
diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRCompression.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRCompression.cs
new file mode 100644
index 00000000..1f96035e
--- /dev/null
+++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRCompression.cs
@@ -0,0 +1,37 @@
+//
+// EXRCompression.cs
+//
+// Author:
+// Michael Becker
+//
+// 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 .
+using System;
+namespace UniversalEditor.DataFormats.Multimedia.Picture.EXR
+{
+ public enum EXRCompression
+ {
+ None,
+ RunLengthEncoding,
+ ZipPerScanline,
+ ZipPer16Scanline,
+ PIZWavelet,
+ PXR24Deflate,
+ B44,
+ B44A,
+ DWAA,
+ DWAB
+ }
+}
diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRDataFormat.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRDataFormat.cs
new file mode 100644
index 00000000..4cfb2c5d
--- /dev/null
+++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRDataFormat.cs
@@ -0,0 +1,431 @@
+//
+// EXRBaseDataFormat.cs
+//
+// Author:
+// Michael Becker
+//
+// 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 .
+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 Properties { get; } = new Dictionary();
+ 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);
+ }
+ }
+
+ ///
+ /// Converts the attribute data in to a instance of the appropriate
+ /// type as indicated by .
+ ///
+ /// 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).
+ ///
+ /// The attribute data.
+ /// Data.
+ /// Data type.
+ protected virtual object ConvertAttributeData(byte[] data, string dataType)
+ {
+ object propertyData = null;
+ MemoryAccessor acc = new MemoryAccessor(data);
+ switch (dataType)
+ {
+ case "chlist":
+ {
+ List chlist = new List();
+ 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);
+ }
+ }
+ }
+
+ ///
+ /// Indicates that a property with the given
+ /// is preferred to be defined; however,
+ /// if the property is not defined, use the value specified by
+ /// .
+ ///
+ /// The name of the property to check.
+ /// The value to assign property to.
+ /// The expected type of the property.
+ private void PreferProperty(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();
+ }
+ }
+}
diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRFlags.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRFlags.cs
new file mode 100644
index 00000000..34ee6e8a
--- /dev/null
+++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRFlags.cs
@@ -0,0 +1,58 @@
+//
+// EXRFlags.cs
+//
+// Author:
+// Michael Becker
+//
+// 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 .
+using System;
+namespace UniversalEditor.DataFormats.Multimedia.Picture.EXR
+{
+ [Flags()]
+ public enum EXRFlags
+ {
+ ///
+ /// If set, this is a regular single-part image and the pixels are stored
+ /// as tiles, and and
+ /// 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.
+ ///
+ SingleTile = 0x200,
+ ///
+ /// 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.
+ ///
+ LongName = 0x400,
+ ///
+ /// 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.
+ ///
+ NonImage = 0x800,
+ ///
+ /// 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.
+ ///
+ Multipart = 0x1000
+ }
+}
diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRLineOrder.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRLineOrder.cs
new file mode 100644
index 00000000..c90677a1
--- /dev/null
+++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRLineOrder.cs
@@ -0,0 +1,43 @@
+//
+// EXRLineOrder.cs
+//
+// Author:
+// Michael Becker
+//
+// 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 .
+using System;
+namespace UniversalEditor.DataFormats.Multimedia.Picture.EXR
+{
+ public enum EXRLineOrder
+ {
+ ///
+ /// Indicates that scan lines are stored in order of increasing Y
+ /// coordinates.
+ ///
+ IncreasingY = 0,
+ ///
+ /// Indicates that scan lines are stored in order of decreasing Y
+ /// coordinates.
+ ///
+ DecreasingY = 1,
+ ///
+ /// 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.
+ ///
+ RandomY = 2
+ }
+}
diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRPixelType.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRPixelType.cs
new file mode 100644
index 00000000..af3acfe5
--- /dev/null
+++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/EXR/EXRPixelType.cs
@@ -0,0 +1,30 @@
+//
+// EXRPixelType.cs
+//
+// Author:
+// Michael Becker
+//
+// 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 .
+using System;
+namespace UniversalEditor.DataFormats.Multimedia.Picture.EXR
+{
+ public enum EXRPixelType
+ {
+ UInt = 0,
+ Half = 1,
+ Float = 2
+ }
+}
diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Microsoft/Bitmap/BitmapDataFormat.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Microsoft/Bitmap/BitmapDataFormat.cs
index f1a0bbaa..194c36fc 100644
--- a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Microsoft/Bitmap/BitmapDataFormat.cs
+++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Microsoft/Bitmap/BitmapDataFormat.cs
@@ -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;
+
///
/// 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
/// The vertical resolution, in pixels-per-meter, of the target device for the bitmap.
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)
diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Radiance/HDRCompression.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Radiance/HDRCompression.cs
new file mode 100644
index 00000000..c9232799
--- /dev/null
+++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Radiance/HDRCompression.cs
@@ -0,0 +1,30 @@
+//
+// HDRCompression.cs
+//
+// Author:
+// Michael Becker
+//
+// 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 .
+using System;
+namespace UniversalEditor.DataFormats.Multimedia.Picture.Radiance
+{
+ public enum HDRCompression
+ {
+ None = 0,
+ RunLengthEncoding = 1,
+ AdaptiveRunLengthEncoding = 2
+ }
+}
diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Radiance/HDRDataFormat.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Radiance/HDRDataFormat.cs
new file mode 100644
index 00000000..2e552afb
--- /dev/null
+++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Radiance/HDRDataFormat.cs
@@ -0,0 +1,176 @@
+//
+// HDRDataFormat.cs
+//
+// Author:
+// Michael Becker
+//
+// 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 .
+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();
+
+ }
+ }
+}
diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/ObjectModels/Multimedia/Picture/PictureObjectModel.cs b/Plugins/UniversalEditor.Plugins.Multimedia/ObjectModels/Multimedia/Picture/PictureObjectModel.cs
index efa47ada..2d30aca7 100644
--- a/Plugins/UniversalEditor.Plugins.Multimedia/ObjectModels/Multimedia/Picture/PictureObjectModel.cs
+++ b/Plugins/UniversalEditor.Plugins.Multimedia/ObjectModels/Multimedia/Picture/PictureObjectModel.cs
@@ -55,16 +55,14 @@ namespace UniversalEditor.ObjectModels.Multimedia.Picture
public List GenerateColorMap()
{
List colorMap = new List();
- 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;
+ }
+ }
+ }
}
}
diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/ObjectModels/Multimedia/Picture/PixelFormat.cs b/Plugins/UniversalEditor.Plugins.Multimedia/ObjectModels/Multimedia/Picture/PixelFormat.cs
new file mode 100644
index 00000000..7203ae80
--- /dev/null
+++ b/Plugins/UniversalEditor.Plugins.Multimedia/ObjectModels/Multimedia/Picture/PixelFormat.cs
@@ -0,0 +1,29 @@
+//
+// PixelFormat.cs
+//
+// Author:
+// Michael Becker
+//
+// 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 .
+using System;
+namespace UniversalEditor.ObjectModels.Multimedia.Picture
+{
+ public enum PixelFormat
+ {
+ BGRA,
+ RGBA
+ }
+}
diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/UniversalEditor.Plugins.Multimedia.csproj b/Plugins/UniversalEditor.Plugins.Multimedia/UniversalEditor.Plugins.Multimedia.csproj
index 5bd44c22..28a2ecc2 100644
--- a/Plugins/UniversalEditor.Plugins.Multimedia/UniversalEditor.Plugins.Multimedia.csproj
+++ b/Plugins/UniversalEditor.Plugins.Multimedia/UniversalEditor.Plugins.Multimedia.csproj
@@ -344,6 +344,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -406,6 +416,8 @@
+
+
@@ -481,6 +493,8 @@
+
+