public void CopyPixels(WICRect prc, uint cbStride, uint cbBufferSize, IntPtr pbBuffer) { int cbLine = (prc.Width * Format.BitsPerPixel + 7) / 8; if (prc.X < 0 || prc.Y < 0 || prc.Width < 0 || prc.Height < 0 || prc.X + prc.Width > (int)Width || prc.Y + prc.Height > (int)Height) { throw new ArgumentOutOfRangeException(nameof(prc), "Requested area does not fall within the image bounds"); } if (cbLine > (int)cbStride) { throw new ArgumentOutOfRangeException(nameof(cbStride), "Stride is too small for the requested area"); } if ((prc.Height - 1) * (int)cbStride + cbLine > (int)cbBufferSize) { throw new ArgumentOutOfRangeException(nameof(cbBufferSize), "Buffer is to small for the requested area"); } if (pbBuffer == IntPtr.Zero) { throw new ArgumentOutOfRangeException(nameof(pbBuffer), "Buffer pointer is invalid"); } Timer.Restart(); CopyPixelsInternal(prc, cbStride, cbBufferSize, pbBuffer); Timer.Stop(); var stats = Stats; stats.CallCount++; stats.PixelCount += prc.Width * prc.Height; stats.ProcessingTime += (double)Timer.ElapsedTicks / Stopwatch.Frequency * 1000; }
public WicPlanarCacheSource(IWICPlanarBitmapSourceTransform source, WICBitmapPlaneDescription descY, WICBitmapPlaneDescription descC, WICRect crop, WICBitmapTransformOptions transformOptions, uint width, uint height, double ratio) { // TODO fractional ratio support? subsampleRatioX = Math.Ceiling((double)descY.Width / descC.Width); subsampleRatioY = Math.Ceiling((double)descY.Height / descC.Height); var scrop = new WICRect(); scrop.X = (int)Math.Floor(crop.X / ratio); scrop.Y = (int)Math.Floor(crop.Y / ratio); scrop.Width = Math.Min((int)Math.Ceiling(crop.Width / ratio), (int)descY.Width); scrop.Height = Math.Min((int)Math.Ceiling(crop.Height / ratio), (int)descY.Height); if (subsampleRatioX > 1d) { descC.Width = Math.Min((uint)Math.Ceiling(scrop.Width / subsampleRatioX), descC.Width); descY.Width = (uint)Math.Min(descC.Width * subsampleRatioX, scrop.Width); if (scrop.X % subsampleRatioX > 0) { scrop.X = (int)(scrop.X / subsampleRatioX) * (int)subsampleRatioX; } } else { descC.Width = descY.Width = (uint)scrop.Width; } if (subsampleRatioY > 1d) { descC.Height = Math.Min((uint)Math.Ceiling(scrop.Height / subsampleRatioY), descC.Height); descY.Height = (uint)Math.Min(descC.Height * subsampleRatioY, scrop.Height); if (scrop.Y % subsampleRatioY > 0) { scrop.Y = (int)(scrop.Y / subsampleRatioY) * (int)subsampleRatioY; } } else { descC.Height = descY.Height = (uint)scrop.Height; } sourceTransform = source; sourceTransformOptions = transformOptions; planeDescriptionY = descY; planeDescriptionC = descC; scaledCrop = scrop; scaledWidth = width; scaledHeight = height; strideY = (uint)scrop.Width + 3u & ~3u; buffHeightY = 16u; strideC = (uint)(Math.Ceiling(scrop.Width / subsampleRatioX)) * 2u + 3u & ~3u; buffHeightC = (uint)(buffHeightY / subsampleRatioY); sourceY = new WicPlanarSource(this, WicPlane.Luma, descY); sourceC = new WicPlanarSource(this, WicPlane.Chroma, descC); }
public unsafe void CopyPixels <T>(WICRect rectangle, int stride, T[] data) where T : struct { Guard.MustBeGreaterThan(stride, 0, "Stride must be greather than 0"); Guard.NotNullOrEmpty(data, nameof(data)); CopyPixels(new IntPtr(&rectangle), stride, data.Length, (IntPtr)Unsafe.AsPointer(ref data[0])); }
public unsafe void CopyPixels(WICRect rectangle, int stride, int size, IntPtr data) { Guard.MustBeGreaterThan(size, 0, "Size must be greather than 0"); Guard.MustBeGreaterThan(stride, 0, "Stride must be greather than 0"); CopyPixels(new IntPtr(&rectangle), stride, size, data); }
unsafe public override void CopyPixels(WICRect prc, uint cbStride, uint cbBufferSize, IntPtr pbBuffer) { fixed(byte *bstart = LineBuff) fixed(ushort *igtstart = LookupTables.InverseGamma, atstart = LookupTables.Alpha) { int oh = prc.Height, oy = prc.Y; prc.Height = 1; for (int y = 0; y < oh; y++) { prc.Y = oy + y; Source.CopyPixels(prc, Stride, Stride, (IntPtr)bstart); ushort *op = (ushort *)pbBuffer + y * cbStride; if (HasAlpha) { mapValuesWithAlpha(bstart, op, igtstart, atstart, (uint)prc.Width * Bpp); } else { mapValues(bstart, op, igtstart, (uint)prc.Width * Bpp); } } } }
unsafe public void CopyPixels(WicPlane plane, WICRect prc, uint cbStride, uint cbBufferSize, IntPtr pbBuffer) { if (lineBuffY.Array == null || (plane == WicPlane.Luma && prc.Y + prc.Height > loadedY) || (plane == WicPlane.Chroma && prc.Y + prc.Height > loadedC)) { loadBuffer(plane, prc); } switch (plane) { case WicPlane.Luma: fixed(byte *pBuffY = lineBuffY.Array) for (int y = 0; y < prc.Height; y++) { Buffer.MemoryCopy(pBuffY + (prc.Y - startY) * strideY + y * strideY + prc.X, (byte *)pbBuffer + y * cbStride, cbStride, prc.Width); } nextY = prc.Y + prc.Height - startY; break; case WicPlane.Chroma: fixed(byte *pBuffC = lineBuffC.Array) for (int y = 0; y < prc.Height; y++) { Buffer.MemoryCopy(pBuffC + (prc.Y - startC) * strideC + y * strideC + prc.X * 2, (byte *)pbBuffer + y * cbStride, cbStride, prc.Width * 2); } nextC = prc.Y + prc.Height - startC; break; } }
public ConvolutionTransform(PixelSource source, KernelMap <TWeight> mapx, KernelMap <TWeight> mapy, bool lumaMode = false) : base(source) { var fmt = Format; if (lumaMode) { if (fmt.ColorRepresentation == PixelColorRepresentation.Bgr || fmt.ColorRepresentation == PixelColorRepresentation.Grey) { fmt = fmt.NumericRepresentation == PixelNumericRepresentation.Float ? PixelFormat.Grey32BppFloat : fmt.NumericRepresentation == PixelNumericRepresentation.Fixed ? PixelFormat.Grey16BppUQ15 : fmt.NumericRepresentation == PixelNumericRepresentation.UnsignedInteger ? PixelFormat.Cache[Consts.GUID_WICPixelFormat8bppGray] : throw new NotSupportedException("Unsupported pixel format"); } else { throw new NotSupportedException("Unsupported pixel format"); } } if (!ProcessorMap.TryGetValue(fmt.FormatGuid, out XProcessor)) { throw new NotSupportedException("Unsupported pixel format"); } if (fmt == PixelFormat.Bgr96BppLinearFloat) { Format = fmt = PixelFormat.Bgrx128BppLinearFloat; } else if (fmt == PixelFormat.Bgr96BppFloat) { Format = fmt = PixelFormat.Bgrx128BppFloat; } YProcessor = ProcessorMap[fmt.FormatGuid]; XMap = mapx; YMap = mapy; BufferSource = lumaMode; SourceRect = new WICRect { Width = (int)Width, Height = 1 }; IntStartLine = -mapy.Samples; IntBpp = fmt.BitsPerPixel / 8 / Unsafe.SizeOf <TPixel>() * Unsafe.SizeOf <TWeight>(); IntStride = mapy.Samples * IntBpp; WorkStride = fmt.BitsPerPixel / 8 * (int)Width + (IntPtr.Size - 1) & ~(IntPtr.Size - 1); int lineBuffLen = (BufferSource ? mapy.Samples : 1) * (int)BufferStride; int intBuffLen = mapx.OutPixels * IntStride; int workBuffLen = mapy.Samples * WorkStride; LineBuff = new ArraySegment <byte>(ArrayPool <byte> .Shared.Rent(lineBuffLen), 0, lineBuffLen).Zero(); IntBuff = new ArraySegment <byte>(ArrayPool <byte> .Shared.Rent(intBuffLen), 0, intBuffLen).Zero(); WorkBuff = lumaMode && !Format.IsBinaryCompatibleWith(fmt) ? new ArraySegment <byte>(ArrayPool <byte> .Shared.Rent(workBuffLen), 0, workBuffLen).Zero() : LineBuff; Width = (uint)mapx.OutPixels; Height = (uint)mapy.OutPixels; }
unsafe private void applyMatteLinearFloat(WICRect prc, float *pixels, int stride) { var igt = LookupTables.InverseGammaFloat; float mrl = igt[maskRed], mgl = igt[maskGreen], mbl = igt[maskBlue]; var v1 = new Vector <float>(1f); var vmat = new Vector <float>(new[] { mbl, mgl, mrl, 1f, mbl, mgl, mrl, 1f }); var vm0 = new Vector <int>(new[] { -1, -1, -1, -1, 0, 0, 0, 0 }); var vm1 = new Vector <int>(new[] { -1, -1, -1, 0, -1, -1, -1, 0 }); for (int y = 0; y < prc.Height; y++) { float *ip = pixels + y * stride; float *ipe = ip + prc.Width * 4 - Vector <float> .Count; while (ip <= ipe) { var vi = Unsafe.Read <Vector <float> >(ip); float ia0 = vi[3], ia1 = Vector <float> .Count == 8 ? vi[7] : ia0; if (ia0 == 0 && ia1 == 0) { Unsafe.Write(ip, vmat); } else if (ia0 < 1f || ia1 < 1f) { var vpa = Vector.ConditionalSelect(vm0, new Vector <float>(ia0), new Vector <float>(ia1)); var vma = v1 - vpa; var vr = vi + vmat * vma; var vo = Vector.ConditionalSelect(vm1, vr, v1); Unsafe.Write(ip, vo); } ip += Vector <float> .Count; } ipe += Vector <float> .Count; while (ip < ipe) { float ib = ip[0], ig = ip[1], ir = ip[2], ia = ip[3], ma = 1f - ia; ib += mbl * ma; ig += mgl * ma; ir += mrl * ma; ip[0] = ib; ip[1] = ig; ip[2] = ir; ip[3] = 1f; ip += 4; } } }
public PixelSourceFromIWICBitmapSource(IWICBitmapSource source, string name, bool profile = true) : base() { realSource = source; sourceRect = new WICRect(); sourceName = profile ? name : $"{name} (nonprofiling)"; WicSource = profile ? this.AsIWICBitmapSource() : source; Format = PixelFormat.Cache[source.GetPixelFormat()]; source.GetSize(out uint width, out uint height); Width = width; Height = height; }
unsafe private void applyMatteCompressed(WICRect prc, byte *pixels, int stride, bool premul) { const byte maxalpha = byte.MaxValue; fixed(ushort *igtstart = LookupTables.InverseGammaUQ15, atstart = LookupTables.AlphaUQ15) fixed(byte *gtstart = LookupTables.Gamma) { byte * gt = gtstart; ushort *igt = igtstart, at = atstart; ushort mrl = igt[maskRed], mgl = igt[maskGreen], mbl = igt[maskBlue]; for (int y = 0; y < prc.Height; y++) { byte *ip = pixels + y * stride; byte *ipe = ip + stride; while (ip < ipe) { int alpha = ip[3]; if (alpha == 0) { ip[0] = maskBlue; ip[1] = maskGreen; ip[2] = maskRed; ip[3] = maxalpha; } else if (alpha < maxalpha) { int ia = at[alpha], ma = UQ15One - ia; int ib = igt[ip[0]]; int ig = igt[ip[1]]; int ir = igt[ip[2]]; if (premul) { ia = UQ15One; } ib = UnscaleToUQ15(ib * ia + mbl * ma); ig = UnscaleToUQ15(ig * ia + mgl * ma); ir = UnscaleToUQ15(ir * ia + mrl * ma); ip[0] = gt[ib]; ip[1] = gt[ig]; ip[2] = gt[ir]; ip[3] = maxalpha; } ip += 4; } } } }
public static void FillBlobFromBitmapSource(this IWICBitmapSource bitmap, IntPtr blob, int bufferStride, int bufferSize) { if (bitmap == null) { throw new ArgumentNullException("bitmap"); } WICRect wicrect = default(WICRect); bitmap.GetSize(out wicrect.Width, out wicrect.Height); using (PinHelper pinHelper = new PinHelper(blob)) { bitmap.CopyPixels(ref wicrect, bufferStride, bufferSize, pinHelper.Addr); } }
unsafe private void loadBuffer(byte *pBuffY, byte *pBuffC, WICRect rect) { var planes = new WICBitmapPlane[2]; planes[0].Format = sourceY.GetPixelFormat(); planes[1].Format = sourceC.GetPixelFormat(); planes[0].cbStride = (uint)strideY; planes[1].cbStride = (uint)strideC; planes[0].cbBufferSize = (uint)lineBuffY.Count; planes[1].cbBufferSize = (uint)lineBuffC.Count; planes[0].pbBuffer = (IntPtr)pBuffY; planes[1].pbBuffer = (IntPtr)pBuffC; sourceTransform.CopyPixels(rect, scaledWidth, scaledHeight, sourceTransformOptions, WICPlanarOptions.WICPlanarOptionsDefault, planes, 2); }
public void Clip(int left, int top, int width, int height) { var rect = new WICRect(); rect.X = left; rect.Y = top; rect.Width = width; rect.Height = height; var clip = WICImagingFactory.CreateBitmapClipper(); clip.Object.Initialize(_comObject.Object, ref rect).ThrowOnError(); _comObject?.Dispose(); _comObject = clip; }
unsafe public override void CopyPixels(WICRect prc, uint cbStride, uint cbBufferSize, IntPtr pbBuffer) { Source.CopyPixels(prc, cbStride, cbBufferSize, pbBuffer); if (Format == Consts.GUID_WICPixelFormat64bppBGRA) { applyMatteLinear(prc, (ushort *)pbBuffer, (int)(cbStride / sizeof(ushort))); } else { fixed(ushort *igtstart = LookupTables.InverseGamma, atstart = LookupTables.Alpha) fixed(byte *gtstart = LookupTables.Gamma) applyMatteGamma(prc, igtstart, gtstart, atstart, (byte *)pbBuffer, (int)cbStride); } }
unsafe private void applyMatteLinear(WICRect prc, ushort *pixels, int stride, bool premul) { const ushort maxalpha = UQ15One; var igt = LookupTables.InverseGammaUQ15; ushort mrl = igt[maskRed], mgl = igt[maskGreen], mbl = igt[maskBlue]; for (int y = 0; y < prc.Height; y++) { ushort *ip = pixels + y * stride; ushort *ipe = ip + prc.Width * 4; while (ip < ipe) { int alpha = ip[3]; if (alpha == 0) { ip[0] = mbl; ip[1] = mgl; ip[2] = mrl; ip[3] = maxalpha; } else if (alpha < maxalpha) { int ia = alpha, ma = maxalpha - ia; ushort ib = ip[0]; ushort ig = ip[1]; ushort ir = ip[2]; if (premul) { ia = UQ15One; } ib = UnFixToUQ15(ib * ia + mbl * ma); ig = UnFixToUQ15(ig * ia + mgl * ma); ir = UnFixToUQ15(ir * ia + mrl * ma); ip[0] = ib; ip[1] = ig; ip[2] = ir; ip[3] = maxalpha; } ip += 4; } } }
public WicConvolution8bpc(IWICBitmapSource source, KernelMap mapx, KernelMap mapy, bool bufferSource = false) : base(source) { BufferSource = bufferSource; XMap = mapx; YMap = mapy; XMapAlpha = mapx.MakeAlphaMap(); YMapAlpha = mapy.MakeAlphaMap(); OutWidth = (uint)mapx.OutPixelCount; OutHeight = (uint)mapy.OutPixelCount; SourceRect = new WICRect() { Width = (int)Width, Height = 1 }; if (Format == Consts.GUID_WICPixelFormat32bppPBGRA) { Processor = new ConvolverBgra8bpc(); } else if (Format == Consts.GUID_WICPixelFormat32bppBGRA) { Processor = new ConvolverBgra8bpc(); } else if (Format == Consts.GUID_WICPixelFormat24bppBGR) { Processor = new ConvolverBgr8bpc(); } else if (Format == Consts.GUID_WICPixelFormat8bppGray) { Processor = new ConvolverGrey8bpc(); } else if (Format == Consts.GUID_WICPixelFormat8bppY) { Processor = new ConvolverGrey8bpc(); } else { throw new NotSupportedException("Unsupported pixel format"); } Stride /= sizeof(byte); IntStride = (int)(mapy.SampleCount * Channels); LineBuff = new byte[(bufferSource ? mapy.SampleCount : 1) * Stride]; IntBuff = new int[OutWidth * IntStride]; IntStartLine = -mapy.SampleCount; }
unsafe public override void CopyPixels(WICRect prc, uint cbStride, uint cbBufferSize, IntPtr pbBuffer) { Source.CopyPixels(prc, cbStride, cbBufferSize, pbBuffer); if (Format == PixelFormat.Pbgra128BppLinearFloat) { applyMatteLinearFloat(prc, (float *)pbBuffer, (int)(cbStride / sizeof(float))); } else if (Format == PixelFormat.Bgra64BppLinearUQ15 || Format == PixelFormat.Pbgra64BppLinearUQ15) { applyMatteLinear(prc, (ushort *)pbBuffer, (int)(cbStride / sizeof(ushort)), Format.AlphaRepresentation == PixelAlphaRepresentation.Associated); } else if (Format.FormatGuid == Consts.GUID_WICPixelFormat32bppBGRA || Format.FormatGuid == Consts.GUID_WICPixelFormat32bppPBGRA) { applyMatteCompressed(prc, (byte *)pbBuffer, (int)cbStride, Format.AlphaRepresentation == PixelAlphaRepresentation.Associated); } }
/// <summary> /// Adds padding to a bitmap, optionally cropping it at the same time. /// </summary> /// <param name="s"></param> /// <param name="left"></param> /// <param name="top"></param> /// <param name="right"></param> /// <param name="bottom"></param> /// <param name="bgcolor"></param> /// <param name="crop"></param> public WicBitmapPadder(IWICBitmapSource s, int left, int top, int right, int bottom, byte[] bgcolor, WICRect crop) { this.s = s; this.left = left; this.right = right; this.bottom = bottom; this.top = top; this.bgcolor = bgcolor; this.crop = crop; Guid pf; s.GetPixelFormat(out pf); if (bgcolor.Length != ConversionUtils.BytesPerPixel(pf)) { throw new ArgumentException("bgcolor length must match the format bytes per pixel"); } }
unsafe private void applyMatteGamma(WICRect prc, ushort *igtstart, byte *gtstart, ushort *atstart, byte *pixels, int stride) { const byte maxalpha = byte.MaxValue; byte * gt = gtstart; ushort *igt = igtstart, at = atstart; for (int y = 0; y < prc.Height; y++) { byte *ip = pixels + y * stride; byte *ipe = ip + prc.Width * Channels; while (ip < ipe) { int alpha = ip[3]; if (alpha == 0) { ip[0] = MaskBlue; ip[1] = MaskGreen; ip[2] = MaskRed; ip[3] = maxalpha; } else if (alpha < maxalpha) { int ia = at[alpha], ma = IntScale - ia; int ib = igt[ip[0]]; int ig = igt[ip[1]]; int ir = igt[ip[2]]; ib = UnscaleToUInt15(ib * ia + MaskBlueLinear * ma); ig = UnscaleToUInt15(ig * ia + MaskGreenLinear * ma); ir = UnscaleToUInt15(ir * ia + MaskRedLinear * ma); ip[0] = gt[ib]; ip[1] = gt[ig]; ip[2] = gt[ir]; ip[3] = maxalpha; } ip += 4; } } }
unsafe protected override void CopyPixelsInternal(WICRect prc, uint cbStride, uint cbBufferSize, IntPtr pbBuffer) { fixed(byte *bstart = &LineBuff.Array[0], wstart = &WorkBuff.Array[0], tstart = &IntBuff.Array[0]) fixed(byte *mapxstart = &XMap.Map.Array[0], mapystart = &YMap.Map.Array[0]) { int oh = prc.Height, ow = prc.Width, ox = prc.X, oy = prc.Y; int smapy = YMap.Samples, chan = YMap.Channels; for (int y = 0; y < oh; y++) { int *pmapy = (int *)mapystart + ((oy + y) * (smapy * chan + 1)); int iy = *pmapy++; LoadBuffer(bstart, wstart, tstart, mapxstart, iy); byte *op = (byte *)pbBuffer + y * cbStride; ConvolveLine(bstart, wstart, tstart, op, (byte *)pmapy, smapy, ox, oy + y, ow); } } }
public static void UpdateGifAnimationContext(WicGifContainer cont, ComPtr <IWICBitmapSource> src, ComPtr <IWICMetadataQueryReader> meta) { Debug.Assert(cont.AnimationContext is not null); var anictx = cont.AnimationContext; const int bytesPerPixel = 4; var finfo = GetGifFrameInfo(cont, src, meta); var fbuff = anictx.FrameBufferSource ??= new FrameBufferSource(cont.ScreenWidth, cont.ScreenHeight, PixelFormat.Bgra32Bpp); var bspan = fbuff.Span; fbuff.ResumeTiming(); // Most GIF viewers clear the background to transparent instead of the background color when the next frame has transparency bool ftrans = meta.GetValueOrDefault <bool>(Wic.Metadata.Gif.TransparencyFlag); if (!finfo.FullScreen && anictx.LastDisposal == GifDisposalMethod.RestoreBackground) { MemoryMarshal.Cast <byte, uint>(bspan).Fill(ftrans ? 0 : cont.BackgroundColor); } // Similarly, they overwrite a background color with transparent pixels but overlay instead when the previous frame is preserved var fspan = bspan.Slice(finfo.Top * fbuff.Stride + finfo.Left * bytesPerPixel); fixed(byte *buff = fspan) { if (!ftrans || anictx.LastDisposal == GifDisposalMethod.RestoreBackground) { var rect = new WICRect { Width = finfo.Width, Height = finfo.Height }; HRESULT.Check(src.Get()->CopyPixels(&rect, (uint)fbuff.Stride, (uint)fspan.Length, buff)); } else { using var overlay = new OverlayTransform(fbuff, src.AsPixelSource(null, nameof(IWICBitmapFrameDecode), false), finfo.Left, finfo.Top, true, true); overlay.CopyPixels(new PixelArea(finfo.Left, finfo.Top, finfo.Width, finfo.Height), fbuff.Stride, fspan.Length, (IntPtr)buff); } } fbuff.PauseTiming(); }
public void CopyPixels(ref WICRect prc, uint cbStride, uint cbBufferSize, byte[] pbBuffer) { //Log.Trace($"CopyPixels called: ({prc.X} {prc.Y} {prc.Width} {prc.Height}) Stride: {cbStride}, Size: {cbBufferSize}"); try { //Log.Trace($"CopyPixels rgbmap {rgbmap.Width}, {rgbmap.Height}"); CopyBGRA(ref prc, cbStride, cbBufferSize, pbBuffer); if (prc.Y + prc.Height == rgbmap.Height) { rgbmap.Dispose(); } //Log.Trace("CopyPixels finished"); } catch (Exception e) { Log.Error("CopyPixels failed: " + e); throw; } }
protected override bool ProcessFrameDecode(MainForm form, IWICBitmapFrameDecode frame, DataEntry[] de, object tag) { CheckGetColorContexts(form, de, frame.GetColorContexts); CheckGetBitmapSource(form, de, frame.GetThumbnail, WinCodecError.WINCODEC_ERR_CODECNOTHUMBNAIL); uint width; uint height; frame.GetSize(out width, out height); Guid pixelFormat; frame.GetPixelFormat(out pixelFormat); uint stride = (PixelFormatInfoRule.GetBitPerPixel(pixelFormat) * width + 7) / 8; byte[] buffer = new byte[stride * height]; WICRect rect = new WICRect(); rect.Height = (int)Math.Min(height, int.MaxValue); rect.Width = (int)Math.Min(width, int.MaxValue); try { frame.CopyPixels(rect, stride, stride * height, buffer); try { frame.CopyPixels(null, stride, stride * height, buffer); } catch (Exception e) { form.Add(this, e.TargetSite.ToString(Resources._0_Failed, "NULL"), de, new DataEntry(e)); } } catch { } return(true); }
unsafe private void applyMatteLinear(WICRect prc, ushort *pixels, int stride) { const ushort maxalpha = IntScale; ushort mrl = MaskRedLinear, mgl = MaskGreenLinear, mbl = MaskBlueLinear; for (int y = 0; y < prc.Height; y++) { ushort *ip = pixels + y * stride; ushort *ipe = ip + prc.Width * Channels; while (ip < ipe) { int alpha = ip[3]; if (alpha == 0) { ip[0] = mbl; ip[1] = mgl; ip[2] = mrl; ip[3] = maxalpha; } else if (alpha < IntScale) { int ia = alpha, ma = maxalpha - ia; ushort ib = ip[0]; ushort ig = ip[1]; ushort ir = ip[2]; ib = UnscaleToUInt15(ib * ia + mbl * ma); ig = UnscaleToUInt15(ig * ia + mgl * ma); ir = UnscaleToUInt15(ir * ia + mrl * ma); ip[0] = ib; ip[1] = ig; ip[2] = ir; ip[3] = maxalpha; } ip += 4; } } }
public static void FillBlobFromBitmapSource(this IWICBitmapSource bitmap, Array blob) { if (bitmap == null) { throw new ArgumentNullException("bitmap"); } if (blob == null) { throw new ArgumentNullException("blob"); } WICRect wicrect = default(WICRect); bitmap.GetSize(out wicrect.Width, out wicrect.Height); int arrayStride = WicUtility.GetArrayStride(blob, wicrect.Width, wicrect.Height); int arrayBufferSize = WicUtility.GetArrayBufferSize(blob); using (PinHelper pinHelper = new PinHelper(blob)) { bitmap.CopyPixels(ref wicrect, arrayStride, arrayBufferSize, pinHelper.Addr); } }
unsafe public override void CopyPixels(WICRect prc, uint cbStride, uint cbBufferSize, IntPtr pbBuffer) { fixed(byte *bstart = LineBuff) fixed(int *mapystart = YMap.Map, mapxstart = XMap.Map, mapxastart = XMapAlpha.Map, mapyastart = YMapAlpha.Map) fixed(int *tstart = IntBuff) { int oh = prc.Height, ow = prc.Width, ox = prc.X, oy = prc.Y; int smapy = YMap.SampleCount; for (int y = 0; y < oh; y++) { int *pmapy = mapystart + ((oy + y) * (smapy + 1)); int *pmapya = mapyastart + ((oy + y) * (smapy + 1)) + 1; int iy = *pmapy++; LoadBuffer(bstart, tstart, mapxstart, mapxastart, iy); void *op = (byte *)pbBuffer + y * cbStride; ConvolveLine(bstart, tstart, (byte *)op, pmapy, pmapya, smapy, ox, oy + y, ow); } } }
public void CenterClip(int?width, int?height) { if (!width.HasValue && !height.HasValue) { return; } var rect = new WICRect(); int w = Width; int h = Height; if (width.HasValue && width.Value < w) { rect.Width = width.Value; rect.X = (w - width.Value) / 2; } else { rect.Width = w; rect.X = 0; } if (height.HasValue && height.Value < h) { rect.Height = height.Value; rect.Y = (h - height.Value) / 2; } else { rect.Height = h; rect.Y = 0; } var clip = WICImagingFactory.CreateBitmapClipper(); clip.Object.Initialize(_comObject.Object, ref rect).ThrowOnError(); _comObject?.Dispose(); _comObject = clip; }
public void CopyPixels([In] ref WICRect prc, [In] uint uiWidth, [In] uint uiHeight, Guid dstFormat, [In] WICBitmapTransformOptions dstTransform, [In] uint nStride, [In] uint cbBufferSize, byte[] pbBuffer) { try { Log.Trace($"Trans CopyPixels called"); Log.Trace($"Trans CopyPixels called: {uiWidth}, {uiHeight} {dstFormat}"); if (dstFormat == GUID_WICPixelFormat32bppBGRA) { CopyBGRA(ref prc, nStride, cbBufferSize, pbBuffer); } if (prc.Y + prc.Height == rgbmap.Height) { rgbmap.Dispose(); } Log.Trace("CopyPixels finished"); } catch (Exception e) { Log.Error("CopyPixels failed: " + e); throw; } }
public WicPlanarCache(WicTransform prev) : base(prev) { if (!(prev.Source is IWICPlanarBitmapSourceTransform)) { throw new NotSupportedException("Transform chain doesn't support planar mode. Only JPEG Decoder, Rotator, Scaler, and ColorSpaceConverter are allowed"); } var trans = (IWICPlanarBitmapSourceTransform)prev.Source; double rat = Context.Settings.HybridScaleRatio.Clamp(1d, 8d); Context.Width = (uint)Math.Ceiling(Context.Width / rat); Context.Height = (uint)Math.Ceiling(Context.Height / rat); // Although generally the last scan has the least significant bit(s) of the luma plane and skipping it could be very beneficial performance-wise, there is no guarantee of scan order. Might be able to do something with more decoder support. //var prog = Frame as IWICProgressiveLevelControl; //if (prog != null) //{ // uint levels = prog.GetLevelCount(); // uint level = (uint)Math.Ceiling(levels / rat) + (Context.Settings.HybridMode == HybridScaleMode.FavorQuality || Context.Settings.HybridMode == HybridScaleMode.Off ? (uint)Math.Ceiling(levels / 8d) : 0u); // prog.SetCurrentLevel(Math.Min(level, levels - (Context.Settings.ScaleRatio >= 2d && levels > 7u ? 2u : 1u))); //} var fmts = new Guid[] { Consts.GUID_WICPixelFormat8bppY, Consts.GUID_WICPixelFormat16bppCbCr }; var desc = new WICBitmapPlaneDescription[2]; if (!trans.DoesSupportTransform(ref Context.Width, ref Context.Height, Context.TransformOptions, WICPlanarOptions.WICPlanarOptionsDefault, fmts, desc, 2)) { throw new NotSupportedException("Requested planar transform not supported"); } var crop = new WICRect { X = Context.Settings.Crop.X, Y = Context.Settings.Crop.Y, Width = Context.Settings.Crop.Width, Height = Context.Settings.Crop.Height }; cacheSource = new WicPlanarCacheSource(trans, desc[0], desc[1], crop, Context.TransformOptions, Context.Width, Context.Height, rat, Context.NeedsCache); SourceY = cacheSource.GetPlane(WicPlane.Luma); SourceCbCr = cacheSource.GetPlane(WicPlane.Chroma); }
static void Main(string [] args) { IWICImagingFactory factory = new WICImagingFactory(); factory.CreateDecoder(ContainerFormats.Png, Vendors.Microsoft, out IWICBitmapDecoder decoder); using (Stream inputStream = new FileStream("Test.png", FileMode.Open)) { decoder.Initialize(inputStream.AsIStream(), WICDecodeOptions.MetadataCacheOnDemand); decoder.GetFrame(0, out IWICBitmapFrameDecode bitmapFrame); bitmapFrame.GetSize(out uint width, out uint height); bitmapFrame.GetResolution(out double dpiX, out double dpiY); Console.WriteLine($"Width: {width}, Height: {height}, DPI: {dpiX}x{dpiY}"); factory.CreateFormatConverter(out IWICFormatConverter formatConverter); formatConverter.Initialize(bitmapFrame, PixelFormats.PixelFormat32bppBGRA, WICBitmapDitherType.None, null, 1, WICBitmapPaletteType.Custom); using (Stream outputStream = new FileStream("Output.png", FileMode.Create)) { factory.CreateEncoder(ContainerFormats.Png, Vendors.Microsoft, out IWICBitmapEncoder encoder); encoder.Initialize(outputStream.AsIStream(), WICBitmapEncoderCacheOption.NoCache); encoder.CreateNewFrame(out IWICBitmapFrameEncode frameEncode, out IPropertyBag2 encoderOptions); frameEncode.Initialize(encoderOptions); frameEncode.SetPixelFormat(PixelFormats.PixelFormat32bppBGRA); frameEncode.SetSize(width, height); frameEncode.SetResolution(dpiX, dpiY); WICRect rect = new WICRect(0, 0, ( int )width, ( int )height); frameEncode.WriteSource(formatConverter, ref rect); frameEncode.Commit(); encoder.Commit(); } } }