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 @@ + +