1 module skia.SKCodec; 2 3 import skia.Exceptions; 4 import skia.SkiaApi; 5 import skia.SKImageInfo; 6 import skia.SKObject; 7 import skia.SKColorTable; 8 import skia.SKColorTable; 9 import skia.SKStream; 10 import skia.SKData; 11 import skia.Definitions; 12 import skia.MathTypes; 13 import skia.Definitions; 14 15 // TODO: `Create(...)` should have overloads that accept a SKPngChunkReader 16 // TODO: missing the `QueryYuv8` and `GetYuv8Planes` members 17 18 class SKCodec : SKObject, ISKSkipObjectRegistration 19 { 20 this (void* handle, bool owns) 21 { 22 super (handle, owns); 23 } 24 25 protected override void Dispose (bool disposing) 26 { 27 return super.Dispose (disposing); 28 } 29 30 override void Dispose() 31 { 32 return super.Dispose(); 33 } 34 35 protected override void DisposeNative () 36 { 37 return SkiaApi.sk_codec_destroy (cast(sk_codec_t*)Handle); 38 } 39 40 static int MinBufferedBytesNeeded () 41 { 42 return cast(int)SkiaApi.sk_codec_min_buffered_bytes_needed (); 43 } 44 45 SKImageInfo Info() { 46 SKImageInfoNative cinfo; 47 SkiaApi.sk_codec_get_info (cast(sk_codec_t*)Handle, &cinfo); 48 return SKImageInfo.ToManaged (cinfo); 49 } 50 51 SKCodecOrigin Origin() 52 { 53 return cast(SKCodecOrigin)EncodedOrigin; 54 } 55 56 SKEncodedOrigin EncodedOrigin() 57 { 58 return SkiaApi.sk_codec_get_origin (cast(sk_codec_t*)Handle); 59 } 60 61 SKEncodedImageFormat EncodedFormat() 62 { 63 return SkiaApi.sk_codec_get_encoded_format (cast(sk_codec_t*)Handle); 64 } 65 66 SKSizeI GetScaledDimensions (float desiredScale) 67 { 68 SKSizeI dimensions; 69 SkiaApi.sk_codec_get_scaled_dimensions (cast(sk_codec_t*)Handle, desiredScale, &dimensions); 70 return dimensions; 71 } 72 73 bool GetValidSubset (ref SKRectI desiredSubset) 74 { 75 SKRectI* ds = &desiredSubset; 76 return SkiaApi.sk_codec_get_valid_subset (cast(sk_codec_t*)Handle, ds); 77 } 78 79 byte[] Pixels() { 80 byte[] pixels; 81 SKCodecResult result = GetPixels (pixels); 82 if (result != SKCodecResult.Success && result != SKCodecResult.IncompleteInput) { 83 throw new Exception (result.stringof); 84 } 85 return pixels; 86 } 87 88 // frames 89 90 int RepetitionCount() 91 { 92 return SkiaApi.sk_codec_get_repetition_count (cast(sk_codec_t*)Handle); 93 } 94 95 int FrameCount() 96 { 97 return SkiaApi.sk_codec_get_frame_count (cast(sk_codec_t*)Handle); 98 } 99 100 SKCodecFrameInfo[] FrameInfo() { 101 int length = SkiaApi.sk_codec_get_frame_count (cast(sk_codec_t*)Handle); 102 SKCodecFrameInfo[] info = new SKCodecFrameInfo[length]; 103 SKCodecFrameInfo* i = info.ptr; 104 SkiaApi.sk_codec_get_frame_info (cast(sk_codec_t*)Handle, i); 105 106 return info; 107 } 108 109 bool GetFrameInfo (int index, out SKCodecFrameInfo frameInfo) 110 { 111 SKCodecFrameInfo* f = &frameInfo; 112 return SkiaApi.sk_codec_get_frame_info_for_index (cast(sk_codec_t*)Handle, index, f); 113 } 114 115 // pixels 116 117 SKCodecResult GetPixels (out byte[] pixels) 118 { 119 return GetPixels (Info, pixels); 120 } 121 122 SKCodecResult GetPixels (SKImageInfo info, out byte[] pixels) 123 { 124 pixels = new byte[info.BytesSize]; 125 return GetPixels (info, pixels); 126 } 127 128 SKCodecResult GetPixels (SKImageInfo info, byte[] pixels) 129 { 130 if (pixels is null) 131 throw new ArgumentNullException (pixels.stringof); 132 133 byte* p = pixels.ptr; 134 return GetPixels (info, cast(void*)p, info.RowBytes, SKCodecOptions.Default); 135 } 136 137 SKCodecResult GetPixels (SKImageInfo info, void* pixels) 138 { 139 return GetPixels (info, pixels, info.RowBytes, SKCodecOptions.Default); 140 } 141 142 SKCodecResult GetPixels (SKImageInfo info, void* pixels, SKCodecOptions options) 143 { 144 return GetPixels (info, pixels, info.RowBytes, options); 145 } 146 147 SKCodecResult GetPixels (SKImageInfo info, void* pixels, int rowBytes, SKCodecOptions options) 148 { 149 if (pixels is null) 150 throw new ArgumentNullException (pixels.stringof); 151 152 auto nInfo = SKImageInfo.FromManaged (info); 153 SKCodecOptionsInternal nOptions = SKCodecOptionsInternal( 154 options.ZeroInitialized, 155 null, 156 options.FrameIndex, 157 options.PriorFrame, 158 ); 159 160 // auto subset = default (SKRectI); 161 if (options.HasSubset) { 162 SKRectI subset = options.Subset.get; 163 nOptions.fSubset = ⊂ 164 } 165 return SkiaApi.sk_codec_get_pixels (cast(sk_codec_t*)Handle, &nInfo, cast(void*)pixels, cast(size_t)rowBytes, &nOptions); 166 } 167 168 SKCodecResult GetPixels (SKImageInfo info, void* pixels, int rowBytes, SKCodecOptions options, void* colorTable, ref int colorTableCount) 169 { 170 return GetPixels (info, pixels, rowBytes, options); 171 } 172 173 SKCodecResult GetPixels (SKImageInfo info, void* pixels, SKCodecOptions options, void* colorTable, ref int colorTableCount) 174 { 175 return GetPixels (info, pixels, info.RowBytes, options); 176 } 177 178 SKCodecResult GetPixels (SKImageInfo info, void* pixels, void* colorTable, ref int colorTableCount) 179 { 180 return GetPixels (info, pixels, info.RowBytes, SKCodecOptions.Default); 181 } 182 183 SKCodecResult GetPixels (SKImageInfo info, void* pixels, int rowBytes, SKCodecOptions options, SKColorTable colorTable, ref int colorTableCount) 184 { 185 return GetPixels (info, pixels, rowBytes, options); 186 } 187 188 SKCodecResult GetPixels (SKImageInfo info, void* pixels, SKCodecOptions options, SKColorTable colorTable, ref int colorTableCount) 189 { 190 return GetPixels (info, pixels, info.RowBytes, options); 191 } 192 193 SKCodecResult GetPixels (SKImageInfo info, void* pixels, SKColorTable colorTable, ref int colorTableCount) 194 { 195 return GetPixels (info, pixels, info.RowBytes, SKCodecOptions.Default); 196 } 197 198 // incremental (start) 199 200 SKCodecResult StartIncrementalDecode (SKImageInfo info, void* pixels, int rowBytes, SKCodecOptions options) 201 { 202 if (pixels is null) 203 throw new ArgumentNullException (pixels.stringof); 204 205 auto nInfo = SKImageInfo.FromManaged (info); 206 SKCodecOptionsInternal nOptions = SKCodecOptionsInternal(); 207 { 208 nOptions.fZeroInitialized = options.ZeroInitialized; 209 nOptions.fSubset = null; 210 nOptions.fFrameIndex = options.FrameIndex; 211 nOptions.fPriorFrame = options.PriorFrame; 212 } 213 // SKRectI subset = default (SKRectI); 214 if (options.HasSubset) { 215 SKRectI subset = (options.Subset.get); 216 nOptions.fSubset = ⊂ 217 } 218 219 return SkiaApi.sk_codec_start_incremental_decode (cast(sk_codec_t*)Handle, &nInfo, cast(void*)pixels, cast(void*)rowBytes, &nOptions); 220 } 221 222 SKCodecResult StartIncrementalDecode (SKImageInfo info, void* pixels, int rowBytes) 223 { 224 auto cinfo = SKImageInfo.FromManaged (info); 225 return SkiaApi.sk_codec_start_incremental_decode (cast(sk_codec_t*)Handle, &cinfo, cast(void*)pixels, cast(void*)rowBytes, null); 226 } 227 228 SKCodecResult StartIncrementalDecode (SKImageInfo info, void* pixels, int rowBytes, SKCodecOptions options, void* colorTable, ref int colorTableCount) 229 { 230 return StartIncrementalDecode (info, pixels, rowBytes, options); 231 } 232 233 SKCodecResult StartIncrementalDecode (SKImageInfo info, void* pixels, int rowBytes, SKCodecOptions options, SKColorTable colorTable, ref int colorTableCount) 234 { 235 return StartIncrementalDecode (info, pixels, rowBytes, options); 236 } 237 238 // incremental (step) 239 240 SKCodecResult IncrementalDecode (out int rowsDecoded) 241 { 242 int* r = &rowsDecoded; 243 return SkiaApi.sk_codec_incremental_decode (cast(sk_codec_t*)Handle, r); 244 } 245 246 SKCodecResult IncrementalDecode () 247 { 248 return SkiaApi.sk_codec_incremental_decode (cast(sk_codec_t*)Handle, null); 249 } 250 251 // scanline (start) 252 253 SKCodecResult StartScanlineDecode (SKImageInfo info, SKCodecOptions options) 254 { 255 auto nInfo = SKImageInfo.FromManaged (info); 256 SKCodecOptionsInternal nOptions = SKCodecOptionsInternal(); { 257 nOptions.fZeroInitialized = options.ZeroInitialized; 258 nOptions.fSubset = null; 259 nOptions.fFrameIndex = options.FrameIndex; 260 nOptions.fPriorFrame = options.PriorFrame; 261 } 262 // SKRectI subset = default (SKRectI); 263 if (options.HasSubset) { 264 SKRectI subset = options.Subset.get; 265 nOptions.fSubset = ⊂ 266 } 267 268 return SkiaApi.sk_codec_start_scanline_decode (cast(sk_codec_t*)Handle, &nInfo, &nOptions); 269 } 270 271 SKCodecResult StartScanlineDecode (SKImageInfo info) 272 { 273 auto cinfo = SKImageInfo.FromManaged (info); 274 return SkiaApi.sk_codec_start_scanline_decode (cast(sk_codec_t*)Handle, &cinfo, null); 275 } 276 277 SKCodecResult StartScanlineDecode (SKImageInfo info, SKCodecOptions options, void* colorTable, ref int colorTableCount) 278 { 279 return StartScanlineDecode (info, options); 280 } 281 282 SKCodecResult StartScanlineDecode (SKImageInfo info, SKCodecOptions options, SKColorTable colorTable, ref int colorTableCount) 283 { 284 return StartScanlineDecode (info, options); 285 } 286 287 // scanline (step) 288 289 int GetScanlines (void* dst, int countLines, int rowBytes) 290 { 291 if (dst is null) 292 throw new ArgumentNullException (dst.stringof); 293 294 return SkiaApi.sk_codec_get_scanlines (cast(sk_codec_t*)Handle, cast(void*)dst, countLines, cast(size_t)rowBytes); 295 } 296 297 bool SkipScanlines (int countLines) 298 { 299 return SkiaApi.sk_codec_skip_scanlines (cast(sk_codec_t*)Handle, countLines); 300 } 301 302 SKCodecScanlineOrder ScanlineOrder() 303 { 304 return SkiaApi.sk_codec_get_scanline_order (cast(sk_codec_t*)Handle); 305 } 306 307 int NextScanline() 308 { 309 return SkiaApi.sk_codec_next_scanline (cast(sk_codec_t*)Handle); 310 } 311 312 int GetOutputScanline (int inputScanline) 313 { 314 return SkiaApi.sk_codec_output_scanline (cast(sk_codec_t*)Handle, inputScanline); 315 } 316 317 // create (streams) 318 319 static SKCodec Create (string filename) 320 { 321 SKCodecResult result; 322 return Create (filename, result); 323 } 324 325 static SKCodec Create (string filename, ref SKCodecResult result) 326 { 327 SKStreamAsset stream = SKFileStream.OpenStream (filename); 328 if (stream is null) { 329 result = SKCodecResult.InternalError; 330 return null; 331 } 332 333 return Create (stream, result); 334 } 335 336 // static SKCodec Create (Stream stream) 337 // { 338 // SKCodecResult result; 339 // return Create (stream, result); 340 // } 341 342 // static SKCodec Create (Stream stream, ref SKCodecResult result) 343 // { 344 // return Create (WrapManagedStream (stream), result); 345 // } 346 347 static SKCodec Create (SKStream stream) 348 { 349 SKCodecResult result; 350 return Create (stream, result); 351 } 352 353 static SKCodec Create (SKStream stream, ref SKCodecResult result) 354 { 355 if (stream is null) 356 throw new ArgumentNullException (stream.stringof); 357 358 SKCodecResult* r = &result; 359 auto codec = GetObject (SkiaApi.sk_codec_new_from_stream (cast(sk_stream_t*)stream.Handle, r)); 360 stream.RevokeOwnership (codec); 361 return codec; 362 } 363 364 // create (data) 365 366 static SKCodec Create (SKData data) 367 { 368 if (data is null) 369 throw new ArgumentNullException (data.stringof); 370 371 return GetObject (SkiaApi.sk_codec_new_from_data (cast(sk_data_t*)data.Handle)); 372 } 373 374 // utils 375 376 // static SKStream WrapManagedStream (Stream stream) 377 // { 378 // if (&stream is null) { 379 // throw new ArgumentNullException (stream.stringof); 380 // } 381 382 // // we will need a seekable stream, so buffer it if need be 383 // if (stream.CanSeek) { 384 // return new SKManagedStream (stream, true); 385 // } else { 386 // return new SKFrontBufferedManagedStream (stream, MinBufferedBytesNeeded, true); 387 // } 388 // } 389 390 static SKCodec GetObject (void* handle) 391 { 392 return handle is null ? null : new SKCodec (handle, true); 393 } 394 }