diff --git a/Source/SharpFont/FTStream.cs b/Source/SharpFont/FTStream.cs
index 927c6e0..abb0f9d 100644
--- a/Source/SharpFont/FTStream.cs
+++ b/Source/SharpFont/FTStream.cs
@@ -43,14 +43,14 @@ namespace SharpFont
/// The number of bytes effectively read by the stream.
[CLSCompliant(false)]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate uint StreamIOFunc(NativeReference stream, uint offset, IntPtr buffer, uint count);
+ public delegate uint StreamIOFunc(IntPtr stream, uint offset, IntPtr buffer, uint count);
///
/// A function used to close a given input stream.
///
/// A handle to the target stream.
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate void StreamCloseFunc(NativeReference stream);
+ public delegate void StreamCloseFunc(IntPtr stream);
///
/// A handle to an input stream.
@@ -84,7 +84,7 @@ public IntPtr Base
return rec.@base;
}
}
-
+
///
/// Gets the stream size in bytes.
///
diff --git a/Source/SharpFont/Face.cs b/Source/SharpFont/Face.cs
index fea801b..01b78ea 100644
--- a/Source/SharpFont/Face.cs
+++ b/Source/SharpFont/Face.cs
@@ -24,6 +24,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
using System;
using System.Collections.Generic;
+using System.IO;
using System.Runtime.InteropServices;
using SharpFont.Bdf;
@@ -53,6 +54,12 @@ public sealed class Face : NativeObject, IDisposable
private Library parentLibrary;
private List childSizes;
+ GCHandle customStreamHandle;
+ IntPtr customStreamPtr;
+ private IntPtr openArgsPtr;
+ private StreamIOFunc streamIOFunc;
+ private StreamCloseFunc streamCloseFunc;
+
#endregion
#region Constructors
@@ -67,6 +74,8 @@ public Face(Library library, string path)
{
}
+
+
///
/// Initializes a new instance of the class.
///
@@ -85,7 +94,85 @@ public Face(Library library, string path, int faceIndex)
Reference = reference;
}
- //TODO make an overload with a FileStream instead of a byte[]
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The parent library.
+ /// The stream of the font file.
+ /// The index of the face to take from the file.
+ /// The stream is automatically disposed with the face.
+ public Face(Library library, Stream stream, int faceIndex, bool takeStreamOwnership)
+ : this(library, new StreamAccessor(stream, takeStreamOwnership), faceIndex)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The parent library.
+ /// Custom object for handling stream access to the font file.
+ /// The index of the face to take from the file.
+ public Face(Library library, ICustomStreamAccessor streamAccessor, int faceIndex)
+ : this(library)
+ {
+ IntPtr reference;
+
+ streamIOFunc = new StreamIOFunc(StreamIOFunc);
+ streamCloseFunc = new StreamCloseFunc(StreamCloseFunc);
+
+ customStreamHandle = GCHandle.Alloc(streamAccessor);
+
+ StreamRec streamRec = new StreamRec();
+ streamRec.size = (UIntPtr)streamAccessor.Length;
+ streamRec.descriptor.pointer = GCHandle.ToIntPtr(customStreamHandle);
+ streamRec.read = streamIOFunc;
+ streamRec.close = streamCloseFunc;
+
+ customStreamPtr = Marshal.AllocHGlobal(Marshal.SizeOf(streamRec));
+ Marshal.StructureToPtr(streamRec, customStreamPtr, false);
+
+
+ OpenArgsRec openArgs = new OpenArgsRec();
+ openArgs.flags = OpenFlags.Stream;
+ openArgs.stream = customStreamPtr;
+
+ openArgsPtr = Marshal.AllocHGlobal(Marshal.SizeOf(openArgs));
+ Marshal.StructureToPtr(openArgs, openArgsPtr, false);
+
+
+ Error err = FT.FT_Open_Face(library.Reference, openArgsPtr, faceIndex, out reference);
+ if (err != Error.Ok)
+ throw new FreeTypeException(err);
+
+ Reference = reference;
+ }
+
+ private uint StreamIOFunc(IntPtr streamPtr, uint offset, IntPtr buffer, uint count)
+ {
+ FTStream ftStream = new FTStream(streamPtr);
+ ICustomStreamAccessor streamAccessor = ((GCHandle)ftStream.Descriptor.Pointer).Target as ICustomStreamAccessor;
+ if (streamAccessor != null)
+ {
+ streamAccessor.Seek((int)offset);
+ if (count > 0)
+ {
+ byte[] readbuffer = new byte[count];
+ int bytesread = streamAccessor.Read(readbuffer);
+ Marshal.Copy(readbuffer, 0, buffer, (int)count);
+ return (uint)bytesread;
+ }
+ }
+ return 0;
+ }
+
+ private void StreamCloseFunc(IntPtr streamPtr)
+ {
+ FTStream ftStream = new FTStream(streamPtr);
+ ICustomStreamAccessor streamAccessor = ((GCHandle)ftStream.Descriptor.Pointer).Target as ICustomStreamAccessor;
+ if (streamAccessor != null) streamAccessor.Close();
+ }
+
///
/// Initializes a new instance of the class from a file that's already loaded into memory.
@@ -2401,6 +2488,10 @@ private void Dispose(bool disposing)
if (memoryFaceHandle.IsAllocated)
memoryFaceHandle.Free();
+ if (openArgsPtr != IntPtr.Zero) Marshal.FreeHGlobal(openArgsPtr);
+ if (customStreamPtr != IntPtr.Zero) Marshal.FreeHGlobal(customStreamPtr);
+ if (customStreamHandle.IsAllocated) customStreamHandle.Free();
+
EventHandler handler = Disposed;
if (handler != null)
handler(this, EventArgs.Empty);
diff --git a/Source/SharpFont/ICustomStreamAccessor.cs b/Source/SharpFont/ICustomStreamAccessor.cs
new file mode 100644
index 0000000..138eb1a
--- /dev/null
+++ b/Source/SharpFont/ICustomStreamAccessor.cs
@@ -0,0 +1,56 @@
+#region MIT License
+/*Copyright (c) 2015-2016 Robert Rouhani
+
+SharpFont based on Tao.FreeType, Copyright (c) 2003-2007 Tao Framework Team
+
+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.*/
+#endregion
+
+namespace SharpFont
+{
+ ///
+ /// Interface for providing access to a custom stream representing a font file.
+ ///
+ public interface ICustomStreamAccessor
+ {
+ ///
+ /// Seeks to a specified position within a stream.
+ ///
+ /// Position from the beginning of the stream to seek to.
+ /// The new position within the stream.
+ int Seek(int position);
+
+ ///
+ /// Reads bytes from the stream. The maximum number of bytes to read is specified by the buffer length.
+ ///
+ /// Buffer to receive read bytes.
+ /// The actual number of bytes read from the stream.
+ int Read(byte[] buffer);
+
+ ///
+ /// Closes the stream. Called by freetype once the font face is destroyed.
+ ///
+ void Close();
+
+ ///
+ /// Returns total length of the stream in bytes.
+ ///
+ int Length { get; }
+ }
+}
diff --git a/Source/SharpFont/SharpFont.csproj b/Source/SharpFont/SharpFont.csproj
index 4ed82c3..b52f4cb 100644
--- a/Source/SharpFont/SharpFont.csproj
+++ b/Source/SharpFont/SharpFont.csproj
@@ -119,6 +119,7 @@
+
@@ -205,6 +206,7 @@
+
diff --git a/Source/SharpFont/StreamAccessor.cs b/Source/SharpFont/StreamAccessor.cs
new file mode 100644
index 0000000..6892f8d
--- /dev/null
+++ b/Source/SharpFont/StreamAccessor.cs
@@ -0,0 +1,76 @@
+#region MIT License
+/*Copyright (c) 2015-2016 Robert Rouhani
+
+SharpFont based on Tao.FreeType, Copyright (c) 2003-2007 Tao Framework Team
+
+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.*/
+#endregion
+
+using System;
+using System.IO;
+
+namespace SharpFont
+{
+ ///
+ /// Custom font stream accessor based on a generic Stream object.
+ ///
+ internal class StreamAccessor : ICustomStreamAccessor
+ {
+ private Stream _stream;
+ private bool _takeStreamOwnership;
+
+ public StreamAccessor(Stream stream, bool takeStreamOwnership)
+ {
+ if (stream == null)
+ throw new ArgumentException("Stream cannot be null", "stream");
+
+ if (!stream.CanRead || !stream.CanSeek)
+ throw new ArgumentException("Stream must support reading and seeking", "stream");
+
+ _stream = stream;
+ _takeStreamOwnership = takeStreamOwnership;
+ }
+
+ public void Close()
+ {
+ if (_takeStreamOwnership)
+ {
+ _stream.Dispose();
+ }
+ }
+
+ public int Read(byte[] buffer)
+ {
+ return _stream.Read(buffer, 0, buffer.Length);
+ }
+
+ public int Seek(int position)
+ {
+ return (int)_stream.Seek(position, SeekOrigin.Begin);
+ }
+
+ public int Length
+ {
+ get
+ {
+ return (int)_stream.Length;
+ }
+ }
+ }
+}