2011-07-12 23 views

答えて

39

私は自分のプロジェクトから関連するソースコードを持っているので、CPU上でのピクセル操作に落とす必要がある場合は、次のプレゼンテーションを追加する必要がありますトリック:

@implementation UIImage (NegativeImage) 

- (UIImage *)negativeImage 
{ 
    // get width and height as integers, since we'll be using them as 
    // array subscripts, etc, and this'll save a whole lot of casting 
    CGSize size = self.size; 
    int width = size.width; 
    int height = size.height; 

    // Create a suitable RGB+alpha bitmap context in BGRA colour space 
    CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); 
    unsigned char *memoryPool = (unsigned char *)calloc(width*height*4, 1); 
    CGContextRef context = CGBitmapContextCreate(memoryPool, width, height, 8, width * 4, colourSpace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast); 
    CGColorSpaceRelease(colourSpace); 

    // draw the current image to the newly created context 
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), [self CGImage]); 

    // run through every pixel, a scan line at a time... 
    for(int y = 0; y < height; y++) 
    { 
     // get a pointer to the start of this scan line 
     unsigned char *linePointer = &memoryPool[y * width * 4]; 

     // step through the pixels one by one... 
     for(int x = 0; x < width; x++) 
     { 
      // get RGB values. We're dealing with premultiplied alpha 
      // here, so we need to divide by the alpha channel (if it 
      // isn't zero, of course) to get uninflected RGB. We 
      // multiply by 255 to keep precision while still using 
      // integers 
      int r, g, b; 
      if(linePointer[3]) 
      { 
       r = linePointer[0] * 255/linePointer[3]; 
       g = linePointer[1] * 255/linePointer[3]; 
       b = linePointer[2] * 255/linePointer[3]; 
      } 
      else 
       r = g = b = 0; 

      // perform the colour inversion 
      r = 255 - r; 
      g = 255 - g; 
      b = 255 - b; 

      // multiply by alpha again, divide by 255 to undo the 
      // scaling before, store the new values and advance 
      // the pointer we're reading pixel data from 
      linePointer[0] = r * linePointer[3]/255; 
      linePointer[1] = g * linePointer[3]/255; 
      linePointer[2] = b * linePointer[3]/255; 
      linePointer += 4; 
     } 
    } 

    // get a CG image from the context, wrap that into a 
    // UIImage 
    CGImageRef cgImage = CGBitmapContextCreateImage(context); 
    UIImage *returnImage = [UIImage imageWithCGImage:cgImage]; 

    // clean up 
    CGImageRelease(cgImage); 
    CGContextRelease(context); 
    free(memoryPool); 

    // and return 
    return returnImage; 
} 

@end 

は、だから、そのUIImageするカテゴリのメソッドを追加します。

  1. はそれが
  2. のメモリにアクセスすることができる明確なCoreGraphicsビットマップコンテキストを作成し、それにUIImageを描く
  3. 全ての画素を通る、インフレクションRGBにあらかじめ乗算アルファからの変換、個別チャネルを反転、再びアルファで乗算し、格納バック
  4. コンテキストから画像を取得し、UIImage
  5. にそれをラップ自体後にクリーンアップし、 UIImageを返す
+0

よく見える、私はそれを試してみよう – Brodie

+0

素晴らしい、ありがとう – Brodie

+0

このコードを提供していただきありがとうございます。このコードを網膜デバイスでどのように使用するには?例えば(retinaScale> 0.0){ } else { UIGraphicsBeginImageContext(image.size); } – elprl

4

もちろん、「差分」ブレンドモード(kCGBlendModeDifference)を使用している可能性があります。イメージ処理を設定するコードの概要については、this questionを参照してください。イメージを下(ベース)イメージとして使用し、その上に純粋な白いビットマップを描画します。

CGImageRefを取得してビットマップコンテキストに描画し、ビットマップコンテキストのピクセルをループすることで、ピクセル単位の操作を手動で行うこともできます。

+1

@ Tommyの答えを置き換えるコードを入力してください(これは私が今使用しています)。 –

+0

素晴らしい、素晴らしい解決策。 – sabiland

3

Tommyの答えは答えですが、私はそれが大きな画像のために本当に激しく時間のかかる作業であることを指摘したいと思います。そこ画像を操作であなたを助けることができる2つのフレームワーク:

  1. CoreImage
  2. アクセラレータ

    とブラッドラーソン、GPUImageから素晴らしいGPUImageフレームワークは、ルーチンが独自のフラグメントを使用してGPU上で実行可能に言及することは本当に価値がありますOpenGlES 2.0環境でのシェーダの大幅な高速化CoreImgeを使用すると、負のフィルタが使用可能な場合、CPUまたはGPUを選択できます。アクセラレータを使用すると、CPUで実行されるすべてのルーチンがベクトル演算処理を使用します。 CoreImageで
+0

@ Tommyの答えを置き換えるコードを提供してください(私は今使っています)。 –

+0

https://developer.apple.com/library/mac/documentation/graphicsimaging/Conceptual/CoreImaging/ci_intro/ci_intro.htmlこちらから確認してください。https://developer.apple.com/library/ios/ documentation/Performance/Conceptual/vImage/Introduction/Introduction.html#// apple_ref/doc/uid/TP30001001を参照してください。アップルサイトでは、いくつかのサンプルを見つけることもできます – Andrea

19

:ちょうどこれを行うには迅速な拡張機能を作成し

#import <CoreImage/CoreImage.h> 

@implementation UIImage (ColorInverse) 

+ (UIImage *)inverseColor:(UIImage *)image { 
    CIImage *coreImage = [CIImage imageWithCGImage:image.CGImage]; 
    CIFilter *filter = [CIFilter filterWithName:@"CIColorInvert"]; 
    [filter setValue:coreImage forKey:kCIInputImageKey]; 
    CIImage *result = [filter valueForKey:kCIOutputImageKey]; 
    return [UIImage imageWithCIImage:result]; 
} 

@end 
+3

最後の行は次のようになるでしょう: [UIImage imageWithCIImage:result scale:image.scale orientation:image.imageOrientation]; であり、元の画像の縮尺や向きが保持されます。 – prewett

3

extension UIImage { 
    func inverseImage(cgResult: Bool) -> UIImage? { 
     let coreImage = UIKit.CIImage(image: self) 
     guard let filter = CIFilter(name: "CIColorInvert") else { return nil } 
     filter.setValue(coreImage, forKey: kCIInputImageKey) 
     guard let result = filter.valueForKey(kCIOutputImageKey) as? UIKit.CIImage else { return nil } 
     if cgResult { // I've found that UIImage's that are based on CIImages don't work with a lot of calls properly 
      return UIImage(CGImage: CIContext(options: nil).createCGImage(result, fromRect: result.extent)) 
     } 
     return UIImage(CIImage: result) 
    } 
} 
+0

Swift 3に更新してください。thx –

0

スウィフト3更新:(@BadPirate回答からCIImageベースUIImagesは(ほとんどの図書館はCGImageが設定されていると仮定)打破するためにも、私は修正CIImageに基づいてUIImageを返すためのオプションを追加しました)

関連する問題