public Bitmap Get(int index) { lock (art.SyncRoot) { if (art.Disposed) { throw new ObjectDisposedException("Art"); } if (index < 0 || index >= Count) { throw new ArgumentOutOfRangeException("index"); } if (art.changeList.ContainsKey(index + Offset)) { return(art.changeList[index + Offset]); } else { IndexData indexData = art.indexFile.Get(index + Offset, false); if (indexData.IsValid) { return(ReadFromStream(indexData)); } else { return(null); } } } }
/// <summary> /// Adds data to the end of the list. /// </summary> /// <param name="data">New data.</param> /// <returns>Index of written data.</returns> /// <exception cref="System.ObjectDisposedException">Object has been disposed.</exception> public int Add(IndexData data) { if (Disposed) { throw new ObjectDisposedException("IndexFile"); } list.Add(data); return(list.Count - 1); }
/// <summary> /// Sets data at specified index. /// </summary> /// <param name="index">Index of data.</param> /// <param name="data">New data.</param> /// <param name="create">If true list is automaticly resized; otherwise exception is thrown.</param> /// <exception cref="System.ArgumentOutOfRangeException">Thrown when create is false and index is less than zero or equal to or greater than Count.</exception> /// <exception cref="System.ObjectDisposedException">Object has been disposed.</exception> public void Set(int index, IndexData data, bool create) { if (Disposed) { throw new ObjectDisposedException("IndexFile"); } if (index > list.Count && create) { Resize(index); } list[index] = data; }
/// <summary> /// Writes a Tile bitmap (44x44) into specified file and returns structure with indexing information. /// </summary> /// <param name="stream">Stream where to write to.</param> /// <param name="bitmap">Bitmap to write. If null, returns invalid IndexData.</param> /// <returns>IndexData structure with indexing information.</returns> /// <remarks>It writes only diamond from source image, other is ignored.</remarks> public static IndexData WriteTile(Stream stream, Bitmap bitmap) { if (stream == null) { throw new ArgumentNullException("stream"); } if (bitmap == null) { return(IndexData.Empty); } // Check bitmap if (bitmap.Height != 44 || bitmap.Width != 44) { throw new ArgumentException("Bitmap has incorrect size. Only allowed is 44x44.", "bitmap"); } // Create index list IndexData indexdata = IndexData.Empty; indexdata.Lookup = (uint)stream.Position; indexdata.Extra = 0; BinaryWriter writer = new BinaryWriter(stream); for (int y = 0; y < 22; y++) { int x = 22 - (y + 1); int lenght = (y + 1) * 2; for (int i = 0; i < lenght; i++) { writer.Write(UOColorConverter.FromColor(bitmap.GetPixel(x + i, y))); } } for (int y = 22; y < 44; y++) { int x = y - 22; int lenght = (44 - y) * 2; for (int i = 0; i < lenght; i++) { writer.Write(UOColorConverter.FromColor(bitmap.GetPixel(x + i, y))); } } indexdata.Lenght = (uint)stream.Position - indexdata.Lookup; return(indexdata); }
/// <summary> /// Loads IndexFile object from file. /// </summary> /// <param name="file">File path.</param> public static IndexFile Load(string file) { Stream stream = null; BinaryReader reader = null; try { stream = File.OpenRead(file); reader = new BinaryReader(stream); Trace.WriteLineIf((stream.Length % IndexData.Size) != 0, "IndexFile: File size is not multiple of 12.", "MulLib"); IndexFile indexFile = new IndexFile(); IndexData data = new IndexData(); for (int i = 0; i < stream.Length / IndexData.Size; i++) { data.Lookup = reader.ReadUInt32(); data.Lenght = reader.ReadUInt32(); data.Extra = reader.ReadUInt32(); indexFile.list.Add(data); } Trace.WriteLine(String.Format("IndexFile: File \"{0}\" succesfully loaded.", file), "MulLib"); return(indexFile); } catch (Exception e) { throw new Exception("Error loading IndexFile.", e); } finally { if (reader != null) { reader.Close(); } if (stream != null) { stream.Close(); } } }
/// <summary> /// Stores this object to specified files. /// </summary> /// <param name="idxFile">Index file.</param> /// <param name="mulFile">Data file.</param> /// <exception cref="System.ObjectDisposedException">Object has been disposed.</exception> public void Save(string idxFile, string mulFile) { lock (syncRoot) { if (Disposed) { throw new ObjectDisposedException("Skills"); } IndexFile indexFile = null; Stream stream = null; BinaryWriter writer = null; Stream indexStream = null; try { indexStream = File.Open(idxFile, FileMode.Create, FileAccess.Write, FileShare.None); indexFile = new IndexFile(); stream = File.OpenWrite(mulFile); writer = new BinaryWriter(stream); IndexData indexData = new IndexData(); foreach (SkillData skillData in list) { indexData.Lookup = (uint)stream.Position; indexData.Lenght = (uint)skillData.Name.Length + 1; indexData.Extra = skillData.Extra; writer.Write(skillData.Action); writer.Write(Encoding.ASCII.GetBytes(skillData.Name)); indexFile.Add(indexData); } indexFile.Resize(256); indexFile.Save(indexStream); Trace.WriteLine(String.Format("IndexFile: File \"{0}\" succesfully saved.", idxFile), "MulLib"); writer.Flush(); Trace.WriteLine(String.Format("Skills: File \"{0}\" succesfully saved.", mulFile), "MulLib"); } catch (Exception e) { throw new Exception("Error saving Skills.", e); } finally { if (indexFile != null) { indexFile.Dispose(); } if (indexStream != null) { indexStream.Close(); } if (writer != null) { writer.Close(); } if (stream != null) { stream.Close(); } } } }
protected override Bitmap ReadFromStream(IndexData indexData) { art.dataStream.Seek(indexData.Lookup, SeekOrigin.Begin); return Art.ReadTile(art.dataStream); }
protected abstract Bitmap ReadFromStream(IndexData indexData);
/// <summary> /// Saves object to specified files. /// </summary> /// <param name="idxFile">Index file path.</param> /// <param name="mulFile">Data file path.</param> /// <remarks> /// If mulFile differs from currently loaded file, new file is optimized (data file is sorted and without empty entries). /// Otherwise file must be loaded with write access. /// </remarks> public void Save(string idxFile, string mulFile) { lock (syncRoot) { if (Disposed) throw new ObjectDisposedException("Art"); Stream indexStream = null; try { indexStream = File.Open(idxFile, FileMode.Create, FileAccess.Write, FileShare.None); if (String.Compare(mulFile, this.mulFile, StringComparison.InvariantCultureIgnoreCase) == 0) { // Target data file is same as source file. File will not be optimized. Stream dataStream = this.dataStream; if (!dataStream.CanWrite) throw new InvalidOperationException("Trying to save data to source file, that is not opened for Write access."); foreach (KeyValuePair<int, Bitmap> pair in changeList) { if (pair.Key < 16384) { // Tile, can be saved to same location in data stream IndexData indexData = indexFile.Get(pair.Key, true); if (indexData.IsValid) { dataStream.Seek(indexData.Lookup, SeekOrigin.Begin); IndexData writtenData = Art.WriteTile(dataStream, pair.Value); Debug.Assert(writtenData.Lookup == indexData.Lookup, "writtenData.Lookup == indexData.Lookup"); Debug.Assert(writtenData.Lenght == indexData.Lenght, "writtenData.Lenght == indexData.Lenght"); } else { dataStream.Seek(0, SeekOrigin.End); IndexData writtenData = Art.WriteTile(dataStream, pair.Value); indexFile.Set(pair.Key, writtenData, true); } } else { // Run, will be saved to end of data stream dataStream.Seek(0, SeekOrigin.End); IndexData writtenData = Art.WriteRun(dataStream, pair.Value); indexFile.Set(pair.Key, writtenData, true); } } dataStream.Flush(); Trace.WriteLine(String.Format("Art: File \"{0}\" succesfully updated.", mulFile), "MulLib"); indexFile.Save(indexStream); Trace.WriteLine(String.Format("IndexFile: File \"{0}\" succesfully saved.", idxFile), "MulLib"); changeList.Clear(); } else { // Target data file differs from source file. Optimization will be performed. try { Stream dataStream = File.Open(mulFile, FileMode.Create, FileAccess.Write, FileShare.None); IndexFile newIndexFile = new IndexFile(); for (int i = 0; i < indexFile.Count; i++) { if (changeList.ContainsKey(i)) { IndexData writtenData; if (i < 16384) writtenData = Art.WriteTile(dataStream, changeList[i]); else writtenData = Art.WriteRun(dataStream, changeList[i]); newIndexFile.Set(i, writtenData, true); } else { IndexData indexData = indexFile.Get(i, false); if (indexData.IsValid) { byte[] data = new byte[indexData.Lenght]; this.dataStream.Seek(indexData.Lookup, SeekOrigin.Begin); this.dataStream.Read(data, 0, (int)indexData.Lenght); IndexData writtenData = new IndexData(); writtenData.Lookup = (uint)dataStream.Position; writtenData.Lenght = indexData.Lenght; writtenData.Extra = indexData.Extra; dataStream.Write(data, 0, (int)writtenData.Lenght); } } } dataStream.Flush(); Trace.WriteLine(String.Format("Art: File \"{0}\" succesfully saved.", mulFile), "MulLib"); newIndexFile.Save(indexStream); Trace.WriteLine(String.Format("IndexFile: File \"{0}\" succesfully saved.", idxFile), "MulLib"); } finally { if (dataStream != null) dataStream.Close(); } } } catch (Exception e) { throw new Exception("Error saving Art.", e); } finally { if (indexStream != null) indexStream.Close(); } } }
/// <summary> /// Sets data at specified index. /// </summary> /// <param name="index">Index of data.</param> /// <param name="data">New data.</param> /// <param name="create">If true list is automaticly resized; otherwise exception is thrown.</param> /// <exception cref="System.ArgumentOutOfRangeException">Thrown when create is false and index is less than zero or equal to or greater than Count.</exception> /// <exception cref="System.ObjectDisposedException">Object has been disposed.</exception> public void Set(int index, IndexData data, bool create) { if (Disposed) throw new ObjectDisposedException("IndexFile"); if (index > list.Count && create) { Resize(index); } list[index] = data; }
/// <summary> /// Adds data to the end of the list. /// </summary> /// <param name="data">New data.</param> /// <returns>Index of written data.</returns> /// <exception cref="System.ObjectDisposedException">Object has been disposed.</exception> public int Add(IndexData data) { if (Disposed) throw new ObjectDisposedException("IndexFile"); list.Add(data); return list.Count - 1; }
/// <summary> /// Loads IndexFile object from file. /// </summary> /// <param name="file">File path.</param> public static IndexFile Load(string file) { Stream stream = null; BinaryReader reader = null; try { stream = File.OpenRead(file); reader = new BinaryReader(stream); Trace.WriteLineIf((stream.Length % IndexData.Size) != 0, "IndexFile: File size is not multiple of 12.", "MulLib"); IndexFile indexFile = new IndexFile(); IndexData data = new IndexData(); for (int i = 0; i < stream.Length / IndexData.Size; i++) { data.Lookup = reader.ReadUInt32(); data.Lenght = reader.ReadUInt32(); data.Extra = reader.ReadUInt32(); indexFile.list.Add(data); } Trace.WriteLine(String.Format("IndexFile: File \"{0}\" succesfully loaded.", file), "MulLib"); return indexFile; } catch (Exception e) { throw new Exception("Error loading IndexFile.", e); } finally { if (reader != null) reader.Close(); if (stream != null) stream.Close(); } }
/// <summary> /// Writes a run-compressed bitmap into specified file and returns structure with indexing information. /// </summary> /// <param name="stream">Stream where to write to.</param> /// <param name="bitmap">Bitmap to write. If null, returns invalid IndexData.</param> /// <returns>IndexData structure with indexing information.</returns> public static IndexData WriteRun(Stream stream, Bitmap bitmap) { if (stream == null) { throw new ArgumentNullException("stream"); } if (bitmap == null) { return(IndexData.Empty); } BinaryWriter writer = new BinaryWriter(stream); IndexData indexdata = IndexData.Empty; indexdata.Lookup = (uint)writer.BaseStream.Position; indexdata.Extra = 0; short width = (short)bitmap.Width; short height = (short)bitmap.Height; writer.Write((int)0); // header, unknown writer.Write(width); writer.Write(height); long lookupTable = writer.BaseStream.Position; int dataStart = (int)writer.BaseStream.Position + height * 2; // Skip lookup table if (writer.BaseStream.Length < dataStart) { writer.BaseStream.SetLength(dataStart); } writer.Seek(dataStart, SeekOrigin.Begin); short y = 0; while (y < height) { // Write record to lookup table int pos = (int)writer.BaseStream.Position; writer.Seek((int)lookupTable, SeekOrigin.Begin); writer.Write((short)((pos - dataStart) / 2)); lookupTable = writer.BaseStream.Position; writer.Seek(pos, SeekOrigin.Begin); // Write line int x = 0; while (x < width) { short xOffset = 0; short xRun = 0; // Skip invisible pixels while (x < width && bitmap.GetPixel(x, y).A == 0) { xOffset++; x++; } if (x == width) { break; } // Read list int xPos = x; while (xPos < width && bitmap.GetPixel(xPos, y).A != 0) { xPos++; xRun++; } // Write chunk header writer.Write(xOffset); writer.Write(xRun); // Write pixel list while (x < width && bitmap.GetPixel(x, y).A != 0) { writer.Write(UOColorConverter.FromColor(bitmap.GetPixel(x, y))); x++; } } // End line writer.Write((short)0); writer.Write((short)0); y++; } indexdata.Lenght = (uint)writer.BaseStream.Position - indexdata.Lookup; return(indexdata); }
/// <summary> /// Saves object to specified files. /// </summary> /// <param name="idxFile">Index file path.</param> /// <param name="mulFile">Data file path.</param> /// <remarks> /// If mulFile differs from currently loaded file, new file is optimized (data file is sorted and without empty entries). /// Otherwise file must be loaded with write access. /// </remarks> public void Save(string idxFile, string mulFile) { lock (syncRoot) { if (Disposed) { throw new ObjectDisposedException("Art"); } Stream indexStream = null; try { indexStream = File.Open(idxFile, FileMode.Create, FileAccess.Write, FileShare.None); if (String.Compare(mulFile, this.mulFile, StringComparison.InvariantCultureIgnoreCase) == 0) { // Target data file is same as source file. File will not be optimized. Stream dataStream = this.dataStream; if (!dataStream.CanWrite) { throw new InvalidOperationException("Trying to save data to source file, that is not opened for Write access."); } foreach (KeyValuePair <int, Bitmap> pair in changeList) { if (pair.Key < 16384) { // Tile, can be saved to same location in data stream IndexData indexData = indexFile.Get(pair.Key, true); if (indexData.IsValid) { dataStream.Seek(indexData.Lookup, SeekOrigin.Begin); IndexData writtenData = Art.WriteTile(dataStream, pair.Value); Debug.Assert(writtenData.Lookup == indexData.Lookup, "writtenData.Lookup == indexData.Lookup"); Debug.Assert(writtenData.Lenght == indexData.Lenght, "writtenData.Lenght == indexData.Lenght"); } else { dataStream.Seek(0, SeekOrigin.End); IndexData writtenData = Art.WriteTile(dataStream, pair.Value); indexFile.Set(pair.Key, writtenData, true); } } else { // Run, will be saved to end of data stream dataStream.Seek(0, SeekOrigin.End); IndexData writtenData = Art.WriteRun(dataStream, pair.Value); indexFile.Set(pair.Key, writtenData, true); } } dataStream.Flush(); Trace.WriteLine(String.Format("Art: File \"{0}\" succesfully updated.", mulFile), "MulLib"); indexFile.Save(indexStream); Trace.WriteLine(String.Format("IndexFile: File \"{0}\" succesfully saved.", idxFile), "MulLib"); changeList.Clear(); } else { // Target data file differs from source file. Optimization will be performed. try { Stream dataStream = File.Open(mulFile, FileMode.Create, FileAccess.Write, FileShare.None); IndexFile newIndexFile = new IndexFile(); for (int i = 0; i < indexFile.Count; i++) { if (changeList.ContainsKey(i)) { IndexData writtenData; if (i < 16384) { writtenData = Art.WriteTile(dataStream, changeList[i]); } else { writtenData = Art.WriteRun(dataStream, changeList[i]); } newIndexFile.Set(i, writtenData, true); } else { IndexData indexData = indexFile.Get(i, false); if (indexData.IsValid) { byte[] data = new byte[indexData.Lenght]; this.dataStream.Seek(indexData.Lookup, SeekOrigin.Begin); this.dataStream.Read(data, 0, (int)indexData.Lenght); IndexData writtenData = new IndexData(); writtenData.Lookup = (uint)dataStream.Position; writtenData.Lenght = indexData.Lenght; writtenData.Extra = indexData.Extra; dataStream.Write(data, 0, (int)writtenData.Lenght); } } } dataStream.Flush(); Trace.WriteLine(String.Format("Art: File \"{0}\" succesfully saved.", mulFile), "MulLib"); newIndexFile.Save(indexStream); Trace.WriteLine(String.Format("IndexFile: File \"{0}\" succesfully saved.", idxFile), "MulLib"); } finally { if (dataStream != null) { dataStream.Close(); } } } } catch (Exception e) { throw new Exception("Error saving Art.", e); } finally { if (indexStream != null) { indexStream.Close(); } } } }
protected override Bitmap ReadFromStream(IndexData indexData) { art.dataStream.Seek(indexData.Lookup, SeekOrigin.Begin); return(Art.ReadRun(art.dataStream)); }