using System.Diagnostics; using System.Drawing; namespace PaintDotNet { public sealed class StitchSurfaceBoxBaseRenderer : StitchSurfaceBoxRenderer { private StitchSurface source; private RenderDelegate renderDelegate; public StitchSurface Source { set { this.source = value; Flush(); } } private void Flush() { this.renderDelegate = null; } protected override void OnVisibleChanged() { Invalidate(); } private void ChooseRenderDelegate() { if (SourceSize.Width > DestinationSize.Width) { // zoom out this.renderDelegate = new RenderDelegate(RenderZoomOutRotatedGridMultisampling); } else if (SourceSize == DestinationSize) { // zoom 100% this.renderDelegate = new RenderDelegate(RenderOneToOne); } else if (SourceSize.Width < DestinationSize.Width) { // zoom in this.renderDelegate = new RenderDelegate(RenderZoomInNearestNeighbor); } } public override void OnDestinationSizeChanged() { ChooseRenderDelegate(); this.OwnerList.InvalidateLookups(); base.OnDestinationSizeChanged(); } public override void OnSourceSizeChanged() { ChooseRenderDelegate(); this.OwnerList.InvalidateLookups(); base.OnSourceSizeChanged(); } public static void RenderOneToOne(StitchSurface dst, StitchSurface source, Point offset) { unsafe { if (source == null) return; Rectangle srcRect = new Rectangle(offset, dst.Size); srcRect.Intersect(source.Bounds); for (int dstRow = 0; dstRow < srcRect.Height; ++dstRow) { ColorBgrB* dstRowPtr = dst.GetRowAddressUnchecked(dstRow); ColorBgrB* srcRowPtr = source.GetPointAddressUnchecked(offset.X, dstRow + offset.Y); //source.stitchBounds; int dstCol = offset.X; int dstColEnd = offset.X + srcRect.Width; int checkerY = dstRow + offset.Y; while (dstCol < dstColEnd) { int b;// = srcRowPtr->B; int g;// = srcRowPtr->G; int r;// = srcRowPtr->R; int a = 255;// srcRowPtr->A; if (!source.stitchBounds.Contains(new Point(dstCol, checkerY)))// a = 0; { r = source.stitchBackColor.R;// 0;// p1->R;// g = source.stitchBackColor.G;// 0;// p1->G;// b = source.stitchBackColor.B;// 0;// p1->B;// } else { b = srcRowPtr->B; g = srcRowPtr->G; r = srcRowPtr->R; } // Blend it over the checkerboard background int v = (((dstCol ^ checkerY) & 8) << 3) + 191; a = a + (a >> 7); int vmia = v * (256 - a); r = ((r * a) + vmia) >> 8; g = ((g * a) + vmia) >> 8; b = ((b * a) + vmia) >> 8; dstRowPtr->setBGR((byte)b, (byte)g, (byte)r); ++dstRowPtr; ++srcRowPtr; ++dstCol; } } } } private void RenderOneToOne(StitchSurface dst, Point offset) { RenderOneToOne(dst, this.source, offset); } private void RenderZoomInNearestNeighbor(StitchSurface dst, Point offset) { unsafe { if (this.source == null) return; int[] d2SLookupY = OwnerList.Dst2SrcLookupY; int[] d2SLookupX = OwnerList.Dst2SrcLookupX; for (int dstRow = 0; dstRow < dst.Height; ++dstRow) { int nnY = dstRow + offset.Y; int srcY = d2SLookupY[nnY]; ColorBgrB* dstPtr = dst.GetRowAddressUnchecked(dstRow); ColorBgrB* srcRow = this.source.GetRowAddressUnchecked(srcY); //source.stitchBounds; for (int dstCol = 0; dstCol < dst.Width; ++dstCol) { int nnX = dstCol + offset.X; int srcX = d2SLookupX[nnX]; ColorBgrB src = *(srcRow + srcX); int b;// = src.B; int g;// = src.G; int r;// = src.R; int a = 255;// src.A; if (!source.stitchBounds.Contains(new Point(srcX, srcY)))// a = 0; { r = source.stitchBackColor.R;// 0;// p1->R;// g = source.stitchBackColor.G;// 0;// p1->G;// b = source.stitchBackColor.B;// 0;// p1->B;// } else { b = src.B; g = src.G; r = src.R; } // Blend it over the checkerboard background int v = (((dstCol + offset.X) ^ (dstRow + offset.Y)) & 8) * 8 + 191; a = a + (a >> 7); int vmia = v * (256 - a); r = ((r * a) + vmia) >> 8; g = ((g * a) + vmia) >> 8; b = ((b * a) + vmia) >> 8; dstPtr->setBGR((byte)b, (byte)g, (byte)r); ++dstPtr; } } } } public static void RenderZoomOutRotatedGridMultisampling(StitchSurface dst, StitchSurface source, Point offset, Size destinationSize) { unsafe { if (source == null) return; /* OpenCvSharp.Mat temp1 = new OpenCvSharp.Mat(dst.mat.Size(), OpenCvSharp.MatType.CV_8UC4); OpenCvSharp.Cv2.CvtColor(dst.mat, temp1, OpenCvSharp.ColorConversionCodes.BGR2BGRA); dst.mat = temp1; dst.Stride = temp1.Width * 4; dst.scan0.VoidStar = (void*)temp1.Data; OpenCvSharp.Mat temp2 = new OpenCvSharp.Mat(source.mat.Size(), OpenCvSharp.MatType.CV_8UC4); OpenCvSharp.Cv2.CvtColor(source.mat, temp2, OpenCvSharp.ColorConversionCodes.BGR2BGRA); source.mat = temp2; source.Stride = temp2.Width * 4; source.scan0.VoidStar = (void*)temp2.Data; */ //if (source.mat != null) //{ // OpenCvSharp.Cv2.ImShow("dst", source.mat); // OpenCvSharp.Cv2.WaitKey(); //} //OpenCvSharp.Cv2.ImShow("dst", dst.mat); //if (dst.mat != null) //OpenCvSharp.Cv2.CvtColor(dst.mat, dst.mat, OpenCvSharp.ColorConversionCodes.BGR2BGRA); //OpenCvSharp.Cv2.ImShow("src", source.mat); //OpenCvSharp.Cv2.WaitKey(); const int fpShift = 12; const int fpFactor = (1 << fpShift); Size sourceSize = source.Size; long fDstLeftLong = ((long)offset.X * fpFactor * (long)sourceSize.Width) / (long)destinationSize.Width; long fDstTopLong = ((long)offset.Y * fpFactor * (long)sourceSize.Height) / (long)destinationSize.Height; long fDstRightLong = ((long)(offset.X + dst.Width) * fpFactor * (long)sourceSize.Width) / (long)destinationSize.Width; long fDstBottomLong = ((long)(offset.Y + dst.Height) * fpFactor * (long)sourceSize.Height) / (long)destinationSize.Height; int fDstLeft = (int)fDstLeftLong; int fDstTop = (int)fDstTopLong; int fDstRight = (int)fDstRightLong; int fDstBottom = (int)fDstBottomLong; int dx = (fDstRight - fDstLeft) / dst.Width; int dy = (fDstBottom - fDstTop) / dst.Height; //int dstSum = 0; for (int dstRow = 0, fDstY = fDstTop; dstRow < dst.Height && fDstY < fDstBottom; ++dstRow, fDstY += dy) { int srcY1 = fDstY >> fpShift; // y int srcY2 = (fDstY + (dy >> 2)) >> fpShift; // y + 0.25 int srcY3 = (fDstY + (dy >> 1)) >> fpShift; // y + 0.50 int srcY4 = (fDstY + (dy >> 1) + (dy >> 2)) >> fpShift; // y + 0.75 #if DEBUG Debug.Assert(source.IsRowVisible(srcY1)); Debug.Assert(source.IsRowVisible(srcY2)); Debug.Assert(source.IsRowVisible(srcY3)); Debug.Assert(source.IsRowVisible(srcY4)); Debug.Assert(dst.IsRowVisible(dstRow)); #endif ColorBgrB* src1 = source.GetRowAddressUnchecked(srcY1); ColorBgrB* src2 = source.GetRowAddressUnchecked(srcY2); ColorBgrB* src3 = source.GetRowAddressUnchecked(srcY3); ColorBgrB* src4 = source.GetRowAddressUnchecked(srcY4); ColorBgrB* dstPtr = dst.GetRowAddressUnchecked(dstRow); int checkerY = dstRow + offset.Y; int checkerX = offset.X; int maxCheckerX = checkerX + dst.Width; for (int fDstX = fDstLeft; checkerX < maxCheckerX && fDstX < fDstRight; ++checkerX, fDstX += dx) { int srcX1 = (fDstX + (dx >> 2)) >> fpShift; // x + 0.25// fDstX >> fpShift; // int srcX2 = (fDstX + (dx >> 1) + (dx >> 2)) >> fpShift; // x + 0.75 int srcX3 = fDstX >> fpShift; // x int srcX4 = (fDstX + (dx >> 1)) >> fpShift; // x + 0.50 #if DEBUG Debug.Assert(source.IsColumnVisible(srcX1)); Debug.Assert(source.IsColumnVisible(srcX2)); Debug.Assert(source.IsColumnVisible(srcX3)); Debug.Assert(source.IsColumnVisible(srcX4)); #endif ColorBgrB* p1 = src1 + srcX1; ColorBgrB* p2 = src2 + srcX2; ColorBgrB* p3 = src3 + srcX3; ColorBgrB* p4 = src4 + srcX4; // / 4;// int r;// = (2 + p1->R + p2->R + p3->R + p4->R) >> 2;// p1->R;// int g;// = (2 + p1->G + p2->G + p3->G + p4->G) >> 2;// p1->G;// int b;// = (2 + p1->B + p2->B + p3->B + p4->B) >> 2;// p1->B;// int a = 255;// (2 + p1->A + p2->A + p3->A + p4->A) >> 2; if (!source.stitchBounds.Contains(new Point(srcX3, srcY1)))// a = 0; { r = source.stitchBackColor.R;// 0;// p1->R;// g = source.stitchBackColor.G;// 0;// p1->G;// b = source.stitchBackColor.B;// 0;// p1->B;// } else { r = (2 + p1->R + p2->R + p3->R + p4->R) >> 2;// p1->R;// g = (2 + p1->G + p2->G + p3->G + p4->G) >> 2;// p1->G;// b = (2 + p1->B + p2->B + p3->B + p4->B) >> 2;// p1->B;// } int apopacity = a; // //source.stitchBounds; // Blend it over the checkerboard background int v = ((checkerX ^ checkerY) & 8) * 8 + 191; a = a + (a >> 7); int vmia = v * (256 - a); r = ((r * a) + vmia) >> 8; g = ((g * a) + vmia) >> 8; b = ((b * a) + vmia) >> 8; dstPtr->setBGR((byte)b, (byte)g, (byte)r); //dstPtr->setBGR((byte)240, (byte)240, (byte)240); ++dstPtr; //++dstSum; } } //System.Console.WriteLine("dstSum:" + dstSum); } } private void RenderZoomOutRotatedGridMultisampling(StitchSurface dst, Point offset) { RenderZoomOutRotatedGridMultisampling(dst, this.source, offset, this.DestinationSize); } public override void Render(StitchSurface dst, Point offset) { if (this.renderDelegate == null) { ChooseRenderDelegate(); } this.renderDelegate(dst, offset); } public StitchSurfaceBoxBaseRenderer(StitchSurfaceBoxRendererList ownerList) : base(ownerList) { ChooseRenderDelegate(); } } }