2010-06-17 22 views
9

, ben belirlemek istiyorum benim programa görüntülerde getiriyorum gibi: bunlar alfa kanallı Alfa Kanalı bir Image Kullanılan eğer belirleyin

  • sahip

    1. o alfa-kanal ise

    # kullanılan 1Image.IsAlphaPixelFormat kullanılarak yeterince basittir. # 2 için, her bir pikselden döngü yapmak dışında, piksellerden en az birinin kullanılan bir alfa kanalı olup olmadığını belirleyebileceğim basit bir yol var mı (yani 255'dan başka bir değere ayarlanmış)? İhtiyacım olan tek şey bir boolean ve sonra 32-bit ya da 24-bit'e kaydedilip kaydedilmeyeceğine karar vereceğim.

    GÜNCELLEME: Ben ImageFlags.HasTranslucent ben aradığım bana sağlamak gerektiğini keşfettiler - maalesef, hiç çalışmaz. Örneğin, en az alfa kanalı 66 olan (yarı saydam) piksel biçimli PNG'ler, False bildirmeye devam eder (Kullanım: if((img.Flags & ImageFlags.HasTranslucent) == 4) ...;). Ben alfa değeri> 0 ve < 255 olan ve yine de False bildiren .bmp dahil olmak üzere tüm görüntü türleri üzerinde test ettik. Hiç kimse bunu kullanıp GDI + 'da çalışıp çalışmadığını bilen var mı?

  • +0

    Yardım etmeleri ziyade çevrimiçi versiyonu yerel kopyasına bağlantı oluşturduk. – ChrisF

    +0

    Yardım durumu "Piksel verilerinin 0 (saydam) ve 255 (opak) dışındaki alfa değerlerine sahip olduğunu belirtir."0 ile doğruyu söylemek istediğin gibi istediğin tam olarak değil. – ChrisF

    +0

    Garip, yerel bir yardım kopyasım yok. Her neyse, evet," HasTranslucent "beni çok uzak ama% 100 değil 0 değerlerine ihtiyacım var –

    cevap

    6

    Her pikselde dolaşmanız gerekmez (iyi olabilir, ancak görüntüye bağlıdır). tüm pikseller üzerinde döngü kurun, ancak 255 Aşağıdaki sözde kodu kullanın dışında bir alfa değeri bulmak zaman sadece döngünün patlak:

    bool hasAlpha = false; 
    foreach (var pixel in image) 
    { 
        hasAlpha = pixel.Alpha != 255; 
        if (hasAlpha) 
        { 
         break; 
        } 
    } 
    

    Yalnızca görüntüler için tüm pikselleri kontrol gerekecek alfa yok. Bu alfa sahip görüntüler için bu oldukça hızlı bir şekilde çıkacak.

    +0

    Teşekkürler ChrisF: Bunu yapmanın tek yolu olduğu ortaya çıkıyor. Soru başka bir çözümün gelip gelmediğini görmek için biraz daha beklemem gerekecek. –

    +0

    @Otaku - Ben Başka bir yolun olup olmadığını görmek için ilgileniyor olmalısın – ChrisF

    +0

    Yukarıdaki güncellemeyi kontrol et –

    5

    Ben ChrisF yanıta göre, daha gelişmiş bir çözüm olsun:

    public bool IsImageTransparent(Bitmap image,string optionalBgColorGhost) 
        { 
         for (int i = 0; i < image.Width; i++) 
         { 
          for (int j = 0; j < image.Height; j++) 
          { 
           var pixel = image.GetPixel(i, j); 
           if (pixel.A != 255) 
            return true; 
          } 
         } 
    
         //Check 4 corners to check if all of them are with the same color! 
         if (!string.IsNullOrEmpty(optionalBgColorGhost)) 
         { 
          if (image.GetPixel(0, 0).ToArgb() == GetColorFromString(optionalBgColorGhost).ToArgb()) 
          { 
           if (image.GetPixel(image.Width - 1, 0).ToArgb() == GetColorFromString(optionalBgColorGhost).ToArgb()) 
           { 
            if (image.GetPixel(0, image.Height - 1).ToArgb() == 
             GetColorFromString(optionalBgColorGhost).ToArgb()) 
            { 
             if (image.GetPixel(image.Width - 1, image.Height - 1).ToArgb() == 
              GetColorFromString(optionalBgColorGhost).ToArgb()) 
             { 
              return true; 
             } 
            } 
           } 
          } 
         } 
    
         return false; 
        } 
    
        public static Color GetColorFromString(string colorHex) 
        { 
         return ColorTranslator.FromHtml(colorHex); 
        } 
    

    Non şeffaf görüntülere bir isteğe bağlı bg renk dize vardır:

    IsImageTransparent(new Bitmap(myImg),"#FFFFFF"); 
    
    +0

    Ek kodun ne için yararlı olduğundan emin değilsiniz, ancak ... neden olmasın sadece Col olarak son argümanı ver veya Dize yerine nesne? Bu dizgeyi kodunuzda 5 kez ayrıştırdığınızdan değil, sadece bir kez yerine “Renk” tipi bir değişkende sakladığınızdan söz etmeyin. – Nyerguds

    3

    : kullanım

    Örnek Bundan daha iyi bir çözüm bulamazsanız, optimize etmek bana saatlerce sürdü:

    public bool IsAlphaBitmap(ref System.Drawing.Imaging.BitmapData BmpData) 
    { 
        byte[] Bytes = new byte[BmpData.Height * BmpData.Stride]; 
        Marshal.Copy(BmpData.Scan0, Bytes, 0, Bytes.Length); 
        for (p = 3; p < Bytes.Length; p += 4) { 
         if (Bytes[p] != 255) return true; 
        } 
        return false; 
    } 
    
    +0

    Oraya dikkat et. Bunu yapmak için piksel başına bit sayısını kontrol etmelisiniz. Bu sadece 32 bpp görüntüler için çalışır. – Nyerguds

    +1

    Bundan potansiyel olarak daha hızlı olan tek şey, 'güvensiz' ve işaretçiler aracılığıyla belleği kopyalamadan doğrudan çaprazlamak olacaktır. – IllidanS4

    +0

    @ IllidanS4 elbette, ve pratikte gitmek için yoldur. –

    2

    Farklı türdeki görüntüler için bir grup yöntemi bir araya getirdiğimde bu son yöntem bana, içine döktüğünüz herhangi bir görüntü için iyi bir iş gibi görünüyor; bu, potansiyel olarak saydam bir gif veya bir alfa kanalı içeren bir png olsun. Elmo'nun hızlı bayt okuma metodu için verdiği cevap sayesinde.

    Yan not: yapImage.IsAlphaPixelFormat(bitmap.PixelFormat)); paletli formatları alfa-yetenekli olarak görürken, bu sayede ,'un aslında şeffaflığa sahip olabilir. Sadece, 'alfa' türü değil. Böyle şeffaflık özellikli 8 bitlik görüntüler HasAlpha bayrağının etkin olmasına rağmen, bu hala kullanışlı bir kontroldür.

    public static Boolean HasTransparency(Bitmap bitmap) 
    { 
        // not an alpha-capable color format. 
        if ((bitmap.Flags & (Int32)ImageFlags.HasAlpha) == 0) 
         return false; 
        // Indexed formats. Special case because one index on their palette is configured as THE transparent color. 
        if (bitmap.PixelFormat == PixelFormat.Format8bppIndexed || bitmap.PixelFormat == PixelFormat.Format4bppIndexed) 
        { 
         ColorPalette pal = bitmap.Palette; 
         // Find the transparent index on the palette. 
         Int32 transCol = -1; 
         for (int i = 0; i < pal.Entries.Length; i++) 
         { 
          Color col = pal.Entries[i]; 
          if (col.A != 255) 
          { 
           // Color palettes should only have one index acting as transparency. Not sure if there's a better way of getting it... 
           transCol = i; 
           break; 
          } 
         } 
         // none of the entries in the palette have transparency information. 
         if (transCol == -1) 
          return false; 
         // Check pixels for existence of the transparent index. 
         Int32 colDepth = Image.GetPixelFormatSize(bitmap.PixelFormat); 
         BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); 
         Int32 stride = data.Stride; 
         Byte[] bytes = new Byte[bitmap.Height * stride]; 
         Marshal.Copy(data.Scan0, bytes, 0, bytes.Length); 
         bitmap.UnlockBits(data); 
         if (colDepth == 8) 
         { 
          // Last line index. 
          Int32 lineMax = bitmap.Width - 1; 
          for (Int32 i = 0; i < bytes.Length; i++) 
          { 
           // Last position to process. 
           Int32 linepos = i % stride; 
           // Passed last image byte of the line. Abort and go on with loop. 
           if (linepos > lineMax) 
            continue; 
           Byte b = bytes[i]; 
           if (b == transCol) 
            return true; 
          } 
         } 
         else if (colDepth == 4) 
         { 
          // line size in bytes. 1-indexed for the moment. 
          Int32 lineMax = bitmap.Width/2; 
          // Check if end of line ends on half a byte. 
          Boolean halfByte = bitmap.Width % 2 != 0; 
          // If it ends on half a byte, one more needs to be processed. 
          // We subtract in the other case instead, to make it 0-indexed right away. 
          if (!halfByte) 
           lineMax--; 
          for (Int32 i = 0; i < bytes.Length; i++) 
          { 
           // Last position to process. 
           Int32 linepos = i % stride; 
           // Passed last image byte of the line. Abort and go on with loop. 
           if (linepos > lineMax) 
            continue; 
           Byte b = bytes[i]; 
           if ((b & 0x0F) == transCol) 
            return true; 
           if (halfByte && linepos == lineMax) // reached last byte of the line. If only half a byte to check on that, abort and go on with loop. 
            continue; 
           if (((b & 0xF0) >> 4) == transCol) 
            return true; 
          } 
         } 
         return false; 
        } 
        if (bitmap.PixelFormat == PixelFormat.Format32bppArgb || bitmap.PixelFormat == PixelFormat.Format32bppPArgb) 
        { 
         BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); 
         Byte[] bytes = new Byte[bitmap.Height * data.Stride]; 
         Marshal.Copy(data.Scan0, bytes, 0, bytes.Length); 
         bitmap.UnlockBits(data); 
         for (Int32 p = 3; p < bytes.Length; p += 4) 
         { 
          if (bytes[p] != 255) 
           return true; 
         } 
         return false; 
        } 
        // Final "screw it all" method. This is pretty slow, but it won't ever be used, unless you 
        // encounter some really esoteric types not handled above, like 16bppArgb1555 and 64bppArgb. 
        for (Int32 i = 0; i < bitmap.Width; i++) 
        { 
         for (Int32 j = 0; j < bitmap.Height; j++) 
         { 
          if (bitmap.GetPixel(i, j).A != 255) 
           return true; 
         } 
        } 
        return false; 
    } 
    
    +0

    Boyanmış görüntüler için satır konumu hesaplamasında bir hata düzeltildi. – Nyerguds