1 module skia.SKData; 2 3 import skia.Definitions; 4 import skia.DelegateProxies; 5 import skia.Exceptions; 6 import skia.SkiaApi; 7 import skia.SKObject; 8 import skia.SKStream; 9 10 import std.algorithm; 11 import std.math; 12 import std.range; 13 import std..string; 14 15 16 /** 17 * 18 */ 19 class SKData : SKObject, ISKNonVirtualReferenceCounted 20 { 21 // We pick a value that is the largest multiple of 4096 that is still smaller than the large object heap threshold (85K). 22 // The CopyTo/CopyToAsync buffer is short-lived and is likely to be collected at Gen0, and it offers a significant 23 // improvement in Copy performance. 24 enum int CopyBufferSize = 81920; 25 26 private __gshared SKData empty; 27 28 shared static this() 29 { 30 empty = new SKDataStatic (SkiaApi.sk_data_new_empty ()); 31 } 32 33 static void EnsureStaticInstanceAreInitialized () 34 { 35 // IMPORTANT: do not remove to ensure that the static instances 36 // are initialized before any access is made to them 37 } 38 39 this (void* x, bool owns) 40 { 41 super (x, owns); 42 } 43 44 protected override void Dispose (bool disposing) 45 { 46 return super.Dispose (disposing); 47 } 48 49 override void Dispose () 50 { 51 super.Dispose (); 52 } 53 54 void ReferenceNative () { return SkiaApi.sk_data_ref (cast(sk_data_t*)Handle); } 55 56 void UnreferenceNative () { return SkiaApi.sk_data_unref (cast(sk_data_t*)Handle); } 57 58 static SKData Empty () { return empty; } 59 60 // CreateCopy 61 62 static SKData CreateCopy (void* bytes, ulong length) 63 { 64 // if (!PlatformConfiguration.Is64Bit && length > uint.max) 65 // throw new ArgumentOutOfRangeException (length.stringof, "The length exceeds the size of pointers."); 66 return GetObject (SkiaApi.sk_data_new_with_copy (cast(void*)bytes, cast(size_t) length)); 67 } 68 69 static SKData CreateCopy ( byte[] bytes) 70 { 71 return CreateCopy (bytes, bytes.length); 72 } 73 74 static SKData CreateCopy (byte[] bytes, size_t length) 75 { 76 byte* b = bytes.ptr; 77 return GetObject (SkiaApi.sk_data_new_with_copy (b, length)); 78 } 79 80 // static SKData CreateCopy (const(byte)[] bytes) 81 // { 82 // byte* b = bytes.ptr; 83 // return CreateCopy (cast(void*)b, bytes.length); 84 // } 85 86 // Create 87 88 static SKData Create (int size) 89 { 90 return GetObject (SkiaApi.sk_data_new_uninitialized (cast(size_t) size)); 91 } 92 93 static SKData Create (size_t size) 94 { 95 version(X86) { 96 if (size > uint.max) 97 throw new ArgumentOutOfRangeException (size.stringof, "The size exceeds the size of pointers."); 98 } 99 100 return GetObject (SkiaApi.sk_data_new_uninitialized (size)); 101 } 102 103 static SKData Create (string filename) 104 { 105 if (filename.empty()) 106 throw new ArgumentException ("The filename cannot be empty.", filename.stringof); 107 108 // auto utf8path = StringUtilities.GetEncodedText (filename, SKTextEncoding.Utf8, true); 109 auto utf8path = filename.toStringz(); 110 byte* u = cast(byte*)utf8path; 111 return GetObject (SkiaApi.sk_data_new_from_file (u.stringof)); 112 } 113 114 // static SKData Create (Stream stream) 115 // { 116 // if (stream is null) 117 // throw new ArgumentNullException (stream.stringof); 118 // if (stream.CanSeek) { 119 // return Create (stream, stream.Length); 120 // } else { 121 // auto memory = new SKDynamicMemoryWStream (); 122 // scope(exit) { 123 // memory.Dispose(); 124 // } 125 126 // using (var managed = new SKManagedStream (stream)) { 127 // managed.CopyTo (memory); 128 // } 129 // return memory.DetachAsData (); 130 // } 131 // } 132 133 // static SKData Create (Stream stream, int length) 134 // { 135 // if (stream is null) 136 // throw new ArgumentNullException (stream.stringof); 137 138 // SKManagedStream managed = new SKManagedStream (stream); 139 // return Create (managed, length); 140 // } 141 142 // static SKData Create (Stream stream, ulong length) 143 // { 144 // if (stream is null) 145 // throw new ArgumentNullException (stream.stringof); 146 147 // SKManagedStream managed = new SKManagedStream (stream); 148 // return Create (managed, length); 149 // } 150 151 // static SKData Create (Stream stream, long length) 152 // { 153 // if (stream is null) 154 // throw new ArgumentNullException (stream.stringof); 155 156 // SKManagedStream managed = new SKManagedStream (stream); 157 // return Create (managed, length); 158 // } 159 160 static SKData Create (SKStream stream) 161 { 162 if (stream is null) 163 throw new ArgumentNullException (stream.stringof); 164 165 return Create (stream, stream.Length); 166 } 167 168 static SKData Create (SKStream stream, int length) 169 { 170 if (stream is null) 171 throw new ArgumentNullException (stream.stringof); 172 173 return GetObject (SkiaApi.sk_data_new_from_stream (cast(sk_stream_t*)stream.Handle, cast(size_t)length)); 174 } 175 176 static SKData Create (SKStream stream, ulong length) 177 { 178 if (stream is null) 179 throw new ArgumentNullException (stream.stringof); 180 181 return GetObject (SkiaApi.sk_data_new_from_stream (cast(sk_stream_t*)stream.Handle, cast(size_t)length)); 182 } 183 184 static SKData Create (SKStream stream, long length) 185 { 186 if (stream is null) 187 throw new ArgumentNullException (stream.stringof); 188 189 return GetObject (SkiaApi.sk_data_new_from_stream (cast(sk_stream_t*)stream.Handle, cast(size_t)length)); 190 } 191 192 // static SKData Create (void* address, int length) 193 // { 194 // return Create (address, length, null, null); 195 // } 196 197 static SKData Create (void* address, size_t length) 198 { 199 return Create (address, length, null, null); 200 } 201 202 static SKData Create (void* address, size_t length, SKDataReleaseDelegate releaseProc) 203 { 204 return Create (address, length, releaseProc, null); 205 } 206 207 static SKData Create (void* address, size_t length, SKDataReleaseDelegate releaseProc, void* context) 208 { 209 // SKDataReleaseDelegate del = releaseProc !is null && context !is null 210 // ? new SKDataReleaseDelegate ((addr, _) () { return releaseProc (addr, context)) } 211 // : releaseProc; 212 213 214 SKDataReleaseDelegate del = releaseProc; 215 if(releaseProc !is null && context !is null) { 216 del = (addr, _t) { releaseProc (addr, context); }; 217 } 218 219 220 // https://www.cnblogs.com/zhaox583132460/p/3402243.html 221 // FIXME: Needing refactor or cleanup -@putao at 2021-01-10T21:25:11+08:00 222 // More tests needed 223 SKDataReleaseDelegateWrapper wrapper = SKDataReleaseDelegateWrapper(del); 224 225 void* ctx = cast(void*)&wrapper; 226 SKDataReleaseProxyDelegate releaseProxy = DelegateProxies.SKDataReleaseDelegateProxy; 227 SKDataReleaseProxyDelegate proxy = DelegateProxies.Create (releaseProxy, ctx); 228 229 return GetObject (SkiaApi.sk_data_new_with_proc (cast(void*)address, length, proxy, ctx)); 230 } 231 232 static SKData FromCString (string str) 233 { 234 // auto bytes = Encoding.ASCII.GetBytes (str ?? string.Empty); 235 byte[] bytes = cast(byte[])str.dup; 236 237 return SKData.CreateCopy (bytes, bytes.length + 1); // + 1 for the terminating char 238 } 239 240 // Subset 241 242 SKData Subset (ulong offset, ulong length) 243 { 244 version(X86) { 245 if (length > uint.max) 246 throw new ArgumentOutOfRangeException (length.stringof, "The length exceeds the size of pointers."); 247 if (offset > uint.max) 248 throw new ArgumentOutOfRangeException (offset.stringof, "The offset exceeds the size of pointers."); 249 } 250 return GetObject (SkiaApi.sk_data_new_subset (cast(sk_data_t*)Handle, cast(size_t) offset, cast(size_t) length)); 251 } 252 253 // ToArray 254 255 byte[] ToArray () 256 { 257 byte[] array = cast(byte[])AsSpan ().dup; 258 // GC.KeepAlive (this); 259 return array; 260 } 261 262 // properties 263 264 bool IsEmpty () { return Size == 0; } 265 266 long Size () { return cast(long)SkiaApi.sk_data_get_size (cast(sk_data_t*)Handle); } 267 268 void* Data () { return cast(void*)SkiaApi.sk_data_get_data (cast(sk_data_t*)Handle); } 269 270 // AsStream 271 272 // Stream AsStream () 273 // { 274 // return new SKDataStream (this, false); 275 // } 276 277 278 // Stream AsStream (bool streamDisposesData) 279 // { 280 // return new SKDataStream (this, streamDisposesData); 281 // } 282 283 284 // AsSpan 285 286 const(byte)[] AsSpan () 287 { 288 void* data = cast(void*)Data; 289 return cast(const(byte)[]) data[0 .. Size()]; 290 } 291 292 // SaveTo 293 void SaveTo (DataWriter target) 294 { 295 if (target is null) 296 throw new ArgumentNullException (target.stringof); 297 298 void* ptr = Data; 299 long total = Size; 300 // ubyte[] buffer = new ubyte[CopyBufferSize]; 301 302 for (long left = total; left > 0;) { 303 auto copyCount = cast(int)min (CopyBufferSize, left); 304 target(cast(ubyte[]) ptr[0..copyCount]); 305 left -= copyCount; 306 ptr += copyCount; 307 } 308 } 309 310 // void SaveTo (Stream target) 311 // { 312 // if (target is null) 313 // throw new ArgumentNullException (target.stringof); 314 315 // void* ptr = Data; 316 // long total = Size; 317 // byte[] buffer = new byte[CopyBufferSize]; // Utils.RentArray<byte> (CopyBufferSize); 318 // scope(exit) { 319 // buffer.Dispose(); 320 // } 321 322 // for (var left = total; left > 0;) { 323 // auto copyCount = cast(int)min (CopyBufferSize, left); 324 // // Marshal.Copy (ptr, buffer, 0, copyCount); 325 // buffer[0..copyCount] = ptr[0..copyCount]; 326 327 // left -= copyCount; 328 // ptr += copyCount; 329 // target.Write (buffer, 0, copyCount); 330 // } 331 // // GC.KeepAlive (this); 332 // } 333 334 static SKData GetObject (void* handle) 335 { 336 return GetOrAddObject!(SKData)(handle, delegate SKData (h, o) { return new SKData (h, o);}); 337 } 338 } 339 340 // 341 342 // private class SKDataStream // : UnmanagedMemoryStream 343 // { 344 // private SKData host; 345 // private bool disposeHost; 346 347 // this (SKData host, bool disposeHost = false) 348 // { 349 // // super(cast(byte *) host.Data, host.Size); 350 // this.host = host; 351 // this.disposeHost = disposeHost; 352 // } 353 354 // protected void Dispose (bool disposing) 355 // // protected override void Dispose (bool disposing) 356 // { 357 // super.Dispose (disposing); 358 // if (disposeHost) { 359 // if(host !is null) host.Dispose (); 360 // } 361 // host = null; 362 // } 363 // } 364 365 // 366 367 private final class SKDataStatic : SKData 368 { 369 this (void* x) 370 { 371 super (x, true); 372 IgnorePublicDispose = true; 373 } 374 } 375