Zagna Posted February 6, 2011 Share Posted February 6, 2011 (edited) Ok, here goes nothingĀ So after finding Pinta's OraFormat.cs and pitching it at others here, null54 came to the rescue and fixed everything. And shrike asking to publish it, here's my attempt. Thanks go to Maia Kozheva and null54. New 4.1.5 version for 2019 with blend mode change Download So there it is, hope it works and.... something. Edited February 9, 2019 by Zagna 1 Quote Link to comment Share on other sites More sharing options...
arcr Posted February 6, 2011 Share Posted February 6, 2011 Cant open images created with MyPaint. Says: "Could not find file" Quote Link to comment Share on other sites More sharing options...
Zagna Posted February 6, 2011 Author Share Posted February 6, 2011 I can easily open .ora files created with MyPaint and that error sounds like it's file in a strange place rather than the plugin? No idea. Can you put a PNG or JPG file the same folder and do they open? Quote Link to comment Share on other sites More sharing options...
arcr Posted February 6, 2011 Share Posted February 6, 2011 (edited) This is what is inside .Ora file: And this is the message I get when try to open it whit Paint.NET : "No se pudo encontrar el Archivo" = "Could not find file" Edited February 6, 2011 by arcr Quote Link to comment Share on other sites More sharing options...
arcr Posted February 6, 2011 Share Posted February 6, 2011 ... Can you put a PNG or JPG file the same folder and do they open? yes, they open. Quote Link to comment Share on other sites More sharing options...
null54 Posted February 6, 2011 Share Posted February 6, 2011 It seems like it is not able to find a file within the ora file, but the ora looks like it is correct in the screen shots. Could you attach the ora file in a zip? Quote Plugin Pack | PSFilterPdn | Content Aware Fill | G'MIC |Ā Paint Shop Pro Filetype | RAW Filetype | WebP Filetype The small increase in performance you get coding in C++ over C# is hardly enough to offset the headache of coding in the C++ language. ~BoltBait Ā Link to comment Share on other sites More sharing options...
arcr Posted February 6, 2011 Share Posted February 6, 2011 Ora file Quote Link to comment Share on other sites More sharing options...
null54 Posted February 7, 2011 Share Posted February 7, 2011 That file loads fine for me, I have no idea what the problem could be. Quote Plugin Pack | PSFilterPdn | Content Aware Fill | G'MIC |Ā Paint Shop Pro Filetype | RAW Filetype | WebP Filetype The small increase in performance you get coding in C++ over C# is hardly enough to offset the headache of coding in the C++ language. ~BoltBait Ā Link to comment Share on other sites More sharing options...
arcr Posted February 10, 2011 Share Posted February 10, 2011 Oh... now i can open it, but in other computer and whit other OS(W7). I think the problem is whit XP or whit the .Net Framework version(3.5) i have in my computer. Quote Link to comment Share on other sites More sharing options...
Lance McKnight Posted February 16, 2011 Share Posted February 16, 2011 Quick question, is this a file type or a plug-in? Quote Officially retired from this forum. Have a nice day. Link to comment Share on other sites More sharing options...
Ego Eram Reputo Posted February 16, 2011 Share Posted February 16, 2011 Both. It's a filetype plugin Quote ebook: Mastering Paint.NET | resources: Plugin Index | Stereogram Tut | proud supporter of Codelab plugins: EER's Plugin Pack | Planetoid | StickMan | WhichSymbol+ | Dr Scott's Markup Renderer | CSV Filetype | dwarf horde plugins: Plugin Browser | ShapeMaker Link to comment Share on other sites More sharing options...
Lance McKnight Posted February 18, 2011 Share Posted February 18, 2011 So it goes into the File Type folder or Effect folder? Sorry for these questions, the OP didn't make it clear where it should go. Quote Officially retired from this forum. Have a nice day. Link to comment Share on other sites More sharing options...
Sarkut Posted February 18, 2011 Share Posted February 18, 2011 (edited) It goes into the File Type folder. Running the .exe will put the .dll in the File Type folder. . Edited February 18, 2011 by Sarkut Quote Link to comment Share on other sites More sharing options...
Lance McKnight Posted February 18, 2011 Share Posted February 18, 2011 Thanks, Sarkut. I think the OP need to amend the post and clear it up. Quote Officially retired from this forum. Have a nice day. Link to comment Share on other sites More sharing options...
Ego Eram Reputo Posted February 19, 2011 Share Posted February 19, 2011 The thread title is "OpenRaster Filetype". Is that not clear enough? Quote ebook: Mastering Paint.NET | resources: Plugin Index | Stereogram Tut | proud supporter of Codelab plugins: EER's Plugin Pack | Planetoid | StickMan | WhichSymbol+ | Dr Scott's Markup Renderer | CSV Filetype | dwarf horde plugins: Plugin Browser | ShapeMaker Link to comment Share on other sites More sharing options...
Lance McKnight Posted February 19, 2011 Share Posted February 19, 2011 (edited) Nevermind. Edited February 19, 2011 by Lance McKnight Quote Officially retired from this forum. Have a nice day. Link to comment Share on other sites More sharing options...
CH5771 Posted February 24, 2011 Share Posted February 24, 2011 (edited) *double post* Edited February 24, 2011 by CH5771 Quote Link to comment Share on other sites More sharing options...
CH5771 Posted February 24, 2011 Share Posted February 24, 2011 (edited) Hi, first: Thank you very very much!!!! I'm working a lot with MyPaint and Paint.Net and you Plugin is exactly what i need. I can open an .ora file without problems into Paint.Net - this is really perfect. but.... I can't save any images from Paint.Net to .ora ... everytime i try i just get the screen: "an unknown error appears while saving" (see attached german screen) I don't know what to do... pleeeease help Some info: Paint.NET v3.5.7 , MyPaint 0.9.0, Windows Vista with all updates. Edited February 24, 2011 by CH5771 Quote Link to comment Share on other sites More sharing options...
Zagna Posted February 24, 2011 Author Share Posted February 24, 2011 I have no idea what the problem is. It used to work fine earlier..... what if it's due to 3.5.7's changes.... no idea at all. It's happening to me too, PDN 3.5.7 and Win 7 SP1. Quote Link to comment Share on other sites More sharing options...
CH5771 Posted February 24, 2011 Share Posted February 24, 2011 (edited) I hate it... "This update improves reliability of saving" ... or non-saving ... *hmpf*... so back to the developers discussion to get it fixed Edited February 24, 2011 by CH5771 Quote Link to comment Share on other sites More sharing options...
null54 Posted February 24, 2011 Share Posted February 24, 2011 The problem was that the ZipOutputStream closes the output stream when it is done instead of letting Paint.NET handle that. MyPaint's stroke map data should now be preserved when loading and saving as well. // 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; using System.Globalization; 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" }) { strokeMapVersions = new string[2] { "mypaint_strokemap", "mypaint_strokemap_v2" }; } /// <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 } else { dst[3] = 255; } } } bmp.UnlockBits(bmpData); layer.UnlockBits(layerData); } image = (Bitmap)layer.Clone(); } return image; } /// <summary> /// The formats for MyPaint's stroke map, version 1 and version 2. /// </summary> private readonly string[] strokeMapVersions; 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"), CultureInfo.InvariantCulture); int height = int.Parse(imageElement.GetAttribute("h"), CultureInfo.InvariantCulture); 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"), CultureInfo.InvariantCulture); // the x offset within the layer int y = int.Parse(GetAttribute(layerElement, "y", "0"), CultureInfo.InvariantCulture); // 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"), CultureInfo.InvariantCulture))); myLayer.Visible = (GetAttribute(layerElement, "visibility", "visible") == "visible"); // newer ora files have this myLayer.Surface.CopyFromGdipBitmap(bmp, false); // does this make sense? string backTile = GetAttribute(layerElement, "background_tile", string.Empty); if (!string.IsNullOrEmpty(backTile)) { ZipEntry tileZf = file.GetEntry(backTile); byte[] tileBytes = null; using (Stream tileStream = file.GetInputStream(tileZf)) { tileBytes = new byte[(int)tileStream.Length]; int numBytesToRead = (int)tileStream.Length; int numBytesRead = 0; while (numBytesToRead > 0) { // Read may return anything from 0 to numBytesToRead. int n = tileStream.Read(tileBytes, numBytesRead, numBytesToRead); // The end of the file is reached. if (n == 0) { break; } numBytesRead += n; numBytesToRead -= n; } } string tileData = Convert.ToBase64String(tileBytes); // convert the tile image to a Base64String and then save it in the layer's MetaData. myLayer.Metadata.SetUserValue("OraBackgroundTile", tileData); } foreach (string version in strokeMapVersions) { string strokeMap = GetAttribute(layerElement, version, string.Empty); if (!string.IsNullOrEmpty(strokeMap)) { ZipEntry strokeZf = file.GetEntry(strokeMap); byte[] strokeBytes = null; using (Stream strokeStream = file.GetInputStream(strokeZf)) { strokeBytes = new byte[(int)strokeStream.Length]; int numBytesToRead = (int)strokeStream.Length; int numBytesRead = 0; while (numBytesToRead > 0) { // Read may return anything from 0 to numBytesToRead. int n = strokeStream.Read(strokeBytes, numBytesRead, numBytesToRead); // The end of the file is reached. if (n == 0) { break; } numBytesRead += n; numBytesToRead -= n; } } string strokeData = Convert.ToBase64String(strokeBytes); // convert the stroke map to a Base64String and then save it in the layer's MetaData. myLayer.Metadata.SetUserValue("OraMyPaintStrokeMapData", strokeData); // Save the version of the stroke map in the MetaData myLayer.Metadata.SetUserValue("OraMyPaintStrokeMapVersion", version); } } doc.Layers.Insert(layerNum, myLayer); } } } return doc; } } // A struct to store the new x,y offsets private struct LayerInfo { public int x; public int y; public LayerInfo(int x, int y) { this.x = x; this.y = y; } } protected override void OnSave(Document input, Stream output, SaveConfigToken token, Surface scratchSurface, ProgressEventHandler callback) { using (ZipOutputStream stream = new ZipOutputStream(output)) { stream.IsStreamOwner = false; stream.UseZip64 = UseZip64.Off; 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); LayerInfo[] layerInfo = new LayerInfo[input.Layers.Count]; for (int i = 0; i < input.Layers.Count; i++) { BitmapLayer layer = (BitmapLayer)input.Layers[i]; Rectangle bounds = layer.Surface.Bounds; int left = layer.Width; int top = layer.Height; int right = 0; int bottom = 0; unsafe { for (int y = 0; y < layer.Height; y++) { ColorBgra* row = layer.Surface.GetRowAddress(y); ColorBgra* pixel = row; for (int x = 0; x < layer.Width; x++) { if (pixel->A > 0) { if (x < left) { left = x; } if (x > right) { right = x; } if (y < top) { top = y; } if (y > bottom) { bottom = y; } } pixel++; } } } if (left < layer.Width && top < layer.Height) // is the layer not empty { bounds = new Rectangle(left, top, (right - left), (bottom - top)); // clip it to the visible rectangle layerInfo[i] = new LayerInfo(left, top); } else { layerInfo[i] = new LayerInfo(0, 0); } string tileData = layer.Metadata.GetUserValue("OraBackgroundTile"); if (!string.IsNullOrEmpty(tileData)) // save the background_tile png if it exists { byte[] tileBytes = Convert.FromBase64String(tileData); stream.PutNextEntry(new ZipEntry("data/background_tile.png")); stream.Write(tileBytes, 0, tileBytes.Length); } string strokeData = layer.Metadata.GetUserValue("OraMyPaintStrokeMapData"); if (!string.IsNullOrEmpty(strokeData)) // save MyPaint's stroke data if it exists { byte[] tileBytes = Convert.FromBase64String(strokeData); stream.PutNextEntry(new ZipEntry("data/layer" + i.ToString(CultureInfo.InvariantCulture) + "_strokemap.dat")); stream.Write(tileBytes, 0, tileBytes.Length); } byte[] buf = null; using (MemoryStream ms = new MemoryStream()) { layer.Surface.CreateAliasedBitmap(bounds, true).Save(ms, ImageFormat.Png); buf = ms.ToArray(); } stream.PutNextEntry(new ZipEntry("data/layer" + i.ToString(CultureInfo.InvariantCulture) + ".png")); stream.Write(buf, 0, buf.Length); } stream.PutNextEntry(new ZipEntry("stack.xml")); databytes = GetLayerXmlData(input.Layers, layerInfo); 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); } System.Diagnostics.Debug.WriteLine("All done here"); } private byte[] GetLayerXmlData(LayerList layers, LayerInfo[] info) // 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(CultureInfo.InvariantCulture)); writer.WriteAttributeString("h", layers.GetAt(0).Height.ToString(CultureInfo.InvariantCulture)); 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--) { BitmapLayer layer = (BitmapLayer)layers[i]; writer.WriteStartElement("layer"); string backTile = layer.Metadata.GetUserValue("OraBackgroundTile"); if (!string.IsNullOrEmpty(backTile)) { writer.WriteAttributeString("background_tile", "data/background_tile.png"); } string strokeMapVersion = layer.Metadata.GetUserValue("OraMyPaintStrokeMapVersion"); if (!string.IsNullOrEmpty(strokeMapVersion)) { writer.WriteAttributeString(strokeMapVersion, "data/layer" + i.ToString(CultureInfo.InvariantCulture) + "_strokemap.dat"); } writer.WriteAttributeString("opacity", ((double)(layers.GetAt(i).Opacity / 255.0)).Clamp(0.0, 1.0).ToString("N2", CultureInfo.InvariantCulture)); // this is even more bizarre if (string.IsNullOrEmpty(strokeMapVersion)) // the stroke map layer does not have a name { writer.WriteAttributeString("name", layers.GetAt(i).Name); } writer.WriteAttributeString("src", "data/layer" + i.ToString(CultureInfo.InvariantCulture) + ".png"); writer.WriteAttributeString("visible", layers.GetAt(i).Visible ? "visible" : "hidden"); writer.WriteAttributeString("x", info[i].x.ToString(CultureInfo.InvariantCulture)); writer.WriteAttributeString("y", info[i].y.ToString(CultureInfo.InvariantCulture)); 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() }; } } } Quote Plugin Pack | PSFilterPdn | Content Aware Fill | G'MIC |Ā Paint Shop Pro Filetype | RAW Filetype | WebP Filetype The small increase in performance you get coding in C++ over C# is hardly enough to offset the headache of coding in the C++ language. ~BoltBait Ā Link to comment Share on other sites More sharing options...
CH5771 Posted February 25, 2011 Share Posted February 25, 2011 WoW! You're incredible fast null54! Thank you! Is the .exe file in the first post already updated? ... Because i don't know how to use / install your bug-fixed version Quote Link to comment Share on other sites More sharing options...
Zagna Posted February 25, 2011 Author Share Posted February 25, 2011 The .exe doesn't magically update itself When null54 saves the plugin by giving updated code, I gotta copy that code into VS 2010, compile it, test it quickly, wrap it in the NSIS installer and then copy it to the download location. And right now the installer has been updated with null54's latest version so it should work once again Quote Link to comment Share on other sites More sharing options...
CH5771 Posted February 25, 2011 Share Posted February 25, 2011 (edited) Hmmm no magic autoupdate?... But for me it feels thats you both are grand master wizzards Thanks for you both - you save my day! It works again!!!! PERFECT!!! Edited February 25, 2011 by CH5771 Quote Link to comment Share on other sites More sharing options...
Zagna Posted March 4, 2011 Author Share Posted March 4, 2011 (edited) I just noticed there's a lil bug somewhere in the code... stack.xml has the right dimensions, but for some reason the lowest and rightmost strips of pixels are discarded completely. so layer0.png is 1 pixel shorter and thinner.... null54 to the rescue? Edit: the culprit seems the be bounds in OnSave and the unsafe bit... Edit2: +1 addition to the rescue! .exe in the first post has been updated // bounds = new Rectangle(left, top, (right - left), (bottom - top)); // clip it to the visible rectangle bounds = new Rectangle(left, top, (right - left)+1, (bottom - top)+1); // clip it to the visible rectangle Edited March 5, 2011 by Zagna Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.