Jump to content

null54

Moderator
  • Posts

    1,975
  • Joined

  • Last visited

  • Days Won

    90

Posts posted by null54

  1. // Author of OraFormat.cs: 2010 Maia Kozheva <sikon@ubuntu.com>
    //
    // Copyright (c) 2010 Maia Kozheva <sikon@ubuntu.com>
    //
    // Permission is hereby granted, free of charge, to any person obtaining a copy
    // of this software and associated documentation files (the "Software"), to deal
    // in the Software without restriction, including without limitation the rights
    // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    // copies of the Software, and to permit persons to whom the Software is
    // furnished to do so, subject to the following conditions:
    //
    // The above copyright notice and this permission notice shall be included in
    // all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    // THE SOFTWARE.
    
    
    using System;
    using System.IO;
    using System.Drawing;
    using System.Xml;
    using PaintDotNet;
    using PaintDotNet.Data;
    using ICSharpCode.SharpZipLib.Zip;
    using System.Drawing.Imaging;
    
    namespace OpenRaster_Filetype
    {
    public class OraFileType : FileType
    {
    private const int ThumbMaxSize = 256;
    
    public OraFileType()
    : base("OpenRaster Image", FileTypeFlags.SupportsLoading | FileTypeFlags.SupportsSaving | FileTypeFlags.SupportsLayers, new String[] { ".ora" })
    {
    }
    
    /// <summary>
    /// Gets the bitmap from the ora layer.
    /// </summary>
    /// <param name="xofs">The x offset of the layer image.</param>
    /// <param name="yofs">The y offset of the layer image.</param>
    /// <param name="inStream">The input stream containing the layer image.</param>
    /// <param name="baseWidth">The width of the base document.</param>
    /// <param name="baseHeight">The height of the base document.</param>
    private unsafe Bitmap GetBitmapFromOraLayer(int xofs, int yofs, Stream inStream, int baseWidth, int baseHeight)
    {
    Bitmap image = null;
    
    using (Bitmap layer = new Bitmap(baseWidth, baseHeight))
    {
    using (Bitmap bmp = new Bitmap(inStream))
    {
    BitmapData layerData = layer.LockBits(new Rectangle(xofs, yofs, bmp.Width , bmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
    BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
    
    int bpp = Bitmap.GetPixelFormatSize(bmp.PixelFormat) / 8; 
    
    for (int y = 0; y < bmp.Height; y++)
    {
    for (int x = 0; x < bmp.Width; x++)
    {
    byte *dst = (byte*)layerData.Scan0.ToPointer() + (y * layerData.Stride) + (x * 4);
    byte* src = (byte*)bmpData.Scan0.ToPointer() + (y * bmpData.Stride) + (x * bpp);
    
    dst[0] = src[0]; // B
    dst[1] = src[1]; // G
    dst[2] = src[2]; // R
    
    if (bpp == 4)
    {
    dst[3] = src[3]; // A
    }
    }
    }
    
    bmp.UnlockBits(bmpData);
    layer.UnlockBits(layerData);
    }
    image = (Bitmap)layer.Clone();
    }
    
    return image;
    }
    
    protected override Document OnLoad(Stream input)
    {
    using (ZipFile file = new ZipFile(input))
    {
    
    XmlDocument stackXml = new XmlDocument();
    stackXml.Load(file.GetInputStream(file.GetEntry("stack.xml")));
    
    XmlElement imageElement = stackXml.DocumentElement;
    int width = int.Parse(imageElement.GetAttribute("w"));
    int height = int.Parse(imageElement.GetAttribute("h"));
    
    Document doc = new Document(width, height);
    
    XmlElement stackElement = (XmlElement)stackXml.GetElementsByTagName("stack")[0];
    XmlNodeList layerElements = stackElement.GetElementsByTagName("layer");
    
    if (layerElements.Count == 0)
    throw new FormatException("No layers found in OpenRaster file");
    int layerCount = layerElements.Count - 1;
    
    for (int i = layerCount; i >= 0; i--) // The last layer in the list is the background so load in reverse
    {
    XmlElement layerElement = (XmlElement)layerElements[i];
    int x = int.Parse(GetAttribute(layerElement, "x", "0")); // the x offset within the layer
    int y = int.Parse(GetAttribute(layerElement, "y", "0")); // the y offset within the layer
    
    int layerNum = layerCount - i;
    
    string name = GetAttribute(layerElement, "name", string.Format("Layer {0}", layerNum));
    
    ZipEntry zf = file.GetEntry(layerElement.GetAttribute("src"));
    
    using (Stream s = file.GetInputStream(zf))
    {
    using (Bitmap bmp = GetBitmapFromOraLayer(x, y, s, width, height))
    {
    BitmapLayer myLayer = null;
    if (i == layerCount) // load the background layer first
    {
    myLayer = Layer.CreateBackgroundLayer(width, height); 
    }
    else
    {
    myLayer = new BitmapLayer(width, height); 
    }
    
    myLayer.Name = name;
    myLayer.Opacity = (byte)(255.0 * double.Parse(GetAttribute(layerElement, "opacity", "1"))); // double to byte? wtf am I doing... O_o there is a better way... right? >_>
    myLayer.Visible = (GetAttribute(layerElement, "visibility", "visible") == "visible"); // newer ora files have this
    
    myLayer.Surface.CopyFromGdipBitmap(bmp, false); // does this make sense?
    
    myLayer.Metadata.SetUserValue("oraPos", string.Format("{0},{1}", x, y));
    
    doc.Layers.Insert(layerNum, myLayer);
    } 
    }
    
    }
    return doc;
    }
    
    }
    
    protected override void OnSave(Document input, Stream output, SaveConfigToken token, Surface scratchSurface, ProgressEventHandler callback)
    {
    using (ZipOutputStream stream = new ZipOutputStream(output))
    {
    ZipEntry mimetype = new ZipEntry("mimetype");
    mimetype.CompressionMethod = CompressionMethod.Stored;
    stream.PutNextEntry(mimetype);
    
    byte[] databytes = System.Text.Encoding.ASCII.GetBytes("image/openraster");
    stream.Write(databytes, 0, databytes.Length);
    
    for (int i = 0; i < input.Layers.Count; i++)
    {
    BitmapLayer layer = (BitmapLayer)input.Layers[i];
    
    byte[] buf = null;
    using (MemoryStream ms = new MemoryStream())
    {
    layer.Surface.CreateAliasedBitmap().Save(ms, ImageFormat.Png);
    buf = ms.ToArray();
    }
    stream.PutNextEntry(new ZipEntry("data/layer" + i.ToString() + ".png"));
    stream.Write(buf, 0, buf.Length);
    }
    
    /*// OraFormat.cs
    for (int i = 0; i < document.Layers.Count; i++)
    {
    Pixbuf pb = document.Layers[i].Surface.ToPixbuf();
    byte[] buf = pb.SaveToBuffer("png");
    (pb as IDisposable).Dispose();
    
    stream.PutNextEntry(new ZipEntry("data/layer" + i.ToString() + ".png"));
    stream.Write(buf, 0, buf.Length);
    }
    */
    
    stream.PutNextEntry(new ZipEntry("stack.xml"));
    databytes = GetLayerXmlData(input.Layers);
    stream.Write(databytes, 0, databytes.Length);
    
    
    using (Surface flat = new Surface(input.Width, input.Height))
    {
    input.Flatten(flat);
    Size thumbSize = GetThumbDimensions(input.Width, input.Height);
    
    Surface scale = new Surface(thumbSize);
    scale.FitSurface(ResamplingAlgorithm.SuperSampling, flat);
    
    using (MemoryStream ms = new MemoryStream())
    {
    scale.CreateAliasedBitmap().Save(ms, ImageFormat.Png);
    databytes = ms.ToArray();
    }
    scale.Dispose();
    }
    stream.PutNextEntry(new ZipEntry("Thumbnails/thumbnail.png"));
    stream.Write(databytes, 0, databytes.Length);
    
    /* // OraFormat.cs
    ImageSurface flattened = document.GetFlattenedImage();
    Pixbuf flattenedPb = flattened.ToPixbuf();
    Size newSize = GetThumbDimensions(flattenedPb.Width, flattenedPb.Height);
    Pixbuf thumb = flattenedPb.ScaleSimple(newSize.Width, newSize.Height, InterpType.Bilinear);
    
    stream.PutNextEntry(new ZipEntry("Thumbnails/thumbnail.png"));
    databytes = thumb.SaveToBuffer("png");
    stream.Write(databytes, 0, databytes.Length);
    
    (flattened as IDisposable).Dispose();
    (flattenedPb as IDisposable).Dispose();
    (thumb as IDisposable).Dispose();
    */
    }
    }
    
    private byte[] GetLayerXmlData(LayerList layers) // OraFormat.cs - minor changes, no idea if still works
    {
    byte[] buf = null;
    
    using(MemoryStream ms = new MemoryStream())
    {
    XmlTextWriter writer = new XmlTextWriter(ms, System.Text.Encoding.UTF8);
    writer.Formatting = Formatting.Indented;
    
    writer.WriteStartElement("image");
    writer.WriteAttributeString("w", layers.GetAt(0).Width.ToString());
    writer.WriteAttributeString("h", layers.GetAt(0).Height.ToString());
    
    writer.WriteStartElement("stack");
    writer.WriteAttributeString("opacity", "1");
    writer.WriteAttributeString("name", "root");
    
    
    // ORA stores layers top to bottom
    for (int i = layers.Count - 1; i >= 0; i--)
    {
    string[] xyPos = null;
    
    string val = ((BitmapLayer)layers[i]).Metadata.GetUserValue("oraPos");
    if (!string.IsNullOrEmpty(val))
    {
    xyPos = new string[2];
    xyPos = val.Split(new char[] { ',' });
    }
    
    
    
    writer.WriteStartElement("layer");
    writer.WriteAttributeString("opacity", string.Format("{0:0.00}", (double)(layers.GetAt(i).Opacity) / 255.0)); // byte to double? wtf am I doing... O_o
    writer.WriteAttributeString("name", layers.GetAt(i).Name);
    writer.WriteAttributeString("src", "data/layer" + i.ToString() + ".png");
    writer.WriteAttributeString("visible", layers.GetAt(i).Visible ? "visible" : "hidden");
    
    if (xyPos != null)
    {
    writer.WriteAttributeString("x", xyPos[0]);
    writer.WriteAttributeString("y", xyPos[1]);
    }
    
    writer.WriteEndElement();
    }
    
    writer.WriteEndElement(); // stack
    writer.WriteEndElement(); // image
    
    writer.Close(); 
    
    buf = ms.ToArray();
    }
    
    return buf;
    }
    
    private Size GetThumbDimensions(int width, int height) // OraFormat.cs
    {
    if (width <= ThumbMaxSize && height <= ThumbMaxSize)
    return new Size(width, height);
    
    if (width > height)
    return new Size(ThumbMaxSize, (int)((double)height / width * ThumbMaxSize));
    else
    return new Size((int)((double)width / height * ThumbMaxSize), ThumbMaxSize);
    }
    
    private static string GetAttribute(XmlElement element, string attribute, string defValue) // OraFormat.cs
    {
    string ret = element.GetAttribute(attribute);
    return string.IsNullOrEmpty(ret) ? defValue : ret;
    }
    }
    
    public class MyFileTypeFactory : IFileTypeFactory
    {
    public FileType[] GetFileTypeInstances()
    {
    return new FileType[] { new OraFileType() };
    }
    }
    }

  2. Can you add a handful of filters so we can see it working? I would also like to see some documentation. Controls named ctl(4) or Map(2) don't exactly scream their function at me.

    It does look very promising, but first impressions are...., daunting!

    The zip has been updated with the official documentation and example code.

  3. This plugin allow some of the filters built with Adobe's Filter Factory plugin for Photoshop to be run in Paint.NET.

    The Filter Factory plugins use a C-style language to modify an image.

    If a Filter Factory filter does not work with this plugin you can use PSFilterPdn to run it.

     

    This plugin is compatible with Paint.NET 3.5.11 and 4.0.x.

     

    PdnFF.png

     

    The Filter Manager will search the directories specified in the directory search list to for filters to display by category.

    The Build Filter button will build the loaded filter as a separate plugin for Paint.NET to use.

    A list of some of the Filter Factory filters is available at http://thepluginsite...rces/freeff.htm.

     

    The plugin icon is from the Silk icon set.

     

    Download:

    PdnFF.zip

     

    Source Code:

    The source code for the plugin and Filter Factory interpreter (ffparse).

    Both are licensed under the terms of the GNU General Public License.

    https://github.com/0xC0000054/pdn-filter-factory

    https://github.com/0xC0000054/pdn-filter-factory-interpreter

×
×
  • Create New...