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 }