2017-04-27 11 views
7

도움이 필요한 특정 문제가 있습니다. 저는 복잡한 proteomics 데이터로 작업하고 있습니다. 우리의 플롯 중 하나는 원시 데이터의 히트 맵을 포함합니다. 이러한 히트 맵은 원시 이미지로 계산 한 다음 차트 캔버스에 맞게 크기를 조절합니다. 그런 식으로 제작 된 이미지 파일은 폭과 높이를 고려할 때 대개 매우 균형을 이룹니다. 일반적으로 이러한 이미지는 약 10 ~ 100 픽셀 너비와 5000 ~ 8000 픽셀 높이입니다 (이 크기는 이미지로 변환해야하는 원본 2D 데이터 배열의 크기입니다). 이후의 목표 해상도는 1300 x 600 픽셀입니다.C에서 크기가 크고 홀수 비율의 이미지 크기 조정

나는 일반적으로 위에서 설명한 차원이 일반적으로 잘 작동 목표 크기

public static Image Resize(Image img, int width, int height) { 
    Bitmap bmp = new Bitmap(width, height); 
    Graphics graphic = Graphics.FromImage((Image)bmp); 
    graphic.InterpolationMode = InterpolationMode.NearestNeighbor; 
    graphic.PixelOffsetMode = PixelOffsetMode.Half; 


    graphic.DrawImage(img, 0, 0, width, height); 
    graphic.Dispose(); 

    return (Image)bmp; 
} 

에 내 이미지 크기를 조정하기위한이 기능을 사용합니다. 하지만 이제는 6 x 54343 픽셀 크기의 새로운 데이터 세트가 생겼습니다. 이 이미지에서 동일한 코드를 사용하면 크기가 조정 된 이미지가 절반으로 비어 있습니다.

원본 이미지 : http://files.biognosys.ch/FileSharing/20170427_StackOverflow/raw.png

(원본 이미지가 너무 사용 제대로 대부분의 브라우저에서 표시되지 않습니다 "로 링크를 저장 ...")

는 (포토샵 사용) 보일 것입니다 방법

: http://files.biognosys.ch/FileSharing/20170427_StackOverflow/photoshop_resize.png 내가 마음에 보관하십시오 http://files.biognosys.ch/FileSharing/20170427_StackOverflow/code_resized.png

위 냈다 코드를 사용할 때

그것은 것으로 보인다 방법 이것은 몇 년 동안 6 x 8000의 이미지에서 문제없이 작동 했으므로 근본적으로 잘못된 것은 여기에 없습니다. 크기 조정을 위해 NearestNeighbor 보간법을 사용하는 것이 중요합니다. 따라서 "어떻게보아야합니까?"이미지가 나오지 않는 다른 보간법을 포함하는 솔루션은 나에게 유용하지 않습니다.

OLI

16 비트 윈도우 시대에서 일부 레거시 제한을 공격 한 것 같습니다
+0

크기 조정에 유용한 추가 설정이 있습니다. 나 자신에 대해 충분히 모르지만 [이] (http://stackoverflow.com/a/24199315/362432) 철저한 대답처럼 보인다 ... – Kempeth

+0

아니, 첫 번째 링크가 깨졌습니다. 하지만 대부분의 브라우저는 6 x 54343이므로 이미지를 표시하는 데 문제가 있습니다. "다른 이름으로 링크 저장"을 시도하십시오. –

+0

오, 아니요. 수정 구슬이 잘못되었습니다. 100 % dpi 설정. 또한, 다시. 그것은 6 x 8000으로 잘 작동했습니다. 그러나 문제가 되더라도 해결책이 필요합니다. 단순히 사용자들에게 DPI 설정을 변경해야한다고 말하면 안되며 그렇지 않으면 소프트웨어를 사용할 수 없습니다. –

답변

6

. 이를 해결하는 확실한 방법은 메모리 연산을 사용하여 소스 이미지를 더 작은 청크로 미리 분할하고 Graphics을 사용하여 크기 조정과 함께 모든 청크를 적용하는 것입니다. 이 방법은 소스 이미지가 Image이 아닌 Bitmap으로 가정합니다. 그러나이 값은 제한이없는 것 같습니다. resized image

그것은 당신의 photoshop_resize.png과 동일하지 않습니다하지만 code_resized.png

매우 유사 :

다음
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = true)] 
public static extern void CopyMemoryUnmanaged(IntPtr dest, IntPtr src, int count); 

// in case you can't use P/Invoke, copy via intermediate .Net buffer   
static void CopyMemoryNet(IntPtr dst, IntPtr src, int count) 
{ 
    byte[] buffer = new byte[count]; 
    Marshal.Copy(src, buffer, 0, count); 
    Marshal.Copy(buffer, 0, dst, count); 
} 

static Image CopyImagePart(Bitmap srcImg, int startH, int endH) 
{ 
    var width = srcImg.Width; 
    var height = endH - startH; 
    var srcBitmapData = srcImg.LockBits(new Rectangle(0, startH, width, height), ImageLockMode.ReadOnly, srcImg.PixelFormat); 

    var dstImg = new Bitmap(width, height, srcImg.PixelFormat); 
    var dstBitmapData = dstImg.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, srcImg.PixelFormat); 

    int bytesCount = Math.Abs(srcBitmapData.Stride) * height; 
    CopyMemoryUnmanaged(dstBitmapData.Scan0, srcBitmapData.Scan0, bytesCount); 
    // in case you can't use P/Invoke, copy via intermediate .Net buffer   
    //CopyMemoryNet(dstBitmapData.Scan0, srcBitmapData.Scan0, bytesCount); 

    srcImg.UnlockBits(srcBitmapData); 
    dstImg.UnlockBits(dstBitmapData); 

    return dstImg; 
} 


public static Image ResizeInParts(Bitmap srcBmp, int width, int height) 
{ 
    int srcStep = srcBmp.Height; 
    int dstStep = height; 
    while (srcStep > 30000) 
    { 
     srcStep /= 2; 
     dstStep /= 2; 
    } 

    var resBmp = new Bitmap(width, height); 
    using (Graphics graphic = Graphics.FromImage(resBmp)) 
    { 
     graphic.InterpolationMode = InterpolationMode.NearestNeighbor; 
     graphic.PixelOffsetMode = PixelOffsetMode.Half; 


     for (int srcTop = 0, dstTop = 0; srcTop < srcBmp.Height; srcTop += srcStep, dstTop += dstStep) 
     { 
      int srcBottom = srcTop + srcStep; 
      int dstH = dstStep; 
      if (srcBottom > srcBmp.Height) 
      { 
       srcBottom = srcBmp.Height; 
       dstH = height - dstTop; 
      } 
      using (var imgPart = CopyImagePart(srcBmp, srcTop, srcBottom)) 
      { 
       graphic.DrawImage(imgPart, 0, dstTop, width, dstH); 
      } 
     } 
    } 

    return resBmp; 
} 

내가 당신의 예제 이미지를 얻을 무엇인가 : 다음 코드의 스케치입니다 이 코드는 srcBmp.Height이 짝수가 아닌 경우와 같이 다른 "가장자리"(가장자리의 픽셀은 픽셀의 절반 만 사용하여 보간됩니다)와 같이 더 잘 처리 할 수 ​​있도록 개선 될 수 있습니다. 그러나이 작업은 쉽지 않습니다. 가정하면 원본 및 크기 조정 된 이미지의 "좋은"크기 또는 직접 보간 논리를 구현하십시오. 이 코드는 스케일링 요소를 고려할 때 이미 사용하기에 충분할 수 있습니다.

+1

내가 바라는 대답은 아니지만 그것이 16 비트 시대의 고유 한 문제라는 것을 아는 것이 적어도 그것을 설명합니다. 나는 당신이 코드 예제에 대해 매우 감사하고 있습니다. 물론 가장자리를 더 잘 표현하기 위해 덩어리 부분을 수행하지 않아도되지만 나중에 지금 가지고있는 것이 더 좋습니다. 고맙습니다. 당신은 여분의 점수를받을 자격이 있습니다. 한계가있는 곳을 아십니까? 그래서 절대적으로 필요하지 않다면 분할 작업을 수행 할 필요가 없습니다. –

+1

@HansPassant가 지적했듯이, 실제 한계는 약 2^15 정도, 즉 32767 또는 32768 정도 여야합니다. 제 코드에는 대략 30000 개가 있습니다 (안전한면에 있음). 또한 내가받은 대답의 수상이 성숙하지 않은 것인지 잘 모르겠습니다. 나는 기다리고 다른 대답을 들여다보기를 권합니다. 예를 들어, SimonMourier의 대답은 유망 해 보입니다 (시도하지 않았 음) – SergGr

+0

두 분에게 현상금에 보상을 드리고 싶습니다. 그러나 당신이 나에게 가장 적합한 해결책을 제공 한 이래로 :) –

2

다음은 작동하는 해결책입니다. Windows WIC ("Windows Imaging Component")을 기반으로합니다. Windows (및 WPF)가 모든 이미징 작업에 사용하는 기본 구성 요소입니다.

저는 작은 .NET interop 레이어를 제공했습니다. 모든 WIC 기능이있는 것은 아니지만 파일/스트림 이미지를로드/크기 조정/저장할 수 있습니다. Scale 메서드에는 GDI +와 비슷한 확장 옵션이 있습니다.

결과가 포토샵과 정확히 동일하지는 않지만 샘플은 정상적으로 작동하는 것 같습니다. 사용 방법은 다음과 같습니다.

using (var bmp = WicBitmapSource.Load("input.png")) 
{ 
    bmp.Scale(1357, 584, WicBitmapInterpolationMode.NearestNeighbor); 
    bmp.Save("output.png"); 
} 

... 

public enum WicBitmapInterpolationMode 
{ 
    NearestNeighbor = 0, 
    Linear = 1, 
    Cubic = 2, 
    Fant = 3, 
    HighQualityCubic = 4, 
} 

public sealed class WicBitmapSource : IDisposable 
{ 
    private IWICBitmapSource _source; 

    private WicBitmapSource(IWICBitmapSource source, Guid format) 
    { 
     _source = source; 
     Format = format; 
     Stats(); 
    } 

    public Guid Format { get; } 
    public int Width { get; private set; } 
    public int Height { get; private set; } 
    public double DpiX { get; private set; } 
    public double DpiY { get; private set; } 

    private void Stats() 
    { 
     if (_source == null) 
     { 
      Width = 0; 
      Height = 0; 
      DpiX = 0; 
      DpiY = 0; 
      return; 
     } 

     int w, h; 
     _source.GetSize(out w, out h); 
     Width = w; 
     Height = h; 

     double dpix, dpiy; 
     _source.GetResolution(out dpix, out dpiy); 
     DpiX = dpix; 
     DpiY = dpiy; 
    } 

    private void CheckDisposed() 
    { 
     if (_source == null) 
      throw new ObjectDisposedException(null); 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    ~WicBitmapSource() 
    { 
     Dispose(false); 
    } 

    private void Dispose(bool disposing) 
    { 
     if (_source != null) 
     { 
      Marshal.ReleaseComObject(_source); 
      _source = null; 
     } 
    } 

    public void Save(string filePath) 
    { 
     Save(filePath, Format, Guid.Empty); 
    } 

    public void Save(string filePath, Guid pixelFormat) 
    { 
     Save(filePath, Format, pixelFormat); 
    } 

    public void Save(string filePath, Guid encoderFormat, Guid pixelFormat) 
    { 
     if (filePath == null) 
      throw new ArgumentNullException(nameof(filePath)); 

     if (encoderFormat == Guid.Empty) 
     { 
      string ext = Path.GetExtension(filePath).ToLowerInvariant(); 
      // we support only png & jpg 
      if (ext == ".png") 
      { 
       encoderFormat = new Guid(0x1b7cfaf4, 0x713f, 0x473c, 0xbb, 0xcd, 0x61, 0x37, 0x42, 0x5f, 0xae, 0xaf); 
      } 
      else if (ext == ".jpeg" || ext == ".jpe" || ext == ".jpg" || ext == ".jfif" || ext == ".exif") 
      { 
       encoderFormat = new Guid(0x19e4a5aa, 0x5662, 0x4fc5, 0xa0, 0xc0, 0x17, 0x58, 0x02, 0x8e, 0x10, 0x57); 
      } 
     } 

     if (encoderFormat == Guid.Empty) 
      throw new ArgumentException(); 

     using (var file = File.OpenWrite(filePath)) 
     { 
      Save(file, encoderFormat, pixelFormat); 
     } 
    } 

    public void Save(Stream stream) 
    { 
     Save(stream, Format, Guid.Empty); 
    } 

    public void Save(Stream stream, Guid pixelFormat) 
    { 
     Save(stream, Format, pixelFormat); 
    } 

    public void Save(Stream stream, Guid encoderFormat, Guid pixelFormat) 
    { 
     if (stream == null) 
      throw new ArgumentNullException(nameof(stream)); 

     CheckDisposed(); 
     Save(_source, stream, encoderFormat, pixelFormat, WICBitmapEncoderCacheOption.WICBitmapEncoderNoCache, null); 
    } 

    public void Scale(int? width, int? height, WicBitmapInterpolationMode mode) 
    { 
     if (!width.HasValue && !height.HasValue) 
      throw new ArgumentException(); 

     int neww; 
     int newh; 
     if (width.HasValue && height.HasValue) 
     { 
      neww = width.Value; 
      newh = height.Value; 
     } 
     else 
     { 
      int w = Width; 
      int h = Height; 
      if (w == 0 || h == 0) 
       return; 

      if (width.HasValue) 
      { 
       neww = width.Value; 
       newh = (width.Value * h)/w; 
      } 
      else 
      { 
       newh = height.Value; 
       neww = (height.Value * w)/h; 
      } 
     } 

     if (neww <= 0 || newh <= 0) 
      throw new ArgumentException(); 

     CheckDisposed(); 
     _source = Scale(_source, neww, newh, mode); 
     Stats(); 
    } 

    // we support only 1-framed files (unlike TIF for example) 
    public static WicBitmapSource Load(string filePath) 
    { 
     if (filePath == null) 
      throw new ArgumentNullException(nameof(filePath)); 

     return LoadBitmapSource(filePath, 0, WICDecodeOptions.WICDecodeMetadataCacheOnDemand); 
    } 

    public static WicBitmapSource Load(Stream stream) 
    { 
     if (stream == null) 
      throw new ArgumentNullException(nameof(stream)); 

     return LoadBitmapSource(stream, 0, WICDecodeOptions.WICDecodeMetadataCacheOnDemand); 
    } 

    private static WicBitmapSource LoadBitmapSource(string filePath, int frameIndex, WICDecodeOptions metadataOptions) 
    { 
     var wfac = (IWICImagingFactory)new WICImagingFactory(); 
     IWICBitmapDecoder decoder = null; 
     try 
     { 
      decoder = wfac.CreateDecoderFromFilename(filePath, null, GenericAccessRights.GENERIC_READ, metadataOptions); 
      return new WicBitmapSource(decoder.GetFrame(frameIndex), decoder.GetContainerFormat()); 
     } 
     finally 
     { 
      Release(decoder); 
      Release(wfac); 
     } 
    } 

    private static WicBitmapSource LoadBitmapSource(Stream stream, int frameIndex, WICDecodeOptions metadataOptions) 
    { 
     var wfac = (IWICImagingFactory)new WICImagingFactory(); 
     IWICBitmapDecoder decoder = null; 
     try 
     { 
      decoder = wfac.CreateDecoderFromStream(new ManagedIStream(stream), null, metadataOptions); 
      return new WicBitmapSource(decoder.GetFrame(frameIndex), decoder.GetContainerFormat()); 
     } 
     finally 
     { 
      Release(decoder); 
      Release(wfac); 
     } 
    } 

    private static IWICBitmapScaler Scale(IWICBitmapSource source, int width, int height, WicBitmapInterpolationMode mode) 
    { 
     var wfac = (IWICImagingFactory)new WICImagingFactory(); 
     IWICBitmapScaler scaler = null; 
     try 
     { 
      scaler = wfac.CreateBitmapScaler(); 
      scaler.Initialize(source, width, height, mode); 
      Marshal.ReleaseComObject(source); 
      return scaler; 
     } 
     finally 
     { 
      Release(wfac); 
     } 
    } 

    private static void Save(IWICBitmapSource source, Stream stream, Guid containerFormat, Guid pixelFormat, WICBitmapEncoderCacheOption cacheOptions, WICRect rect) 
    { 
     var wfac = (IWICImagingFactory)new WICImagingFactory(); 
     IWICBitmapEncoder encoder = null; 
     IWICBitmapFrameEncode frame = null; 
     try 
     { 
      encoder = wfac.CreateEncoder(containerFormat, null); 
      encoder.Initialize(new ManagedIStream(stream), cacheOptions); 
      encoder.CreateNewFrame(out frame, IntPtr.Zero); 
      frame.Initialize(IntPtr.Zero); 

      if (pixelFormat != Guid.Empty) 
      { 
       frame.SetPixelFormat(pixelFormat); 
      } 

      frame.WriteSource(source, rect); 
      frame.Commit(); 
      encoder.Commit(); 
     } 
     finally 
     { 
      Release(frame); 
      Release(encoder); 
      Release(wfac); 
     } 
    } 

    private static void Release(object obj) 
    { 
     if (obj != null) 
     { 
      Marshal.ReleaseComObject(obj); 
     } 
    } 

    [ComImport] 
    [Guid("CACAF262-9370-4615-A13B-9F5539DA4C0A")] 
    private class WICImagingFactory 
    { 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    private class WICRect 
    { 
     public int X; 
     public int Y; 
     public int Width; 
     public int Height; 
    } 

    [Flags] 
    private enum WICDecodeOptions 
    { 
     WICDecodeMetadataCacheOnDemand = 0x0, 
     WICDecodeMetadataCacheOnLoad = 0x1, 
    } 

    [Flags] 
    private enum WICBitmapEncoderCacheOption 
    { 
     WICBitmapEncoderCacheInMemory = 0x0, 
     WICBitmapEncoderCacheTempFile = 0x1, 
     WICBitmapEncoderNoCache = 0x2, 
    } 

    [Flags] 
    private enum GenericAccessRights : uint 
    { 
     GENERIC_READ = 0x80000000, 
     GENERIC_WRITE = 0x40000000, 
     GENERIC_EXECUTE = 0x20000000, 
     GENERIC_ALL = 0x10000000, 

     GENERIC_READ_WRITE = GENERIC_READ | GENERIC_WRITE 
    } 

    [Guid("ec5ec8a9-c395-4314-9c77-54d7a935ff70"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    private interface IWICImagingFactory 
    { 
     IWICBitmapDecoder CreateDecoderFromFilename([MarshalAs(UnmanagedType.LPWStr)] string wzFilename, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] Guid[] pguidVendor, GenericAccessRights dwDesiredAccess, WICDecodeOptions metadataOptions); 
     IWICBitmapDecoder CreateDecoderFromStream(IStream pIStream, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] Guid[] pguidVendor, WICDecodeOptions metadataOptions); 

     void NotImpl2(); 
     void NotImpl3(); 
     void NotImpl4(); 

     IWICBitmapEncoder CreateEncoder([MarshalAs(UnmanagedType.LPStruct)] Guid guidContainerFormat, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] Guid[] pguidVendor); 

     void NotImpl6(); 
     void NotImpl7(); 

     IWICBitmapScaler CreateBitmapScaler(); 

     // not fully impl... 
    } 

    [Guid("00000120-a8f2-4877-ba0a-fd2b6645fb94"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    private interface IWICBitmapSource 
    { 
     void GetSize(out int puiWidth, out int puiHeight); 
     Guid GetPixelFormat(); 
     void GetResolution(out double pDpiX, out double pDpiY); 

     void NotImpl3(); 
     void NotImpl4(); 
    } 

    [Guid("00000302-a8f2-4877-ba0a-fd2b6645fb94"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    private interface IWICBitmapScaler : IWICBitmapSource 
    { 
     #region IWICBitmapSource 
     new void GetSize(out int puiWidth, out int puiHeight); 
     new Guid GetPixelFormat(); 
     new void GetResolution(out double pDpiX, out double pDpiY); 
     new void NotImpl3(); 
     new void NotImpl4(); 
     #endregion IWICBitmapSource 

     void Initialize(IWICBitmapSource pISource, int uiWidth, int uiHeight, WicBitmapInterpolationMode mode); 
    } 

    [Guid("9EDDE9E7-8DEE-47ea-99DF-E6FAF2ED44BF"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    private interface IWICBitmapDecoder 
    { 
     void NotImpl0(); 
     void NotImpl1(); 

     Guid GetContainerFormat(); 

     void NotImpl3(); 
     void NotImpl4(); 
     void NotImpl5(); 
     void NotImpl6(); 
     void NotImpl7(); 
     void NotImpl8(); 
     void NotImpl9(); 

     IWICBitmapFrameDecode GetFrame(int index); 
    } 

    [Guid("3B16811B-6A43-4ec9-A813-3D930C13B940"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    private interface IWICBitmapFrameDecode : IWICBitmapSource 
    { 
     // not fully impl... 
    } 

    [Guid("00000103-a8f2-4877-ba0a-fd2b6645fb94"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    private interface IWICBitmapEncoder 
    { 
     void Initialize(IStream pIStream, WICBitmapEncoderCacheOption cacheOption); 
     Guid GetContainerFormat(); 

     void NotImpl2(); 
     void NotImpl3(); 
     void NotImpl4(); 
     void NotImpl5(); 
     void NotImpl6(); 

     void CreateNewFrame(out IWICBitmapFrameEncode ppIFrameEncode, IntPtr encoderOptions); 
     void Commit(); 

     // not fully impl... 
    } 

    [Guid("00000105-a8f2-4877-ba0a-fd2b6645fb94"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    private interface IWICBitmapFrameEncode 
    { 
     void Initialize(IntPtr pIEncoderOptions); 
     void SetSize(int uiWidth, int uiHeight); 
     void SetResolution(double dpiX, double dpiY); 
     void SetPixelFormat([MarshalAs(UnmanagedType.LPStruct)] Guid pPixelFormat); 

     void NotImpl4(); 
     void NotImpl5(); 
     void NotImpl6(); 
     void NotImpl7(); 

     void WriteSource(IWICBitmapSource pIBitmapSource, WICRect prc); 
     void Commit(); 

     // not fully impl... 
    } 

    private class ManagedIStream : IStream 
    { 
     private Stream _stream; 

     public ManagedIStream(Stream stream) 
     { 
      _stream = stream; 
     } 

     public void Read(byte[] buffer, int count, IntPtr pRead) 
     { 
      int read = _stream.Read(buffer, 0, count); 
      if (pRead != IntPtr.Zero) 
      { 
       Marshal.WriteInt32(pRead, read); 
      } 
     } 

     public void Seek(long offset, int origin, IntPtr newPosition) 
     { 
      long pos = _stream.Seek(offset, (SeekOrigin)origin); 
      if (newPosition != IntPtr.Zero) 
      { 
       Marshal.WriteInt64(newPosition, pos); 
      } 
     } 

     public void SetSize(long newSize) 
     { 
      _stream.SetLength(newSize); 
     } 

     public void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG stg, int flags) 
     { 
      const int STGTY_STREAM = 2; 
      stg = new System.Runtime.InteropServices.ComTypes.STATSTG(); 
      stg.type = STGTY_STREAM; 
      stg.cbSize = _stream.Length; 
      stg.grfMode = 0; 

      if (_stream.CanRead && _stream.CanWrite) 
      { 
       const int STGM_READWRITE = 0x00000002; 
       stg.grfMode |= STGM_READWRITE; 
       return; 
      } 

      if (_stream.CanRead) 
      { 
       const int STGM_READ = 0x00000000; 
       stg.grfMode |= STGM_READ; 
       return; 
      } 

      if (_stream.CanWrite) 
      { 
       const int STGM_WRITE = 0x00000001; 
       stg.grfMode |= STGM_WRITE; 
       return; 
      } 

      throw new IOException(); 
     } 

     public void Write(byte[] buffer, int count, IntPtr written) 
     { 
      _stream.Write(buffer, 0, count); 
      if (written != IntPtr.Zero) 
      { 
       Marshal.WriteInt32(written, count); 
      } 
     } 

     public void Clone(out IStream ppstm) { throw new NotImplementedException(); } 
     public void Commit(int grfCommitFlags) { throw new NotImplementedException(); } 
     public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten) { throw new NotImplementedException(); } 
     public void LockRegion(long libOffset, long cb, int dwLockType) { throw new NotImplementedException(); } 
     public void Revert() { throw new NotImplementedException(); } 
     public void UnlockRegion(long libOffset, long cb, int dwLockType) { throw new NotImplementedException(); } 
    } 
}