GPUImagePicture+TextureSubimage.m 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. //
  2. // GPUImagePicture+TextureSubimage.m
  3. // GPUImage
  4. //
  5. // Created by Jack Wu on 2014-05-28.
  6. // Copyright (c) 2014 Brad Larson. All rights reserved.
  7. //
  8. #import "GPUImagePicture+TextureSubimage.h"
  9. @implementation GPUImagePicture (TextureSubimage)
  10. - (void)replaceTextureWithSubimage:(UIImage*)subimage {
  11. return [self replaceTextureWithSubCGImage:[subimage CGImage]];
  12. }
  13. - (void)replaceTextureWithSubCGImage:(CGImageRef)subimageSource {
  14. CGRect rect = (CGRect) {.origin = CGPointZero, .size = (CGSize){.width = CGImageGetWidth(subimageSource), .height = CGImageGetHeight(subimageSource)}};
  15. return [self replaceTextureWithSubCGImage:subimageSource inRect:rect];
  16. }
  17. - (void)replaceTextureWithSubimage:(UIImage*)subimage inRect:(CGRect)subRect {
  18. return [self replaceTextureWithSubCGImage:[subimage CGImage] inRect:subRect];
  19. }
  20. - (void)replaceTextureWithSubCGImage:(CGImageRef)subimageSource inRect:(CGRect)subRect {
  21. NSAssert(outputFramebuffer, @"Picture must be initialized first before replacing subtexture");
  22. NSAssert(self.framebufferForOutput.textureOptions.internalFormat == GL_RGBA, @"For replacing subtexture the internal texture format must be GL_RGBA.");
  23. CGRect subimageRect = (CGRect){.origin = CGPointZero, .size = (CGSize){.width = CGImageGetWidth(subimageSource), .height = CGImageGetHeight(subimageSource)}};
  24. NSAssert(!CGRectIsEmpty(subimageRect), @"Passed sub image must not be empty - it should be at least 1px tall and wide");
  25. NSAssert(!CGRectIsEmpty(subRect), @"Passed sub rect must not be empty");
  26. NSAssert(CGSizeEqualToSize(subimageRect.size, subRect.size), @"Subimage size must match the size of sub rect");
  27. // We don't have to worry about scaling the subimage or finding a power of two size.
  28. // The initialization has taken care of that for us.
  29. dispatch_semaphore_signal(imageUpdateSemaphore);
  30. BOOL shouldRedrawUsingCoreGraphics = NO;
  31. // Since internal format is always RGBA, we need the input data in RGBA as well.
  32. CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(subimageSource);
  33. CGBitmapInfo byteOrderInfo = bitmapInfo & kCGBitmapByteOrderMask;
  34. if (byteOrderInfo != kCGBitmapByteOrderDefault && byteOrderInfo != kCGBitmapByteOrder32Big) {
  35. shouldRedrawUsingCoreGraphics = YES;
  36. }
  37. else {
  38. CGImageAlphaInfo alphaInfo = bitmapInfo & kCGBitmapAlphaInfoMask;
  39. if (alphaInfo != kCGImageAlphaPremultipliedLast && alphaInfo != kCGImageAlphaLast && alphaInfo != kCGImageAlphaNoneSkipLast) {
  40. shouldRedrawUsingCoreGraphics = YES;
  41. }
  42. }
  43. GLubyte *imageData = NULL;
  44. CFDataRef dataFromImageDataProvider;
  45. if (shouldRedrawUsingCoreGraphics)
  46. {
  47. // For resized or incompatible image: redraw
  48. imageData = (GLubyte *) calloc(1, (int)subimageRect.size.width * (int)subimageRect.size.height * 4);
  49. CGColorSpaceRef genericRGBColorspace = CGColorSpaceCreateDeviceRGB();
  50. CGContextRef imageContext = CGBitmapContextCreate(imageData, (size_t)subimageRect.size.width, (size_t)subimageRect.size.height, 8, (size_t)subimageRect.size.width * 4, genericRGBColorspace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast);
  51. CGContextDrawImage(imageContext, CGRectMake(0.0, 0.0, subimageRect.size.width, subimageRect.size.height), subimageSource);
  52. CGContextRelease(imageContext);
  53. CGColorSpaceRelease(genericRGBColorspace);
  54. }
  55. else
  56. {
  57. // Access the raw image bytes directly
  58. dataFromImageDataProvider = CGDataProviderCopyData(CGImageGetDataProvider(subimageSource));
  59. imageData = (GLubyte *)CFDataGetBytePtr(dataFromImageDataProvider);
  60. }
  61. runSynchronouslyOnVideoProcessingQueue(^{
  62. [GPUImageContext useImageProcessingContext];
  63. [outputFramebuffer disableReferenceCounting];
  64. glBindTexture(GL_TEXTURE_2D, [outputFramebuffer texture]);
  65. // no need to use self.outputTextureOptions here since pictures need this texture formats and type
  66. glTexSubImage2D(GL_TEXTURE_2D, 0, subRect.origin.x, subRect.origin.y, (GLint)subRect.size.width, subRect.size.height, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
  67. if (self.shouldSmoothlyScaleOutput)
  68. {
  69. glGenerateMipmap(GL_TEXTURE_2D);
  70. }
  71. glBindTexture(GL_TEXTURE_2D, 0);
  72. });
  73. if (shouldRedrawUsingCoreGraphics)
  74. {
  75. free(imageData);
  76. }
  77. else
  78. {
  79. CFRelease(dataFromImageDataProvider);
  80. }
  81. }
  82. @end