diff --git a/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj
index 515526b5..73639548 100644
--- a/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj
+++ b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj
@@ -639,6 +639,7 @@
+
diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/ZSoft/PCXDataFormat.cs b/CSharp/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/ZSoft/PCXDataFormat.cs
new file mode 100644
index 00000000..6a99bf36
--- /dev/null
+++ b/CSharp/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/ZSoft/PCXDataFormat.cs
@@ -0,0 +1,342 @@
+//
+// PCXDataFormat.cs
+//
+// Author:
+// Mike Becker
+//
+// Copyright (c) 2019 Mike Becker
+//
+// 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 MBS.Framework.Drawing;
+using UniversalEditor.IO;
+using UniversalEditor.ObjectModels.Multimedia.Palette;
+using UniversalEditor.ObjectModels.Multimedia.Picture;
+
+namespace UniversalEditor.DataFormats.Multimedia.Picture.ZSoft
+{
+ public class PCXDataFormat : DataFormat
+ {
+ private static DataFormatReference _dfr = null;
+ protected override DataFormatReference MakeReferenceInternal()
+ {
+ if (_dfr == null)
+ {
+ _dfr = base.MakeReferenceInternal();
+ _dfr.Capabilities.Add(typeof(PictureObjectModel), DataFormatCapabilities.All);
+ }
+ return _dfr;
+ }
+
+ private PCXHeader LoadPCXHeader(Reader reader)
+ {
+ PCXHeader header = new PCXHeader();
+ header.Manufacturer = reader.ReadByte(); // Constant Flag, 10 = ZSoft.pcx
+
+ header.Version = reader.ReadByte(); // Version information
+ // 0 = Version 2.5 of PC Paintbrush
+ // 2 = Version 2.8 w / palette information
+ // 3 = Version 2.8 w / o palette information
+ // 4 = PC Paintbrush for Windows(Plus for Windows uses Ver 5)
+ // 5 = Version 3.0 and > of PC Paintbrush and PC Paintbrush +, includes Publisher's Paintbrush . Includes 24 - bit.PCX files
+ header.Encoding = reader.ReadByte(); // 1 = .PCX run length encoding
+ header.BitsPerPixel = reader.ReadByte(); // 1 Number of bits to represent a pixel (per Plane) - 1, 2, 4, or 8
+ header.XStart = reader.ReadInt16(); // Image Dimensions: Xmin,Ymin,Xmax,Ymax (2-bytes each)
+ header.YStart = reader.ReadInt16();
+ header.XEnd = reader.ReadInt16();
+ header.YEnd = reader.ReadInt16();
+
+ // *HDpi and VDpi represent the Horizontal and Vertical resolutions which the
+ // image was created(either printer or scanner); i.e.an image which was
+ // scanned might have 300 and 300 in each of these fields.
+ header.HDpi = reader.ReadInt16(); // Horizontal Resolution of image in DPI *
+ header.VDpi = reader.ReadInt16(); // Vertical Resolution of image in DPI *
+
+
+ header.Palette = reader.ReadBytes(48); // Color palette setting, see text
+ header.Reserved1 = reader.ReadByte();// Should be set to 0.
+ header.NumBitPlanes = reader.ReadByte();// Number of color planes
+
+ header.BytesPerLine = reader.ReadInt16(); // Number of bytes to allocate for a scanline plane. MUST be an EVEN number. Do NOT calculate from Xmax-Xmin.
+ header.PaletteInfo = reader.ReadInt16(); // How to interpret palette - 1 = Color / BW, 2 = Grayscale(ignored in PB IV / IV +)
+ header.HorizontalScreenSize = reader.ReadInt16(); // Horizontal screen size in pixels.New field found only in PB IV / IV Plus
+ header.VerticalScreenSize = reader.ReadInt16(); // Vertical screen size in pixels.New field found only in PB IV / IV Plus
+
+ byte[] Filler = reader.ReadBytes(54); // Blank to fill out 128 byte header.Set all bytes to 0
+
+ if (header.NumBitPlanes == 3)
+ {
+ header.BitsPerPixel = 24;
+ }
+ else
+ {
+ if (header.NumBitPlanes != 1 && header.NumBitPlanes != 4)
+ {
+ int nbp = (int)header.NumBitPlanes & 0xFF;
+ throw new InvalidDataFormatException(String.Format("Bad number of bit planes [{0}] for PCX file", nbp));
+ }
+ switch (header.BitsPerPixel)
+ {
+ case 1:
+ {
+ switch (header.NumBitPlanes)
+ {
+ case 1:
+ {
+ header.BitsPerPixel = 1;
+ break;
+ }
+ case 2:
+ {
+ header.BitsPerPixel = 2;
+ break;
+ }
+ case 3:
+ case 4:
+ {
+ header.BitsPerPixel = 4;
+ break;
+ }
+ default:
+ {
+ int ibpp = (int)header.BitsPerPixel & 0xFF;
+ int inum = (int)header.NumBitPlanes & 0xFF;
+ throw new InvalidDataFormatException(String.Format("Bad BPP [{0}/{1}] for PCX file", ibpp, inum));
+ }
+ };
+ break;
+ }
+ case 2:
+ {
+ header.BitsPerPixel = 2;
+ break;
+ }
+ case 4:
+ {
+ header.BitsPerPixel = 4;
+ break;
+ }
+ case 8:
+ {
+ header.BitsPerPixel = 8;
+ break;
+ }
+ default:
+ {
+ int ibpp = (int)header.BitsPerPixel & 0xFF;
+ throw new InvalidDataFormatException(String.Format("Bad BPP [{0}] for PCX file", ibpp));
+ }
+ }
+ }
+ return header;
+ }
+
+ private enum PaletteType
+ {
+ NoPalette,
+ BuiltInPalette,
+ FooterPalette
+ }
+
+ protected override void LoadInternal(ref ObjectModel objectModel)
+ {
+ Reader reader = base.Accessor.Reader;
+ PictureObjectModel pic = (objectModel as PictureObjectModel);
+
+ PCXHeader header = LoadPCXHeader(reader);
+
+ byte[] row = null;
+ int bytesPerLine = header.NumBitPlanes * header.BytesPerLine;
+ int width = 1 + header.XEnd - header.XStart;
+ int height = 1 + header.YEnd - header.YStart;
+ PaletteType palType = PaletteType.NoPalette;
+ switch (header.BitsPerPixel)
+ {
+ case 1:
+ case 2:
+ case 4:
+ {
+ palType = PaletteType.BuiltInPalette;
+ header.BitsPerPixel = 8;
+ row = new byte[header.Width];
+ break;
+ }
+ case 8:
+ {
+ palType = PaletteType.FooterPalette;
+ header.BitsPerPixel = 8;
+ break;
+ }
+ default:
+ {
+ palType = PaletteType.NoPalette;
+ header.BitsPerPixel = 24;
+ break;
+ }
+ }
+
+ PaletteObjectModel palette = new PaletteObjectModel();
+ if (palType == PaletteType.BuiltInPalette)
+ {
+ reader.Seek(16, SeekOrigin.Begin); // (stream_start + (bsw::file_size_t)16);
+ LoadPCXPalette(reader, palette, true);
+ }
+ else
+ {
+ if (palType == PaletteType.FooterPalette)
+ {
+ if (reader.Accessor.Length < 769 + 128)
+ {
+ throw new InvalidDataFormatException(String.Format("Bad size [{0}] of the PCX file", reader.Accessor.Length));
+ }
+ reader.Seek(-769, SeekOrigin.End);
+ byte pcx_pal_magic = reader.ReadByte();
+ if (pcx_pal_magic != 12)
+ {
+ throw new InvalidDataFormatException("Unexpected start palette code in the PCX file");
+ }
+ LoadPCXPalette(reader, palette, false);
+ }
+ }
+
+ reader.Seek(128, SeekOrigin.Begin);
+
+ pic.Width = header.Width;
+ pic.Height = header.Height;
+
+ if (palette != null)
+ {
+ // pic.Palette = palette;
+ }
+ byte[] scan_line = new byte[bytesPerLine];
+ for (int y = 0; y < header.Height; y++)
+ {
+ LoadPCXScanLine(reader, scan_line);
+ if (header.BitsPerPixel == 24)
+ {
+ put_pixels_24 (pic, scan_line, y, header);
+ }
+ else
+ {
+ if (header.BitsPerPixel == 8)
+ {
+ put_pixels_8 (pic, scan_line, y, header, palette);
+ }
+ else
+ {
+ put_pixels_by_bits (pic, palette, scan_line, y, header, row);
+ }
+
+ }
+ }
+ }
+ private void LoadPCXScanLine(Reader reader, byte[] line)
+ {
+ int x = 0;
+ while (x < line.Length)
+ {
+ byte run_len = 1;
+ byte code = reader.ReadByte();
+ byte val;
+ if (0xC0 == (0xC0 & code))
+ {
+ run_len = (byte)(0x3F & code);
+ val = reader.ReadByte();
+ }
+ else
+ {
+ val = code;
+ }
+
+ for (int i = 0; i < run_len; i++, x++)
+ {
+ if (x < line.Length)
+ {
+ line[x] = val;
+ }
+ else
+ {
+ // end of line
+ break;
+ }
+ }
+ }
+ }
+
+ private void put_pixels_24(PictureObjectModel img, byte[] scan_line, int y, PCXHeader pcx_info)
+ {
+ for (int x = 0; x < pcx_info.Width; x++)
+ {
+ img.SetPixel(Color.FromRGBAByte(scan_line[0 * pcx_info.Width + x], scan_line[1 * pcx_info.Width + x], scan_line[2 * pcx_info.Width + x]), x, y);
+ }
+ }
+ private void put_pixels_8(PictureObjectModel img, byte[] scan_line, int y, PCXHeader pcx_info, PaletteObjectModel palette)
+ {
+ for (int x = 0; x < scan_line.Length /* pcx_info.Width */; x++)
+ {
+ img.SetPixel(palette.Entries[scan_line[x] % (palette.Entries.Count)].Color, x, y);
+ }
+ }
+ private void put_pixels_by_bits(PictureObjectModel img, PaletteObjectModel palette, byte[] scan_line, int y, PCXHeader pcx_info, byte[] row)
+ {
+ int bytes_in_line = pcx_info.BytesPerLine / pcx_info.NumBitPlanes;
+ uint k = 0;
+ for (uint plane = 0; plane < pcx_info.NumBitPlanes; plane++)
+ {
+ uint x = 0;
+ for (int i = 0; i < bytes_in_line; i++)
+ {
+ byte _byte = scan_line[k++];
+ for(int j = 7; j >= 0; j--)
+ {
+ byte bit = (byte)((_byte >> j) & 1);
+ /* skip padding bits */
+ if (i* 8 + j >= pcx_info.Width)
+ {
+ continue;
+ }
+ int z = ((int)bit << (int)plane);
+ row[x++] |= (byte)z;
+ }
+ }
+ }
+ for (int x = 0; x < pcx_info.Width; x++)
+ {
+ img.SetPixel(palette.Entries[row[x]].Color, x, y);
+ row[x] = 0;
+ }
+ }
+
+ private void LoadPCXPalette(Reader reader, PaletteObjectModel palette, bool is16colors)
+ {
+ uint to_read = (uint)(is16colors ? 16 : 256);
+ for (uint i = 0; i < to_read; i++)
+ {
+ byte r = reader.ReadByte();
+ byte g = reader.ReadByte();
+ byte b = reader.ReadByte();
+
+ palette.Entries.Add(Color.FromRGBAInt32((int)r & 0xFF, (int)g & 0xFF, (int)b & 0xFF));
+ }
+ }
+
+
+
+
+ protected override void SaveInternal(ObjectModel objectModel)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/ZSoft/PCXHeader.cs b/CSharp/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/ZSoft/PCXHeader.cs
new file mode 100644
index 00000000..6b292c22
--- /dev/null
+++ b/CSharp/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/ZSoft/PCXHeader.cs
@@ -0,0 +1,51 @@
+//
+// PCXHeader.cs
+//
+// Author:
+// Mike Becker
+//
+// Copyright (c) 2019 Mike Becker
+//
+// 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.ZSoft
+{
+ public struct PCXHeader
+ {
+ public byte Manufacturer;
+ public byte Version;
+ public byte Encoding;
+ public byte BitsPerPixel;
+
+ public short XStart;
+ public short YStart;
+ public short XEnd;
+ public short YEnd;
+
+ public short HDpi;
+ public short VDpi;
+
+ public byte[] Palette;
+ public byte Reserved1;
+ public byte NumBitPlanes;
+
+ public short BytesPerLine;
+ public short PaletteInfo;
+ public short HorizontalScreenSize;
+ public short VerticalScreenSize;
+
+ public int Width { get { return 1 + XEnd - XStart; } }
+ public int Height { get { return 1 + YEnd - YStart; } }
+ }
+}
diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Multimedia/ObjectModels/Multimedia/Picture/PictureObjectModel.cs b/CSharp/Plugins/UniversalEditor.Plugins.Multimedia/ObjectModels/Multimedia/Picture/PictureObjectModel.cs
index 56e513c6..582ddd85 100644
--- a/CSharp/Plugins/UniversalEditor.Plugins.Multimedia/ObjectModels/Multimedia/Picture/PictureObjectModel.cs
+++ b/CSharp/Plugins/UniversalEditor.Plugins.Multimedia/ObjectModels/Multimedia/Picture/PictureObjectModel.cs
@@ -131,11 +131,6 @@ namespace UniversalEditor.ObjectModels.Multimedia.Picture
return omr;
}
- public void SetPixel(object p, int x, int y)
- {
- throw new NotImplementedException();
- }
-
public override void Clear()
{
ColorMap.Clear();
diff --git a/CSharp/Plugins/UniversalEditor.Plugins.Multimedia/UniversalEditor.Plugins.Multimedia.csproj b/CSharp/Plugins/UniversalEditor.Plugins.Multimedia/UniversalEditor.Plugins.Multimedia.csproj
index d5baac79..423a178d 100644
--- a/CSharp/Plugins/UniversalEditor.Plugins.Multimedia/UniversalEditor.Plugins.Multimedia.csproj
+++ b/CSharp/Plugins/UniversalEditor.Plugins.Multimedia/UniversalEditor.Plugins.Multimedia.csproj
@@ -301,6 +301,8 @@
+
+
@@ -343,5 +345,8 @@
Designer
+
+
+
\ No newline at end of file