SDImageGraphics.m 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /*
  2. * This file is part of the SDWebImage package.
  3. * (c) Olivier Poitrey <rs@dailymotion.com>
  4. *
  5. * For the full copyright and license information, please view the LICENSE
  6. * file that was distributed with this source code.
  7. */
  8. #import "SDImageGraphics.h"
  9. #import "NSImage+Compatibility.h"
  10. #import "objc/runtime.h"
  11. #if SD_MAC
  12. static void *kNSGraphicsContextScaleFactorKey;
  13. static CGContextRef SDCGContextCreateBitmapContext(CGSize size, BOOL opaque, CGFloat scale) {
  14. if (scale == 0) {
  15. // Match `UIGraphicsBeginImageContextWithOptions`, reset to the scale factor of the device’s main screen if scale is 0.
  16. scale = [NSScreen mainScreen].backingScaleFactor;
  17. }
  18. size_t width = ceil(size.width * scale);
  19. size_t height = ceil(size.height * scale);
  20. if (width < 1 || height < 1) return NULL;
  21. //pre-multiplied BGRA for non-opaque, BGRX for opaque, 8-bits per component, as Apple's doc
  22. CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
  23. CGImageAlphaInfo alphaInfo = kCGBitmapByteOrder32Host | (opaque ? kCGImageAlphaNoneSkipFirst : kCGImageAlphaPremultipliedFirst);
  24. CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, space, kCGBitmapByteOrderDefault | alphaInfo);
  25. CGColorSpaceRelease(space);
  26. if (!context) {
  27. return NULL;
  28. }
  29. CGContextScaleCTM(context, scale, scale);
  30. return context;
  31. }
  32. #endif
  33. CGContextRef SDGraphicsGetCurrentContext(void) {
  34. #if SD_UIKIT || SD_WATCH
  35. return UIGraphicsGetCurrentContext();
  36. #else
  37. return NSGraphicsContext.currentContext.CGContext;
  38. #endif
  39. }
  40. void SDGraphicsBeginImageContext(CGSize size) {
  41. #if SD_UIKIT || SD_WATCH
  42. UIGraphicsBeginImageContext(size);
  43. #else
  44. SDGraphicsBeginImageContextWithOptions(size, NO, 1.0);
  45. #endif
  46. }
  47. void SDGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale) {
  48. #if SD_UIKIT || SD_WATCH
  49. UIGraphicsBeginImageContextWithOptions(size, opaque, scale);
  50. #else
  51. CGContextRef context = SDCGContextCreateBitmapContext(size, opaque, scale);
  52. if (!context) {
  53. return;
  54. }
  55. NSGraphicsContext *graphicsContext = [NSGraphicsContext graphicsContextWithCGContext:context flipped:NO];
  56. objc_setAssociatedObject(graphicsContext, &kNSGraphicsContextScaleFactorKey, @(scale), OBJC_ASSOCIATION_RETAIN);
  57. CGContextRelease(context);
  58. [NSGraphicsContext saveGraphicsState];
  59. NSGraphicsContext.currentContext = graphicsContext;
  60. #endif
  61. }
  62. void SDGraphicsEndImageContext(void) {
  63. #if SD_UIKIT || SD_WATCH
  64. UIGraphicsEndImageContext();
  65. #else
  66. [NSGraphicsContext restoreGraphicsState];
  67. #endif
  68. }
  69. UIImage * SDGraphicsGetImageFromCurrentImageContext(void) {
  70. #if SD_UIKIT || SD_WATCH
  71. return UIGraphicsGetImageFromCurrentImageContext();
  72. #else
  73. NSGraphicsContext *context = NSGraphicsContext.currentContext;
  74. CGContextRef contextRef = context.CGContext;
  75. if (!contextRef) {
  76. return nil;
  77. }
  78. CGImageRef imageRef = CGBitmapContextCreateImage(contextRef);
  79. if (!imageRef) {
  80. return nil;
  81. }
  82. CGFloat scale = 0;
  83. NSNumber *scaleFactor = objc_getAssociatedObject(context, &kNSGraphicsContextScaleFactorKey);
  84. if ([scaleFactor isKindOfClass:[NSNumber class]]) {
  85. scale = scaleFactor.doubleValue;
  86. }
  87. if (!scale) {
  88. // reset to the scale factor of the device’s main screen if scale is 0.
  89. scale = [NSScreen mainScreen].backingScaleFactor;
  90. }
  91. NSImage *image = [[NSImage alloc] initWithCGImage:imageRef scale:scale orientation:kCGImagePropertyOrientationUp];
  92. CGImageRelease(imageRef);
  93. return image;
  94. #endif
  95. }