private void FromStream(Stream stm, string filename) { Debug.Assert(stm != null); int bufferSize = _bufferSizeIncrement; if (stm.CanSeek) { bufferSize = (int)stm.Length + 1; // If this stream is seekable (most cases), we will only have one buffer alloc and read below // otherwise, we will incrementally grow the buffer and read until end of profile. // profiles are typcially small, so usually one allocation will suffice } byte[] rawBytes = new byte[bufferSize]; int numBytesRead = 0; while (bufferSize < _maximumColorContextLength) { numBytesRead += stm.Read(rawBytes, numBytesRead, bufferSize - numBytesRead); if (numBytesRead < bufferSize) { FromRawBytes(rawBytes, numBytesRead, /* dontThrowException = */ false); using (FactoryMaker factoryMaker = new FactoryMaker()) { HRESULT.Check(UnsafeNativeMethodsMilCoreApi.WICCodec.CreateColorContext(factoryMaker.ImagingFactoryPtr, out _colorContextHandle)); HRESULT.Check(IWICCC.InitializeFromMemory(_colorContextHandle, rawBytes, (uint)numBytesRead)); } return; } else { bufferSize += _bufferSizeIncrement; byte[] newRawBytes = new byte[bufferSize]; rawBytes.CopyTo(newRawBytes, 0); rawBytes = newRawBytes; } } throw new ArgumentException(SR.Get(SRID.ColorContext_FileTooLarge), filename); }
/// <summary> /// Create a ColorContext from an unmanaged color context /// </summary> private ColorContext(SafeMILHandle colorContextHandle) { _colorContextHandle = colorContextHandle; // // For 3.* backwards compat, we aren't going to HRESULT.Check() anywhere because // that could introduce new exceptions. If anything fails, _colorContextHelper // will be invalid and we'll emulate the old failure behavior later in // OpenProfileStream() // IWICCC.WICColorContextType type; if (HRESULT.Failed(IWICCC.GetType(_colorContextHandle, out type))) { return; } switch (type) { case IWICCC.WICColorContextType.WICColorContextProfile: uint cbProfileActual; int hr = IWICCC.GetProfileBytes(_colorContextHandle, 0, null, out cbProfileActual); if (HRESULT.Succeeded(hr) && cbProfileActual != 0) { byte[] profileData = new byte[cbProfileActual]; if (HRESULT.Failed(IWICCC.GetProfileBytes( _colorContextHandle, cbProfileActual, profileData, out cbProfileActual)) ) { return; } FromRawBytes(profileData, (int)cbProfileActual, /* dontThrowException = */ true); } break; case IWICCC.WICColorContextType.WICColorContextExifColorSpace: uint colorSpace; if (HRESULT.Failed(IWICCC.GetExifColorSpace(_colorContextHandle, out colorSpace))) { return; } // // From MSDN: // "1" is sRGB. We will use our built-in sRGB profile. // "2" is Adobe RGB. WIC says we should never see this because they are nonstandard and instead a // real profile will be returned. // "3-65534" is unused. // // From the Exif spec: // B. Tag Relating to Color Space // ColorSpace // // The color space information tag (ColorSpace) is always recorded as the color space specifier. // Normally sRGB (=1) is used to define the color space based on the PC monitor conditions and environment. If a // color space other than sRGB is used, Uncalibrated (=FFFF.H) is set. Image data recorded as Uncalibrated can be // treated as sRGB when it is converted to Flashpix. On sRGB see Annex E. // Tag = 40961 (A001.H) // Type = SHORT // Count = 1 // 1 = sRGB // FFFF.H = Uncalibrated // // So for 65535 we will return sRGB since it is acceptible rather than having an invalid ColorContext. The Exif // CC should always be the second one so the real one is given priority. Alternatively, we could ignore the // uncalibrated CC but that would be a breaking change with 3.* (returning 1 instead of 2). // // If anything other than 1 or 65535 happens, _colorContextHelper will remain invalid and we will emulate // the old crash behavior in OpenProfileStream(). // if (colorSpace == 1 || colorSpace == 65535) { ResourceManager resourceManager = new ResourceManager( _colorProfileResources, Assembly.GetAssembly(typeof(ColorContext)) ); byte[] sRGBProfile = (byte[])resourceManager.GetObject(_sRGBProfileName); // The existing ColorContext has already been initialized as Exif so we can't initialize it again // and instead must create a new one. using (FactoryMaker factoryMaker = new FactoryMaker()) { _colorContextHandle.Dispose(); _colorContextHandle = null; if (HRESULT.Failed(UnsafeNativeMethodsMilCoreApi.WICCodec.CreateColorContext( factoryMaker.ImagingFactoryPtr, out _colorContextHandle)) ) { return; } if (HRESULT.Failed(IWICCC.InitializeFromMemory( _colorContextHandle, sRGBProfile, (uint)sRGBProfile.Length)) ) { return; } } // Finally, fill in _colorContextHelper FromRawBytes(sRGBProfile, sRGBProfile.Length, /* dontThrowException = */ true); } else if (Invariant.Strict) { Invariant.Assert(false, String.Format(CultureInfo.InvariantCulture, "IWICColorContext::GetExifColorSpace returned {0}.", colorSpace)); } break; default: if (Invariant.Strict) { Invariant.Assert(false, "IWICColorContext::GetType() returned WICColorContextUninitialized."); } break; } // SECURITY NOTE: This constructor does not set a Uri because the profile comes from raw file // data. Thus, we don't set _isProfileUriNotFromUser to true because we // don't want get_ProfileUri to demand permission to return null. Debug.Assert(_profileUri.Value == null); }