1 module skia.SKPixmap;
2 
3 import skia.SkiaApi;
4 import skia.SKImageInfo;
5 import skia.SKObject;
6 import skia.MathTypes;
7 import skia.SKColorTable;
8 import skia.SKColor;
9 import skia.SKColorF;
10 import skia.SKColorSpace;
11 import skia.Definitions;
12 import skia.SKStream;
13 import skia.SKImage;
14 import skia.Exceptions;
15 import skia.SKData;
16 import skia.SKBitmap;
17 
18 class SKPixmap : SKObject
19 {
20 	private const string UnableToCreateInstanceMessage = "Unable to create a new SKPixmap instance.";
21 
22 	// this is not meant to be anything but a GC reference to keep the actual pixel data alive
23 	SKObject pixelSource;
24 
25 	this (void* handle, bool owns)
26 	{
27     super (handle, owns);
28 	}
29 
30 	this ()
31 	{
32     this (SkiaApi.sk_pixmap_new (), true);
33 		if (Handle is null) {
34 			throw new InvalidOperationException (UnableToCreateInstanceMessage);
35 		}
36 	}
37 
38 	this (SKImageInfo info, void* addr)
39 	{
40     this (info, addr, info.RowBytes);
41 	}
42 
43 	this (SKImageInfo info, void* addr, int rowBytes, SKColorTable ctable)
44 	{
45     this (info, addr, info.RowBytes);
46 	}
47 
48 	this (SKImageInfo info, void* addr, int rowBytes)
49 	{
50     this (null, true);
51 		auto cinfo = SKImageInfo.FromManaged ( info);
52 		Handle = SkiaApi.sk_pixmap_new_with_params (&cinfo, cast(void*)addr, cast(void*)rowBytes);
53 		if (Handle is null) {
54 			throw new InvalidOperationException (UnableToCreateInstanceMessage);
55 		}
56 	}
57 
58 	protected override void Dispose (bool disposing)
59   {
60     return super.Dispose (disposing);
61   }
62 
63   override void Dispose()
64   {
65     return super.Dispose();
66   }
67 		
68 	protected override void DisposeNative ()
69   {
70     return 	SkiaApi.sk_pixmap_destructor (cast(sk_pixmap_t*)Handle);
71   }
72 	
73 
74 	protected override void DisposeManaged ()
75 	{
76 		super.DisposeManaged ();
77 
78 		pixelSource = null;
79 	}
80 
81 	// Reset
82 
83 	void Reset ()
84 	{
85 		SkiaApi.sk_pixmap_reset (cast(sk_pixmap_t*)Handle);
86 		pixelSource = null;
87 	}
88 
89 	void Reset (SKImageInfo info, void* addr, int rowBytes, SKColorTable ctable)
90 	{
91 		Reset (info, addr, rowBytes);
92 	}
93 
94 	void Reset (SKImageInfo info, void* addr, int rowBytes)
95 	{
96 		auto cinfo = SKImageInfo.FromManaged (info);
97 		SkiaApi.sk_pixmap_reset_with_params (cast(sk_pixmap_t*)Handle, &cinfo, cast(void*)addr, cast(void*)rowBytes);
98 		pixelSource = null;
99 	}
100 
101 	// properties
102 
103 	SKImageInfo Info()
104 	{
105 		SKImageInfoNative cinfo;
106 		SkiaApi.sk_pixmap_get_info (cast(sk_pixmap_t*)Handle, &cinfo);
107 		return SKImageInfo.ToManaged ( cinfo);
108 	}
109 
110 	int Width()
111   {
112     return Info.Width;
113   } 
114 
115 	int Height()
116   {
117     return Info.Height;
118   } 
119 
120 	SKSizeI Size() 
121 	{
122 		auto info = Info;
123 		return SKSizeI (info.Width, info.Height);
124 	}
125 
126 	SKRectI Rect()
127   {
128     return SKRectI.Create (Size);
129   } 
130 
131 	SKColorType ColorType()
132   {
133     return Info.ColorType;
134   } 
135 
136 	SKAlphaType AlphaType()
137   {
138     return Info.AlphaType;
139   }
140 
141 	SKColorSpace ColorSpace()
142   {
143     return Info.ColorSpace;
144   } 
145 
146 	int BytesPerPixel()
147   {
148     return Info.BytesPerPixel;
149   } 
150 
151 	int RowBytes()
152   {
153     return cast(int)SkiaApi.sk_pixmap_get_row_bytes (cast(sk_pixmap_t*)Handle);
154   }
155 
156 	int BytesSize()
157   {
158     return Info.BytesSize;
159   }
160 
161 	// pixels
162 
163 	void* GetPixels ()
164   {
165     return cast(void*)SkiaApi.sk_pixmap_get_pixels (cast(sk_pixmap_t*)Handle);
166   }
167 		
168 
169 	void* GetPixels (int x, int y)
170   {
171     return cast(void*)SkiaApi.sk_pixmap_get_pixels_with_xy (cast(sk_pixmap_t*)Handle, x, y);
172   }
173 		
174 
175 	const(byte)[] GetPixelSpan ()
176   {
177 	  const(void)* dataPtr = SkiaApi.sk_pixmap_get_pixels (cast(sk_pixmap_t*)Handle);
178     return cast(const(byte)[])(dataPtr[0..BytesSize]);
179   }
180 		
181 
182 	// unsafe T[] GetPixelSpan<T> ()
183 	// 	where T : unmanaged
184 	// {
185 	// 	auto info = Info;
186 	// 	if (info.empty())
187 	// 		return null;
188 
189 	// 	auto bpp = info.BytesPerPixel;
190 	// 	if (bpp <= 0)
191 	// 		return null;
192 
193 	// 	// byte is always valid
194 	// 	if (typeof (T) == typeof (byte))
195 	// 		return new T[] (SkiaApi.sk_pixmap_get_writable_addr (Handle), info.BytesSize);
196 
197 	// 	// other types need to make sure they fit
198 	// 	auto size = sizeof (T);
199 	// 	if (bpp != size)
200 	// 		throw new ArgumentException ("Size of T ({size}) is not the same as the size of each pixel ({bpp}).", T.stringof);
201 
202 	// 	return new T[] (SkiaApi.sk_pixmap_get_writable_addr (Handle), info.Width * info.Height);
203 	// }
204 
205 	SKColor GetPixelColor (int x, int y)
206 	{
207 		return cast(SKColor)SkiaApi.sk_pixmap_get_pixel_color (cast(sk_pixmap_t*)Handle, x, y);
208 	}
209 
210 	// ColorTable
211 
212 	SKColorTable ColorTable()
213   {
214     return null;
215   }
216 
217 	// Resize
218 
219 	static bool Resize (SKPixmap dst, SKPixmap src, SKBitmapResizeMethod method)
220 	{
221 		if (dst is null)
222 			throw new ArgumentNullException (dst.stringof);
223 		if (src is null)
224 			throw new ArgumentNullException (src.stringof);
225 
226 		return src.ScalePixels (dst, method.ToFilterQuality ());
227 	}
228 
229 	// ScalePixels
230 
231 	bool ScalePixels (SKPixmap destination, SKFilterQuality quality)
232 	{
233 		if (destination is null)
234 			throw new ArgumentNullException (destination.stringof);
235 
236 		return SkiaApi.sk_pixmap_scale_pixels (cast(sk_pixmap_t*)Handle, cast(sk_pixmap_t*)destination.Handle, quality);
237 	}
238 
239 	// ReadPixels
240 
241 	bool ReadPixels (SKImageInfo dstInfo, void* dstPixels, int dstRowBytes, int srcX, int srcY, SKTransferFunctionBehavior behavior)
242   {
243     return ReadPixels (dstInfo, dstPixels, dstRowBytes, srcX, srcY);
244   }
245 		
246 
247 	bool ReadPixels (SKImageInfo dstInfo, void* dstPixels, int dstRowBytes, int srcX, int srcY)
248 	{
249 		auto cinfo = SKImageInfo.FromManaged ( dstInfo);
250 		return SkiaApi.sk_pixmap_read_pixels (cast(sk_pixmap_t*)Handle, &cinfo, cast(void*)dstPixels, cast(void*)dstRowBytes, srcX, srcY);
251 	}
252 
253 	bool ReadPixels (SKImageInfo dstInfo, void* dstPixels, int dstRowBytes)	
254   {
255 		return ReadPixels (dstInfo, dstPixels, dstRowBytes, 0, 0);
256 	}
257 
258 	bool ReadPixels (SKPixmap pixmap, int srcX, int srcY)	
259   {
260 		return ReadPixels (pixmap.Info, pixmap.GetPixels (), pixmap.RowBytes, srcX, srcY);
261 	}
262 
263 	bool ReadPixels (SKPixmap pixmap)	
264   {
265 		return ReadPixels (pixmap.Info, pixmap.GetPixels (), pixmap.RowBytes, 0, 0);
266 	}
267 
268 	// Encode
269 
270 	SKData Encode (SKEncodedImageFormat encoder, int quality)
271 	{
272 		auto stream =  new SKDynamicMemoryWStream ();
273 		scope(exit) {
274 		    stream.Dispose();
275 		}
276 
277 		auto result = Encode (stream, encoder, quality);
278 		return result ? stream.DetachAsData () : null;
279 	}
280 
281 	// bool Encode (Stream dst, SKEncodedImageFormat encoder, int quality)
282 	// {
283 	// 	if (dst is null)
284 	// 		throw new ArgumentNullException (dst.stringof);
285 
286 	// 	auto wrapped =  new SKManagedWStream (dst);
287 	// 	scope(exit) {
288 	// 	    wrapped.Dispose();
289 	// 	}
290 
291 	// 	return Encode (wrapped, encoder, quality);
292 	// }
293 
294 	bool Encode (SKWStream dst, SKEncodedImageFormat encoder, int quality)
295 	{
296 		if (dst is null)
297 			throw new ArgumentNullException (dst.stringof);
298 
299 		return SkiaApi.sk_pixmap_encode_image (cast(sk_wstream_t*)dst.Handle, cast(sk_pixmap_t*)Handle, encoder, quality);
300 	}
301 
302 	static bool Encode (SKWStream dst, SKBitmap src, SKEncodedImageFormat format, int quality)
303 	{
304 		if (dst is null)
305 			throw new ArgumentNullException (dst.stringof);
306 		if (src is null)
307 			throw new ArgumentNullException (src.stringof);
308 
309 		return src.Encode (dst, format, quality);
310 	}
311 
312 	static bool Encode (SKWStream dst, SKPixmap src, SKEncodedImageFormat encoder, int quality)
313 	{
314 		if (dst is null)
315 			throw new ArgumentNullException (dst.stringof);
316 		if (src is null)
317 			throw new ArgumentNullException (src.stringof);
318 
319 		return src.Encode (dst, encoder, quality);
320 	}
321 
322 	// Encode (webp)
323 
324 	SKData Encode (SKWebpEncoderOptions options)
325 	{
326 		auto stream =  new SKDynamicMemoryWStream ();
327 		scope(exit) {
328 		    stream.Dispose();
329 		}
330 
331 		auto result = Encode (stream, options);
332 		return result ? stream.DetachAsData () : null;
333 	}
334 
335 	// bool Encode (Stream dst, SKWebpEncoderOptions options)
336 	// {
337 	// 	if (dst is null)
338 	// 		throw new ArgumentNullException (dst.stringof);
339 
340 	// 	auto wrapped =  new SKManagedWStream (dst);
341 	// 	scope(exit) {
342 	// 	    wrapped.Dispose();
343 	// 	}
344 
345 	// 	return Encode (wrapped, options);
346 	// }
347 
348 	bool Encode (SKWStream dst, SKWebpEncoderOptions options)
349 	{
350 		if (dst is null)
351 			throw new ArgumentNullException (dst.stringof);
352 
353 		return SkiaApi.sk_webpencoder_encode (cast(sk_wstream_t*)dst.Handle, cast(sk_pixmap_t*)Handle, &options);
354 	}
355 
356 	static bool Encode (SKWStream dst, SKPixmap src, SKWebpEncoderOptions options)
357 	{
358 		if (dst is null)
359 			throw new ArgumentNullException (dst.stringof);
360 		if (src is null)
361 			throw new ArgumentNullException (src.stringof);
362 
363 		return src.Encode (dst, options);
364 	}
365 
366 	// Encode (jpeg)
367 
368 	SKData Encode (SKJpegEncoderOptions options)
369 	{
370 		auto stream =  new SKDynamicMemoryWStream ();
371 		scope(exit) {
372 		    stream.Dispose();
373 		}
374 
375 		auto result = Encode (stream, options);
376 		return result ? stream.DetachAsData () : null;
377 	}
378 
379 	// bool Encode (Stream dst, SKJpegEncoderOptions options)
380 	// {
381 	// 	if (dst is null)
382 	// 		throw new ArgumentNullException (dst.stringof);
383 
384 	// 	auto wrapped =  new SKManagedWStream (dst);
385 	// 	scope(exit) {
386 	// 	    wrapped.Dispose();
387 	// 	}
388 
389 	// 	return Encode (wrapped, options);
390 	// }
391 
392 	bool Encode (SKWStream dst, SKJpegEncoderOptions options)
393 	{
394 		if (dst is null)
395 			throw new ArgumentNullException (dst.stringof);
396 
397 		return SkiaApi.sk_jpegencoder_encode (cast(sk_wstream_t*)dst.Handle,cast(sk_pixmap_t*) Handle, &options);
398 	}
399 
400 	static bool Encode (SKWStream dst, SKPixmap src, SKJpegEncoderOptions options)
401 	{
402 		if (dst is null)
403 			throw new ArgumentNullException (dst.stringof);
404 		if (src is null)
405 			throw new ArgumentNullException (src.stringof);
406 
407 		return src.Encode (dst, options);
408 	}
409 
410 	// Encode (png)
411 
412 	SKData Encode (SKPngEncoderOptions options)
413 	{
414 		auto stream =  new SKDynamicMemoryWStream ();
415 		scope(exit) {
416 		    stream.Dispose();
417 		}
418 
419 		auto result = Encode (stream, options);
420 		return result ? stream.DetachAsData () : null;
421 	}
422 
423 	// bool Encode (Stream dst, SKPngEncoderOptions options)
424 	// {
425 	// 	if (dst is null)
426 	// 		throw new ArgumentNullException (dst.stringof);
427 
428 	// 	auto wrapped =  new SKManagedWStream (dst);
429 	// 	scope(exit) {
430 	// 	    wrapped.Dispose();
431 	// 	}
432 
433 	// 	return Encode (wrapped, options);
434 	// }
435 
436 	bool Encode (SKWStream dst, SKPngEncoderOptions options)
437 	{
438 		if (dst is null)
439 			throw new ArgumentNullException (dst.stringof);
440 
441 		return SkiaApi.sk_pngencoder_encode (cast(sk_wstream_t*)dst.Handle,cast(sk_pixmap_t*)Handle, &options);
442 	}
443 
444 	static bool Encode (SKWStream dst, SKPixmap src, SKPngEncoderOptions options)
445 	{
446 		if (dst is null)
447 			throw new ArgumentNullException (dst.stringof);
448 		if (src is null)
449 			throw new ArgumentNullException (src.stringof);
450 
451 		return src.Encode (dst, options);
452 	}
453 
454 	// ExtractSubset
455 
456 	SKPixmap ExtractSubset (SKRectI subset)
457 	{
458 		auto result = new SKPixmap ();
459 		if (!ExtractSubset (result, subset)) {
460 			result.Dispose ();
461 			result = null;
462 		}
463 		return result;
464 	}
465 
466 	bool ExtractSubset (SKPixmap result, SKRectI subset)
467 	{
468 		if (result is null)
469 			throw new ArgumentNullException (result.stringof);
470 
471 		return SkiaApi.sk_pixmap_extract_subset (cast(sk_pixmap_t*)Handle, cast(sk_pixmap_t*)result.Handle, &subset);
472 	}
473 
474 	// Erase
475 
476 	bool Erase (SKColor color)
477 	{
478 		return Erase (color, Rect);
479 	}
480 
481 	bool Erase (SKColor color, SKRectI subset)
482 	{
483 		return SkiaApi.sk_pixmap_erase_color (cast(sk_pixmap_t*)Handle, cast(uint)color, &subset);
484 	}
485 
486 	bool Erase (SKColorF color)	
487   {
488 		return Erase (color, Rect);
489 	}
490 
491 	bool Erase (SKColorF color, SKRectI subset)	
492   {
493 		return SkiaApi.sk_pixmap_erase_color4f (cast(sk_pixmap_t*)Handle, &color, &subset);
494 	}
495 
496 	// With*
497 
498 	SKPixmap WithColorType (SKColorType newColorType)
499 	{
500 		return new SKPixmap (Info.WithColorType (newColorType), GetPixels (), RowBytes);
501 	}
502 
503 	SKPixmap WithColorSpace (SKColorSpace newColorSpace)
504 	{
505 		return new SKPixmap (Info.WithColorSpace (newColorSpace), GetPixels (), RowBytes);
506 	}
507 
508 	SKPixmap WithAlphaType (SKAlphaType newAlphaType)
509 	{
510 		return new SKPixmap (Info.WithAlphaType (newAlphaType), GetPixels (), RowBytes);
511 	}
512 }