FUImageHelper.m 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. //
  2. // FUImageHelper.m
  3. // FULiveDemo
  4. //
  5. // Created by L on 2018/8/3.
  6. // Copyright © 2018年 L. All rights reserved.
  7. //
  8. #import "FUImageHelper.h"
  9. @implementation FUImageHelper
  10. + (void) convertUIImageToBitmapRGBA8:(UIImage *) image completionHandler:(void (^)(int32_t size, unsigned char * bits))completionHandler {
  11. CGImageRef imageRef = image.CGImage;
  12. // Create a bitmap context to draw the uiimage into
  13. CGContextRef context = [self newBitmapRGBA8ContextFromImage:imageRef];
  14. if(!context) {
  15. return ;
  16. }
  17. int32_t width = (int32_t)CGImageGetWidth(imageRef);
  18. int32_t height = (int32_t)CGImageGetHeight(imageRef);
  19. CGRect rect = CGRectMake(0, 0, width, height);
  20. // Draw image into the context to get the raw image data
  21. CGContextDrawImage(context, rect, imageRef);
  22. // Get a pointer to the data
  23. unsigned char *bitmapData = (unsigned char *)CGBitmapContextGetData(context);
  24. // Copy the data and release the memory (return memory allocated with new)
  25. size_t bytesPerRow = CGBitmapContextGetBytesPerRow(context);
  26. size_t bufferLength = bytesPerRow * height;
  27. unsigned char *newBitmap = NULL;
  28. union i32c{
  29. int32_t i32v;
  30. unsigned char bytes[4];
  31. };
  32. union i32c cwidth;
  33. cwidth.i32v = width;
  34. union i32c cheight;
  35. cheight.i32v = height;
  36. if(bitmapData) {
  37. newBitmap = (unsigned char *)malloc(sizeof(unsigned char) * bytesPerRow * height + 8);
  38. newBitmap[0] =cwidth.bytes[0];
  39. newBitmap[1] =cwidth.bytes[1];
  40. newBitmap[2] =cwidth.bytes[2];
  41. newBitmap[3] =cwidth.bytes[3];
  42. newBitmap[4]=cheight.bytes[0];
  43. newBitmap[5] =cheight.bytes[1];
  44. newBitmap[6] =cheight.bytes[2];
  45. newBitmap[7] =cheight.bytes[3];
  46. if(newBitmap) { // Copy the data
  47. for(int i = 8; i < bufferLength+8; ++i) {
  48. newBitmap[i] = bitmapData[i - 8];
  49. }
  50. }
  51. free(bitmapData);
  52. } else {
  53. NSLog(@"Error getting bitmap pixel data\n");
  54. }
  55. CGContextRelease(context);
  56. completionHandler((size_t)bufferLength +8,newBitmap);
  57. }
  58. + (CGContextRef) newBitmapRGBA8ContextFromImage:(CGImageRef) image {
  59. CGContextRef context = NULL;
  60. CGColorSpaceRef colorSpace;
  61. uint32_t *bitmapData;
  62. size_t bitsPerPixel = 32;
  63. size_t bitsPerComponent = 8;
  64. size_t bytesPerPixel = bitsPerPixel / bitsPerComponent;
  65. size_t width = CGImageGetWidth(image);
  66. size_t height = CGImageGetHeight(image);
  67. size_t bytesPerRow = width * bytesPerPixel;
  68. size_t bufferLength = bytesPerRow * height;
  69. colorSpace = CGColorSpaceCreateDeviceRGB();
  70. if(!colorSpace) {
  71. NSLog(@"Error allocating color space RGB\n");
  72. return NULL;
  73. }
  74. // Allocate memory for image data
  75. bitmapData = (uint32_t *)malloc(bufferLength);
  76. if(!bitmapData) {
  77. NSLog(@"Error allocating memory for bitmap\n");
  78. CGColorSpaceRelease(colorSpace);
  79. return NULL;
  80. }
  81. //Create bitmap context
  82. context = CGBitmapContextCreate(bitmapData,
  83. width,
  84. height,
  85. bitsPerComponent,
  86. bytesPerRow,
  87. colorSpace,
  88. kCGImageAlphaPremultipliedLast); // RGBA
  89. if(!context) {
  90. free(bitmapData);
  91. NSLog(@"Bitmap context not created");
  92. }
  93. CGColorSpaceRelease(colorSpace);
  94. return context;
  95. }
  96. + (unsigned char *)getRGBAWithImage:(UIImage *)image
  97. {
  98. int RGBA = 4;
  99. CGImageRef imageRef = [image CGImage];
  100. size_t width = CGImageGetWidth(imageRef);
  101. size_t height = CGImageGetHeight(imageRef);
  102. CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
  103. unsigned char *rawData = (unsigned char *) malloc(width * height * sizeof(unsigned char) * RGBA);
  104. NSUInteger bytesPerPixel = RGBA;
  105. NSUInteger bytesPerRow = bytesPerPixel * width;
  106. NSUInteger bitsPerComponent = 8;
  107. CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
  108. CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
  109. CFRelease(imageRef);
  110. CGColorSpaceRelease(colorSpace);
  111. CGContextRelease(context);
  112. return rawData;
  113. }
  114. + (unsigned char *)getRGBAWithImageName:(NSString *)imageName width:(int *)width height:(int *)height{
  115. //获取图片文件路径
  116. NSString * path = [[NSBundle mainBundle]pathForResource:imageName ofType:@"png"];
  117. NSURL * url = [NSURL fileURLWithPath:path];
  118. CGImageRef imageRef = NULL;
  119. CGImageSourceRef myImageSource;
  120. //通过文件路径创建CGImageSource对象
  121. myImageSource = CGImageSourceCreateWithURL((CFURLRef)url, NULL);
  122. //获取第一张图片
  123. imageRef = CGImageSourceCreateImageAtIndex(myImageSource,
  124. 0,
  125. NULL);
  126. size_t width0 = CGImageGetWidth(imageRef);
  127. size_t height0 = CGImageGetHeight(imageRef);
  128. *width = (int)width0;
  129. *height = (int)height0;
  130. int RGBA = 4;
  131. CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
  132. unsigned char *rawData = (unsigned char *) malloc(width0 * height0 * sizeof(unsigned char) * RGBA);
  133. memset(rawData, 0, width0 * height0 * sizeof(unsigned char) * RGBA);
  134. NSUInteger bytesPerPixel = RGBA;
  135. NSUInteger bytesPerRow = bytesPerPixel * width0;
  136. NSUInteger bitsPerComponent = 8;
  137. CGContextRef context = CGBitmapContextCreate(rawData, width0, height0, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
  138. CGContextDrawImage(context, CGRectMake(0, 0, width0, height0), imageRef);
  139. CFRelease(imageRef);
  140. CGColorSpaceRelease(colorSpace);
  141. CGContextRelease(context);
  142. CFRelease(myImageSource);
  143. return rawData;
  144. }
  145. + (UIImage *) convertBitmapRGBA8ToUIImage:(unsigned char *) buffer
  146. withWidth:(int) width
  147. withHeight:(int) height{
  148. /* 一些到blend完,带上了素材alpha,导致保存效果不对,强行将alpha = 1.0 */
  149. int length = height * width * 4;
  150. for (int i=0; i<length; i+=4)
  151. {
  152. buffer[i+3] = 255;
  153. }
  154. CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
  155. CGContextRef context = CGBitmapContextCreate(buffer,
  156. width,
  157. height,
  158. 8,
  159. width * 4,
  160. colorSpace,
  161. kCGImageAlphaPremultipliedLast);
  162. CGContextSetAlpha(context, 1.0);
  163. CGImageRef imageRef = CGBitmapContextCreateImage(context);
  164. CGContextRelease(context);
  165. CGColorSpaceRelease(colorSpace);
  166. UIImage *image = [UIImage imageWithCGImage:imageRef];
  167. CGImageRelease(imageRef);
  168. return image;
  169. }
  170. +(CVPixelBufferRef) pixelBufferFromImage:(UIImage *)image {
  171. NSDictionary *options = @{
  172. (NSString*)kCVPixelBufferCGImageCompatibilityKey : @YES,
  173. (NSString*)kCVPixelBufferCGBitmapContextCompatibilityKey : @YES,
  174. (NSString*)kCVPixelBufferIOSurfacePropertiesKey: [NSDictionary dictionary]
  175. };
  176. CVPixelBufferRef pxbuffer = NULL;
  177. CGFloat frameWidth = CGImageGetWidth(image.CGImage);
  178. CGFloat frameHeight = CGImageGetHeight(image.CGImage);
  179. CVReturn status = CVPixelBufferCreate(
  180. kCFAllocatorDefault,
  181. frameWidth,
  182. frameHeight,
  183. kCVPixelFormatType_32BGRA,
  184. (__bridge CFDictionaryRef)options,
  185. &pxbuffer);
  186. NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
  187. CVPixelBufferLockBaseAddress(pxbuffer, 0);
  188. void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
  189. NSParameterAssert(pxdata != NULL);
  190. CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
  191. CGContextRef context = CGBitmapContextCreate(
  192. pxdata,
  193. frameWidth,
  194. frameHeight,
  195. 8,
  196. CVPixelBufferGetBytesPerRow(pxbuffer),
  197. rgbColorSpace, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little);
  198. NSParameterAssert(context);
  199. CGContextConcatCTM(context, CGAffineTransformIdentity);
  200. CGContextDrawImage(context, CGRectMake(0, 0, frameWidth, frameHeight), image.CGImage);
  201. CGColorSpaceRelease(rgbColorSpace);
  202. CGContextRelease(context);
  203. CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
  204. // CFRelease(rgbColorSpace) ;
  205. return pxbuffer;
  206. }
  207. +(UIImage *)imageFromPixelBuffer:(CVPixelBufferRef)pixelBufferRef {
  208. CVPixelBufferLockBaseAddress(pixelBufferRef, 0);
  209. float width = CVPixelBufferGetWidth(pixelBufferRef);
  210. float height = CVPixelBufferGetHeight(pixelBufferRef);
  211. CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBufferRef];
  212. CIContext *temporaryContext = [CIContext contextWithOptions:nil];
  213. CGImageRef videoImage = [temporaryContext
  214. createCGImage:ciImage
  215. fromRect:CGRectMake(0, 0,
  216. width,
  217. height)];
  218. UIImage *image = [UIImage imageWithCGImage:videoImage];
  219. CGImageRelease(videoImage);
  220. CVPixelBufferUnlockBaseAddress(pixelBufferRef, 0);
  221. return image;
  222. }
  223. + (UIImage *)imageFromPixelBuffer2:(CVPixelBufferRef)pixelBufferRef {
  224. CVPixelBufferLockBaseAddress(pixelBufferRef, 0);
  225. float width = CVPixelBufferGetWidth(pixelBufferRef);
  226. float height = CVPixelBufferGetHeight(pixelBufferRef);
  227. CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBufferRef];
  228. CIContext *temporaryContext = [CIContext contextWithOptions:nil];
  229. CGImageRef videoImage = [temporaryContext
  230. createCGImage:ciImage
  231. fromRect:CGRectMake(0, 0,
  232. width,
  233. height)];
  234. UIImage *image = [UIImage imageWithCGImage:videoImage];
  235. CGImageRelease(videoImage);
  236. CVPixelBufferUnlockBaseAddress(pixelBufferRef, 0);
  237. return image;
  238. }
  239. /**
  240. 获取屏幕截图
  241. @return 返回屏幕截图
  242. */
  243. //+(UIImage *)fullScreenshots{
  244. // UIWindow *screenWindow = [[UIApplication sharedApplication] keyWindow];
  245. // UIGraphicsBeginImageContext(screenWindow.frame.size);//全屏截图,包括window
  246. // [screenWindow.layer renderInContext:UIGraphicsGetCurrentContext()];
  247. // UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
  248. // return viewImage;
  249. //}
  250. + (UIImage *)fullScreenshots
  251. {
  252. CGSize imageSize = CGSizeZero;
  253. UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
  254. if (UIInterfaceOrientationIsPortrait(orientation)) {
  255. imageSize = [UIScreen mainScreen].bounds.size;
  256. } else {
  257. imageSize = CGSizeMake([UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width);
  258. }
  259. // 传入的View.frame.size是0的话,直接返回nil,防止 UIGraphicsBeginImageContext() 传入0,导致崩溃
  260. if (CGSizeEqualToSize(imageSize, CGSizeZero)) {
  261. return nil;
  262. }
  263. UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
  264. CGContextRef context = UIGraphicsGetCurrentContext();
  265. for (UIWindow *window in [[UIApplication sharedApplication] windows]) {
  266. CGContextSaveGState(context);
  267. CGContextTranslateCTM(context, window.center.x, window.center.y);
  268. CGContextConcatCTM(context, window.transform);
  269. CGContextTranslateCTM(context, -window.bounds.size.width * window.layer.anchorPoint.x, -window.bounds.size.height * window.layer.anchorPoint.y);
  270. if (orientation == UIInterfaceOrientationLandscapeLeft) {
  271. CGContextRotateCTM(context, M_PI_2);
  272. CGContextTranslateCTM(context, 0, -imageSize.width);
  273. } else if (orientation == UIInterfaceOrientationLandscapeRight) {
  274. CGContextRotateCTM(context, -M_PI_2);
  275. CGContextTranslateCTM(context, -imageSize.height, 0);
  276. } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
  277. CGContextRotateCTM(context, M_PI);
  278. CGContextTranslateCTM(context, -imageSize.width, -imageSize.height);
  279. }
  280. if ([window respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) {
  281. [window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES];
  282. } else {
  283. [window.layer renderInContext:context];
  284. }
  285. CGContextRestoreGState(context);
  286. }
  287. UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
  288. UIGraphicsEndImageContext();
  289. return image;
  290. }
  291. /**
  292. 获取点击的颜色
  293. @param point 点击的位置
  294. @return 返回点击地方的颜色
  295. */
  296. +(UIColor*)getPixelColorScreenWindowAtLocation:(CGPoint)point{
  297. UIColor* color = nil;
  298. UIImage *image = [self fullScreenshots];
  299. CGImageRef inImage = image.CGImage;
  300. // Create off screen bitmap context to draw the image into. Format ARGB is 4 bytes for each pixel: Alpa, Red, Green, Blue
  301. CGContextRef cgctx = [self createARGBBitmapContextFromImage:inImage];
  302. if (cgctx == NULL) { return nil; }
  303. size_t w = CGImageGetWidth(inImage);
  304. size_t h = CGImageGetHeight(inImage);
  305. CGRect rect = {{0,0},{w,h}};
  306. // Draw the image to the bitmap context. Once we draw, the memory
  307. // allocated for the context for rendering will then contain the
  308. // raw image data in the specified color space.
  309. CGContextDrawImage(cgctx, rect, inImage);
  310. // Now we can get a pointer to the image data associated with the bitmap
  311. // context.
  312. unsigned char* data = CGBitmapContextGetData (cgctx);
  313. CGFloat scale = [UIScreen mainScreen].scale;
  314. if (data != NULL) {
  315. //offset locates the pixel in the data from x,y.
  316. //4 for 4 bytes of data per pixel, w is width of one row of data.
  317. @try {
  318. int offset = 4*((w*round(point.y * scale))+round(point.x * scale));
  319. int alpha = (int)data[offset];
  320. int red = (int)data[offset+1];
  321. int green = (int)data[offset+2];
  322. int blue = (int)data[offset+3];
  323. color = [UIColor colorWithRed:(red/255.0f) green:(green/255.0f) blue:(blue/255.0f) alpha:(alpha/255.0f)];
  324. free(data);
  325. }
  326. @catch (NSException * e) {
  327. NSLog(@"%@",[e reason]);
  328. }
  329. @finally {
  330. }
  331. }
  332. return color;
  333. }
  334. + (UIColor*) getColorImage:(UIImage *)image withPoint:(CGPoint)point{
  335. UIColor *color = nil;
  336. CGImageRef inImage = image.CGImage;
  337. // Create off screen bitmap context to draw the image into. Format ARGB is 4 bytes for each pixel: Alpa, Red, Green, Blue
  338. CGContextRef cgctx = [self createARGBBitmapContextFromImage:inImage];
  339. if (cgctx == NULL) { return nil; }
  340. size_t w = CGImageGetWidth(inImage);
  341. size_t h = CGImageGetHeight(inImage);
  342. CGRect rect = {{0,0},{w,h}};
  343. // Draw the image to the bitmap context. Once we draw, the memory
  344. // allocated for the context for rendering will then contain the
  345. // raw image data in the specified color space.
  346. CGContextDrawImage(cgctx, rect, inImage);
  347. // Now we can get a pointer to the image data associated with the bitmap
  348. // context.
  349. unsigned char* data = CGBitmapContextGetData (cgctx);
  350. CGFloat scale = [UIScreen mainScreen].scale;
  351. if (data != NULL) {
  352. //offset locates the pixel in the data from x,y.
  353. //4 for 4 bytes of data per pixel, w is width of one row of data.
  354. @try {
  355. int offset = 4*((w*round(point.y))+round(point.x));
  356. int alpha = (int)data[offset];
  357. int red = (int)data[offset+1];
  358. int green = (int)data[offset+2];
  359. int blue = (int)data[offset+3];
  360. color = [UIColor colorWithRed:(red/255.0f) green:(green/255.0f) blue:(blue/255.0f) alpha:(alpha/255.0f)];
  361. free(data);
  362. }
  363. @catch (NSException * e) {
  364. NSLog(@"%@",[e reason]);
  365. }
  366. @finally {
  367. }
  368. }
  369. return color;
  370. }
  371. +(CGContextRef) createARGBBitmapContextFromImage:(CGImageRef) inImage {
  372. CGContextRef context = NULL;
  373. CGColorSpaceRef colorSpace;
  374. void * bitmapData;
  375. int bitmapByteCount;
  376. int bitmapBytesPerRow;
  377. // Get image width, height. We'll use the entire image.
  378. size_t pixelsWide = CGImageGetWidth(inImage);
  379. size_t pixelsHigh = CGImageGetHeight(inImage);
  380. // Declare the number of bytes per row. Each pixel in the bitmap in this
  381. // example is represented by 4 bytes; 8 bits each of red, green, blue, and
  382. // alpha.
  383. bitmapBytesPerRow = (pixelsWide * 4);
  384. bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);
  385. // Use the generic RGB color space.
  386. colorSpace = CGColorSpaceCreateDeviceRGB();
  387. if (colorSpace == NULL) {
  388. fprintf(stderr, "Error allocating color spacen");
  389. return NULL;
  390. }
  391. // Allocate memory for image data. This is the destination in memory
  392. // where any drawing to the bitmap context will be rendered.
  393. bitmapData = malloc( bitmapByteCount );
  394. if (bitmapData == NULL) {
  395. fprintf (stderr, "Memory not allocated!");
  396. CGColorSpaceRelease( colorSpace );
  397. return NULL;
  398. }
  399. // Create the bitmap context. We want pre-multiplied ARGB, 8-bits
  400. // per component. Regardless of what the source image format is
  401. // (CMYK, Grayscale, and so on) it will be converted over to the format
  402. // specified here by CGBitmapContextCreate.
  403. context = CGBitmapContextCreate (bitmapData,
  404. pixelsWide,
  405. pixelsHigh,
  406. 8, // bits per component
  407. bitmapBytesPerRow,
  408. colorSpace,
  409. kCGImageAlphaPremultipliedFirst);
  410. if (context == NULL) {
  411. free (bitmapData);
  412. fprintf (stderr, "Context not created!");
  413. }
  414. // Make sure and release colorspace before returning
  415. CGColorSpaceRelease( colorSpace );
  416. return context;
  417. }
  418. ////点击获取点击位置的颜色
  419. //-(IBAction)onClik:(UITapGestureRecognizer*)tap{
  420. // CGPoint point = [tap locationInView:self];
  421. // UIColor* color = [self getPixelColorAtLocation:point withImage:[self fullScreenshots]];
  422. //}
  423. @end