2014-11-28 5 views
0

참고 : 이전 질문의 배경을 다시 한 번 표시하면 모든 관련 자료를 한 곳에서 찾을 수 있습니다.이미지 데이터를 반전 한 후에도 광도계 해석 태그 문제가 발생합니다.

Android 휴대 기기에서 이미지를 캡쳐하고 있으며 JPEG 형식입니다. 이미지는 72X72DPI이고 24 비트입니다. LibTiff.Net을 사용하여이 JPEG 이미지를 TIFF로 변환하고 MinIsWhite에 대한 Photometric Interpretation = 0 태그를 설정하려고하면 이미지가 음수로 바뀝니다 (흰색이 검은 색이되고 검은 색이 흰색이됩니다). 환경은 Windows 8.1 64 비트, Visual Studio 2012입니다. 태그 값은 0이어야합니다. 0 = 흰색은 0입니다.

이미지에 반드시 Photometric.MINISWHITE를 사용해야하므로 아래 코드에 따라 TIFF에 쓰기 전에 이미지 데이터를 반전시켜 보았습니다. 그런 다음 압축이 CCITT4 대신 LZW로 변경되고 광도가 MINISWHITE에서 MINISBLACK으로 변경되고 FIllorder 태그가 제거되고 PlanarConfig 태그가 제거되며 새 태그 예측기에 값 1이 추가되고 이미지가 다시 음수로 바뀝니다.

public partial class Form1 : Form 
    { 
     private const TiffTag TIFFTAG_ASCIITAG = (TiffTag)666; 
     private const TiffTag TIFFTAG_LONGTAG = (TiffTag)667; 
     private const TiffTag TIFFTAG_SHORTTAG = (TiffTag)668; 
     private const TiffTag TIFFTAG_RATIONALTAG = (TiffTag)669; 
     private const TiffTag TIFFTAG_FLOATTAG = (TiffTag)670; 
     private const TiffTag TIFFTAG_DOUBLETAG = (TiffTag)671; 
     private const TiffTag TIFFTAG_BYTETAG = (TiffTag)672; 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      using (Bitmap bmp = new Bitmap(@"D:\Projects\ITests\images\IMG_2.jpg")) 
      { 
       // convert jpg image to tiff 
       byte[] tiffBytes = GetTiffImageBytes(bmp, false); 
       File.WriteAllBytes(@"D:\Projects\ITests\images\output.tif", tiffBytes); 

       //Invert the tiff image 
       Bitmap bmpTiff = new Bitmap(@"D:\Projects\ITests\images\output.tif"); 
       Bitmap FBitmap = Transform(bmpTiff); 
       FBitmap.Save(@"D:\Projects\ITests\images\invOutput1.tif"); 

      } 
     } 

     public static byte[] GetTiffImageBytes(Bitmap img, bool byScanlines) 
     { 
      try 
      { 
       byte[] raster = GetImageRasterBytes(img); 

       using (MemoryStream ms = new MemoryStream()) 
       { 
        using (Tiff tif = Tiff.ClientOpen("InMemory", "w", ms, new TiffStream())) 
        { 
         if (tif == null) 
          return null; 

         tif.SetField(TiffTag.IMAGEWIDTH, img.Width); 
         tif.SetField(TiffTag.IMAGELENGTH, img.Height); 
         tif.SetField(TiffTag.COMPRESSION, Compression.CCITTFAX4); 
         tif.SetField(TiffTag.PHOTOMETRIC, Photometric.MINISWHITE); 
         tif.SetField(TiffTag.ROWSPERSTRIP, img.Height); 
         tif.SetField(TiffTag.XRESOLUTION, 200); 
         tif.SetField(TiffTag.YRESOLUTION, 200); 
         tif.SetField(TiffTag.SUBFILETYPE, 0); 
         tif.SetField(TiffTag.BITSPERSAMPLE, 1); 
         tif.SetField(TiffTag.FILLORDER, FillOrder.LSB2MSB); 
         tif.SetField(TiffTag.ORIENTATION, BitMiracle.LibTiff.Classic.Orientation.TOPLEFT); 
         tif.SetField(TiffTag.SAMPLESPERPIXEL, 1); 
         tif.SetField(TiffTag.RESOLUTIONUNIT, ResUnit.INCH); 
         tif.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG); 
         int tiffStride = tif.ScanlineSize(); 
         int stride = raster.Length/img.Height; 
         if (byScanlines) 
         { 
          // raster stride MAY be bigger than TIFF stride (due to padding in raster bits) 
          for (int i = 0, offset = 0; i < img.Height; i++) 
          { 
           bool res = tif.WriteScanline(raster, offset, i, 0); 
           if (!res) 
            return null; 

           offset += stride; 
          } 
         } 
         else 
         { 
          if (tiffStride < stride) 
          { 
           // raster stride is bigger than TIFF stride 
           // this is due to padding in raster bits 
           // we need to create correct TIFF strip and write it into TIFF 
           byte[] stripBits = new byte[tiffStride * img.Height]; 
           for (int i = 0, rasterPos = 0, stripPos = 0; i < img.Height; i++) 
           { 
            System.Buffer.BlockCopy(raster, rasterPos, stripBits, stripPos, tiffStride); 
            rasterPos += stride; 
            stripPos += tiffStride; 
           } 

           // Write the information to the file 
           int n = tif.WriteEncodedStrip(0, stripBits, stripBits.Length); 
           if (n <= 0) 
            return null; 
          } 
          else 
          { 
           // Write the information to the file 
           int n = tif.WriteEncodedStrip(0, raster, raster.Length); 
           if (n <= 0) 
            return null; 
          } 
         } 
        } 

        return ms.GetBuffer(); 
       } 
      } 
      catch (Exception) 
      { 
       return null; 
      } 
     } 

     public static byte[] GetImageRasterBytes(Bitmap img) 
     { 
      // Specify full image 
      Rectangle rect = new Rectangle(0, 0, img.Width, img.Height); 

      Bitmap bmp = img; 
      byte[] bits = null; 

      try 
      { 
       // Lock the managed memory 
       if (img.PixelFormat != PixelFormat.Format1bppIndexed) 
        bmp = convertToBitonal(img); 

       BitmapData bmpdata = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format1bppIndexed); 

       // Declare an array to hold the bytes of the bitmap. 
       bits = new byte[bmpdata.Stride * bmpdata.Height]; 

       // Copy the sample values into the array. 
       Marshal.Copy(bmpdata.Scan0, bits, 0, bits.Length); 

       // Release managed memory 
       bmp.UnlockBits(bmpdata); 
      } 
      finally 
      { 
       if (bmp != img) 
        bmp.Dispose(); 
      } 

      return bits; 
     } 

     private static Bitmap convertToBitonal(Bitmap original) 
     { 
      int sourceStride; 
      byte[] sourceBuffer = extractBytes(original, out sourceStride); 

      // Create destination bitmap 
      Bitmap destination = new Bitmap(original.Width, original.Height, 
       PixelFormat.Format1bppIndexed); 

      destination.SetResolution(original.HorizontalResolution, original.VerticalResolution); 

      // Lock destination bitmap in memory 
      BitmapData destinationData = destination.LockBits(
       new Rectangle(0, 0, destination.Width, destination.Height), 
       ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed); 

      // Create buffer for destination bitmap bits 
      int imageSize = destinationData.Stride * destinationData.Height; 
      byte[] destinationBuffer = new byte[imageSize]; 

      int sourceIndex = 0; 
      int destinationIndex = 0; 
      int pixelTotal = 0; 
      byte destinationValue = 0; 
      int pixelValue = 128; 
      int height = destination.Height; 
      int width = destination.Width; 
      int threshold = 500; 

      for (int y = 0; y < height; y++) 
      { 
       sourceIndex = y * sourceStride; 
       destinationIndex = y * destinationData.Stride; 
       destinationValue = 0; 
       pixelValue = 128; 

       for (int x = 0; x < width; x++) 
       { 
        // Compute pixel brightness (i.e. total of Red, Green, and Blue values) 
        pixelTotal = sourceBuffer[sourceIndex + 1] + sourceBuffer[sourceIndex + 2] + 
         sourceBuffer[sourceIndex + 3]; 

        if (pixelTotal > threshold) 
         destinationValue += (byte)pixelValue; 

        if (pixelValue == 1) 
        { 
         destinationBuffer[destinationIndex] = destinationValue; 
         destinationIndex++; 
         destinationValue = 0; 
         pixelValue = 128; 
        } 
        else 
        { 
         pixelValue >>= 1; 
        } 

        sourceIndex += 4; 
       } 

       if (pixelValue != 128) 
        destinationBuffer[destinationIndex] = destinationValue; 
      } 

      Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize); 
      destination.UnlockBits(destinationData); 
      return destination; 
     } 

     private static byte[] extractBytes(Bitmap original, out int stride) 
     { 
      Bitmap source = null; 

      try 
      { 
       // If original bitmap is not already in 32 BPP, ARGB format, then convert 
       if (original.PixelFormat != PixelFormat.Format32bppArgb) 
       { 
        source = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb); 
        source.SetResolution(original.HorizontalResolution, original.VerticalResolution); 
        using (Graphics g = Graphics.FromImage(source)) 
        { 
         g.DrawImageUnscaled(original, 0, 0); 
        } 
       } 
       else 
       { 
        source = original; 
       } 

       // Lock source bitmap in memory 
       BitmapData sourceData = source.LockBits(
        new Rectangle(0, 0, source.Width, source.Height), 
        ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 

       // Copy image data to binary array 
       int imageSize = sourceData.Stride * sourceData.Height; 
       byte[] sourceBuffer = new byte[imageSize]; 
       Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize); 

       // Unlock source bitmap 
       source.UnlockBits(sourceData); 
       stride = sourceData.Stride; 
       return sourceBuffer; 
      } 
      finally 
      { 
       if (source != original) 
        source.Dispose(); 
      } 

     } 

     public Bitmap Transform(Bitmap bitmapImage) 
     { 
      var bitmapRead = bitmapImage.LockBits(new Rectangle(0, 0, bitmapImage.Width, bitmapImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppPArgb); 
      var bitmapLength = bitmapRead.Stride * bitmapRead.Height; 
      var bitmapBGRA = new byte[bitmapLength]; 
      Marshal.Copy(bitmapRead.Scan0, bitmapBGRA, 0, bitmapLength); 
      bitmapImage.UnlockBits(bitmapRead); 
      for (int i = 0; i < bitmapLength; i += 4) 
      { 
       bitmapBGRA[i] = (byte)(255 - bitmapBGRA[i]); 
       bitmapBGRA[i + 1] = (byte)(255 - bitmapBGRA[i + 1]); 
       bitmapBGRA[i + 2] = (byte)(255 - bitmapBGRA[i + 2]); 
       //  [i + 3] = ALPHA. 
      } 

      var bitmapWrite = bitmapImage.LockBits(new Rectangle(0, 0, bitmapImage.Width, bitmapImage.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppPArgb); 
      Marshal.Copy(bitmapBGRA, 0, bitmapWrite.Scan0, bitmapLength); 
      bitmapImage.UnlockBits(bitmapWrite); 

      return bitmapImage; 
     } 
    } 

답변

0

TIFF에 쓰기 전에 GetTiffImageBytes 방법으로 이미지 바이트를 반전해야합니다. 또한 Transform 메서드는 이중 수준 이미지를 32bpp로 변환하므로 결국 LZW 압축 이미지를 얻습니다.

그래서, GetTiffImageBytes 방법에 byte[] raster = GetImageRasterBytes(img); 뒤에 다음 코드

for (int k = 0; k < raster.Length; k++) 
    raster[k] = (byte)(~raster[k]); 

를 추가합니다. 이렇게하면 이미지 바이트가 반전됩니다. 다음 코드를 사용하지 마십시오.

//Invert the tiff image 
Bitmap bmpTiff = new Bitmap(@"D:\Projects\ITests\images\output.tif"); 
Bitmap FBitmap = Transform(bmpTiff); 
FBitmap.Save(@"D:\Projects\ITests\images\invOutput1.tif"); 
+0

당신은 나의 슈퍼 스타 Bobrovsky입니다! 그것은 필요한만큼 정확히 작동했습니다. 적시에 도움을 주셔서 감사합니다. 건배! – Harshoo