2017-11-01 22 views
1

申し訳ありませんが、これは既にどこかで答えられていますが、見つけられませんでした。Xamarin iOS:UIImageピクセルの色をピクセル単位で変更する方法

基本的に、コード自体が黒で背景が白です(これはUIImageです)。白い背景の色を透明またはカスタムの色に変更し、QRコードの色を黒から白に変更したいと思います。

(XamarinのiOSで)私はすでに、次のコードを使用して、特定のピクセルの色を取得する方法を知っている:

static UIColor GetPixelColor(CGBitmapContext context, byte[] rawData, 
UIImage barcode, CGPoint pt) 
    { 
     var handle = GCHandle.Alloc(rawData); 
     UIColor resultColor = null; 
     using (context) 
     { 
      context.DrawImage(new CGRect(-pt.X, pt.Y - barcode.Size.Height, 
      barcode.Size.Width, barcode.Size.Height), barcode.CGImage); 
      float red = (rawData[0])/255.0f; 
      float green = (rawData[1])/255.0f; 
      float blue = (rawData[2])/255.0f; 
      float alpha = (rawData[3])/255.0f; 
      resultColor = UIColor.FromRGBA(red, green, blue, alpha); 
     } 

     return resultColor; 
    } 

これは、現在、私の関数である:

static UIImage GetRealQRCode(UIImage barcode) 
    { 
     int width = (int)barcode.Size.Width; 
     int height = (int)barcode.Size.Height; 
     var bytesPerPixel = 4; 
     var bytesPerRow = bytesPerPixel * width; 
     var bitsPerComponent = 8; 
     var colorSpace = CGColorSpace.CreateDeviceRGB(); 
     var rawData = new byte[bytesPerRow * height]; 

     CGBitmapContext context = new CGBitmapContext(rawData, width, 
     height, bitsPerComponent, bytesPerRow, colorSpace, 
     CGImageAlphaInfo.PremultipliedLast); 

     for (int i = 0; i < rawData.Length; i++) 
     { 
      for (int j = 0; j < bytesPerRow; j++) 
      { 
       CGPoint pt = new CGPoint(i, j); 
       UIColor currentColor = GetPixelColor(context, rawData, 
       barcode, pt); 
      } 
     } 
    } 

誰もがどのように知っていますこれを行う ? ありがとうございます!

答えて

2

そうでない場合は実際には個々のピクセルにアクセスする必要がありますが、最後の結果のみを表示するには、先に存在するフィルタを使用して、まず黒のピクセルをアルファマスクとして使用します。そうでなければ、Marshal.AllocHGlobalとポインタを使って私の他の答えを見てください。

using (var coreImage = new CIImage(ImageView1.Image)) 
using (var invertFilter = CIFilter.FromName("CIColorInvert")) 
{ 
    invertFilter.Image = coreImage; 
    using (var alphaMaskFiter = CIFilter.FromName("CIMaskToAlpha")) 
    { 
     alphaMaskFiter.Image = invertFilter.OutputImage; 
     var newCoreImage = alphaMaskFiter.OutputImage; 
     var uiimage = new UIImage(newCoreImage); 

     imageView2.Image = uiimage; // Do something with your new UIImage 
    } 
} 

プラス側は、これは、高速連射され;-)と結果は同じです。でも速く

enter image description here

あなたが必要な場合を処理しますが、これらの画像の数を変換するバッチと仮定これらの2つのフィルタを1つのカーネルに組み込んだカスタムCIKernelを書くことができます。

+0

まず、あなたの答えをsoooたくさんありがとう!私はすべての個々のピクセルにアクセスする必要はありません:あなたが言ったように、上記のコードを使用したいと思います。私の問題は、UIImageを直接受け取っていて、CGImageがベースになっているだけです(CIImageがヌルです)、CIImageとして自分のイメージがあるようにそれを隠す方法はありますか?再度、感謝します ! – Praestolatio

+0

@Praestolatio 'UIImage'(これには多くの異なるコンストラクタがあります)を渡して' CIImage'を作成することができます。 'var coreImage = new CIImage(aUIImageObject)); ' – SushiHangover

+0

あなたのソリューションにはコンストラクタが見当たりませんでした。私の問題はこのコード行から来ているようです:return ImageSource.FromStream(()=> theQRCode.AsPNG()。AsStream());ここで、QRコードはソリューションから返されたUIImageです。 CIImageをXamarinに変換できない可能性がありますか?ImageSourceから?もう一度ありがとうございます – Praestolatio

-1

Xamarin.IOSこの方法では、私のためにすべての色を透明に変換することができます.pngで動作する ".jpg"ファイルでのみ動作しますが、ファイルをjpgに変換してこのメ​​ソッドを呼び出すことができます。

public static UIImage ProcessImage (UIImage image) 
     { 
      CGImage rawImageRef = image.CGImage; 
      nfloat[] colorMasking = new nfloat[6] { 222, 255, 222, 255, 222, 255 }; 
      CGImage imageRef = rawImageRef.WithMaskingColors(colorMasking); 
      UIImage imageB = UIImage.FromImage(imageRef); 
      return imageB; 
     } 

よろしくごUIImageCGImage(とないCIImage)に裏打ちされたと仮定すると

enter image description here

3

var cgImage = ImageView1.Image.CGImage; // Your UIImage with a CGImage backing image 

var bytesPerPixel = 4; 
var bitsPerComponent = 8; 
var bytesPerUInt32 = sizeof(UInt32)/sizeof(byte); 

var width = cgImage.Width; 
var height = cgImage.Height; 

var bytesPerRow = bytesPerPixel * cgImage.Width; 
var numOfBytes = cgImage.Height * cgImage.Width * bytesPerUInt32; 

IntPtr pixelPtr = IntPtr.Zero; 
try 
{ 
    pixelPtr = Marshal.AllocHGlobal((int)numOfBytes); 

    using (var colorSpace = CGColorSpace.CreateDeviceRGB()) 
    { 
     CGImage newCGImage; 
     using (var context = new CGBitmapContext(pixelPtr, width, height, bitsPerComponent, bytesPerRow, colorSpace, CGImageAlphaInfo.PremultipliedLast)) 
     { 
      context.DrawImage(new CGRect(0, 0, width, height), cgImage); 
      unsafe 
      { 
       var currentPixel = (byte*)pixelPtr.ToPointer(); 
       for (int i = 0; i < height; i++) 
       { 
        for (int j = 0; j < width; j++) 
        { 
         // RGBA8888 pixel format 
         if (*currentPixel == byte.MinValue) 
         { 
          *currentPixel = byte.MaxValue; 
          *(currentPixel + 1) = byte.MaxValue; 
          *(currentPixel + 2) = byte.MaxValue; 
         } 
         else 
         { 
          *currentPixel = byte.MinValue; 
          *(currentPixel + 1) = byte.MinValue; 
          *(currentPixel + 2) = byte.MinValue; 
          *(currentPixel + 3) = byte.MinValue; 
         } 
         currentPixel += 4; 
        } 
       } 
      } 
      newCGImage = context.ToImage(); 
     } 
     var uiimage = new UIImage(newCGImage); 

     imageView2.Image = uiimage; // Do something with your new UIImage 
    } 
} 
finally 
{ 
    if (pixelPtr != IntPtr.Zero) 
     Marshal.FreeHGlobal(pixelPtr); 
} 

enter image description here

+0

私はアルゴリズムを実装しようとしていますが、特定のピクセルの色を変更しようとしています。 * byte.MinValue *と* byte.MaxValue *について説明できますか?コードは600 * 600のPNG画像では非常に遅いようです – OrcusZ

+0

@OrcusZ byte.MinValue | MaxValueは静的に定義された定数です(0 | 255)。 'byte'型です。 600x600はマネージコードでアクセスされている360,000のRGBA8888の値なので、GPU CIKernel、CまたはASMで処理するのと同じくらい速く進んでいるわけではありません。 – SushiHangover

+0

@OrcusZ単色を変更するだけで、 CoreImage CIFilterがより高速になります。 – SushiHangover

関連する問題