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 }