public void CopyFrom(IImageReaderWriter sourceImage, RectInt sourceImageRect, int destXOffset, int destYOffset) { RectInt sourceImageBounds = sourceImage.GetBounds(); RectInt clippedSourceImageRect = new RectInt(); if (clippedSourceImageRect.IntersectRectangles(sourceImageRect, sourceImageBounds)) { RectInt destImageRect = clippedSourceImageRect; destImageRect.Offset(destXOffset, destYOffset); RectInt destImageBounds = GetBounds(); RectInt clippedDestImageRect = new RectInt(); if (clippedDestImageRect.IntersectRectangles(destImageRect, destImageBounds)) { // we need to make sure the source is also clipped to the dest. So, we'll copy this back to source and offset it. clippedSourceImageRect = clippedDestImageRect; clippedSourceImageRect.Offset(-destXOffset, -destYOffset); CopyFromNoClipping(sourceImage, clippedSourceImageRect, destXOffset, destYOffset); } } }
public virtual RectInt GetBounds() { return(linkedImage.GetBounds()); }
public void Render(IImageReaderWriter source, double destX, double destY) { int inScaleX = 1; int inScaleY = 1; int angleRadians = 0; // exit early if the dest and source bounds don't touch. // TODO: <BUG> make this do rotation and scalling RectInt sourceBounds = source.GetBounds(); RectInt destBounds = this.destImageReaderWriter.GetBounds(); sourceBounds.Offset((int)destX, (int)destY); if (!RectInt.DoIntersect(sourceBounds, destBounds)) { //if (inScaleX != 1 || inScaleY != 1 || angleRadians != 0) //{ // throw new NotImplementedException(); //} return; } double scaleX = inScaleX; double scaleY = inScaleY; Affine graphicsTransform = this.CurrentTransformMatrix; if (!graphicsTransform.IsIdentity()) { if (scaleX != 1 || scaleY != 1 || angleRadians != 0) { throw new NotImplementedException(); } graphicsTransform.Transform(ref destX, ref destY); } #if false // this is an optomization that eliminates the drawing of images that have their alpha set to all 0 (happens with generated images like explosions). MaxAlphaFrameProperty maxAlphaFrameProperty = MaxAlphaFrameProperty::GetMaxAlphaFrameProperty(source); if((maxAlphaFrameProperty.GetMaxAlpha() * color.A_Byte) / 256 <= ALPHA_CHANNEL_BITS_DIVISOR) { m_OutFinalBlitBounds.SetRect(0,0,0,0); } #endif bool isScale = (scaleX != 1 || scaleY != 1); bool isRotated = true; if (Math.Abs(angleRadians) < (0.1 * MathHelper.Tau / 360)) { isRotated = false; angleRadians = 0; } //bool IsMipped = false; //double ox, oy; //source.GetOriginOffset(out ox, out oy); bool canUseMipMaps = isScale; if (scaleX > 0.5 || scaleY > 0.5) { canUseMipMaps = false; } bool needSourceResampling = isScale || isRotated || destX != (int)destX || destY != (int)destY; VertexStore imgBoundsPath = GetFreeVxs(); // this is the fast drawing path if (needSourceResampling) { #if false // if the scalling is small enough the results can be improved by using mip maps if(CanUseMipMaps) { CMipMapFrameProperty* pMipMapFrameProperty = CMipMapFrameProperty::GetMipMapFrameProperty(source); double OldScaleX = scaleX; double OldScaleY = scaleY; const CFrameInterface* pMippedFrame = pMipMapFrameProperty.GetMipMapFrame(ref scaleX, ref scaleY); if(pMippedFrame != source) { IsMipped = true; source = pMippedFrame; sourceOriginOffsetX *= (OldScaleX / scaleX); sourceOriginOffsetY *= (OldScaleY / scaleY); } HotspotOffsetX *= (inScaleX / scaleX); HotspotOffsetY *= (inScaleY / scaleY); } #endif Affine destRectTransform = BuildImageBoundsPath(source.Width, source.Height, imgBoundsPath, destX, destY, ox, oy, scaleX, scaleY, angleRadians); // We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004] Affine sourceRectTransform = destRectTransform.CreateInvert(); var imgSpanGen = new ImgSpanGenRGBA_BilinearClip( source, Drawing.Color.Black, new SpanInterpolatorLinear(sourceRectTransform)); var v1 = destRectTransform.TransformToVxs(imgBoundsPath, GetFreeVxs()); Render(v1, imgSpanGen); ReleaseVxs(ref v1); #if false // this is some debug you can enable to visualize the dest bounding box LineFloat(BoundingRect.left, BoundingRect.top, BoundingRect.right, BoundingRect.top, WHITE); LineFloat(BoundingRect.right, BoundingRect.top, BoundingRect.right, BoundingRect.bottom, WHITE); LineFloat(BoundingRect.right, BoundingRect.bottom, BoundingRect.left, BoundingRect.bottom, WHITE); LineFloat(BoundingRect.left, BoundingRect.bottom, BoundingRect.left, BoundingRect.top, WHITE); #endif } else // TODO: this can be even faster if we do not use an intermediat buffer { Affine destRectTransform = BuildImageBoundsPath(source.Width, source.Height, imgBoundsPath, destX, destY); // We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004] Affine sourceRectTransform = destRectTransform.CreateInvert(); var interpolator = new SpanInterpolatorLinear(sourceRectTransform); ImgSpanGen imgSpanGen = null; switch (source.BitDepth) { case 32: imgSpanGen = new ImgSpanGenRGBA_NN_StepXBy1(source, interpolator); break; case 24: imgSpanGen = new ImgSpanGenRGB_NNStepXby1(source, interpolator); break; case 8: imgSpanGen = new ImgSpanGenGray_NNStepXby1(source, interpolator); break; default: throw new NotImplementedException(); } var v1 = destRectTransform.TransformToVxs(imgBoundsPath, GetFreeVxs()); Render(v1, imgSpanGen); ReleaseVxs(ref v1); unchecked { destImageChanged++; }; } ReleaseVxs(ref imgBoundsPath); }
public void Render(IImageReaderWriter source, double destX, double destY) { int inScaleX = 1; int inScaleY = 1; int angleRadians = 0; // exit early if the dest and source bounds don't touch. // TODO: <BUG> make this do rotation and scalling RectInt sourceBounds = source.GetBounds(); sourceBounds.Offset((int)destX, (int)destY); RectInt destBounds = this.destImageReaderWriter.GetBounds(); if (!RectInt.DoIntersect(sourceBounds, destBounds)) { //if (inScaleX != 1 || inScaleY != 1 || angleRadians != 0) //{ // throw new NotImplementedException(); //} return; } double scaleX = inScaleX; double scaleY = inScaleY; Affine graphicsTransform = this.CurrentTransformMatrix; if (!graphicsTransform.IsIdentity()) { if (scaleX != 1 || scaleY != 1 || angleRadians != 0) { throw new NotImplementedException(); } graphicsTransform.Transform(ref destX, ref destY); } #if false // this is an optomization that eliminates the drawing of images that have their alpha set to all 0 (happens with generated images like explosions). MaxAlphaFrameProperty maxAlphaFrameProperty = MaxAlphaFrameProperty::GetMaxAlphaFrameProperty(source); if ((maxAlphaFrameProperty.GetMaxAlpha() * color.A_Byte) / 256 <= ALPHA_CHANNEL_BITS_DIVISOR) { m_OutFinalBlitBounds.SetRect(0, 0, 0, 0); } #endif bool isScale = (scaleX != 1 || scaleY != 1); bool isRotated = false; if (angleRadians != 0 && Math.Abs(angleRadians) >= (0.1 * MathHelper.Tau / 360)) { isRotated = true; } else { angleRadians = 0;//reset very small angle to 0 } //bool IsMipped = false; //double ox, oy; //source.GetOriginOffset(out ox, out oy); bool canUseMipMaps = isScale; if (scaleX > 0.5 || scaleY > 0.5) { canUseMipMaps = false; } bool needSourceResampling = isScale || isRotated || destX != (int)destX || destY != (int)destY; VectorToolBox.GetFreeVxs(out VertexStore imgBoundsPath); // this is the fast drawing path if (needSourceResampling) { #if false // if the scalling is small enough the results can be improved by using mip maps if (CanUseMipMaps) { CMipMapFrameProperty *pMipMapFrameProperty = CMipMapFrameProperty::GetMipMapFrameProperty(source); double OldScaleX = scaleX; double OldScaleY = scaleY; const CFrameInterface *pMippedFrame = pMipMapFrameProperty.GetMipMapFrame(ref scaleX, ref scaleY); if (pMippedFrame != source) { IsMipped = true; source = pMippedFrame; sourceOriginOffsetX *= (OldScaleX / scaleX); sourceOriginOffsetY *= (OldScaleY / scaleY); } HotspotOffsetX *= (inScaleX / scaleX); HotspotOffsetY *= (inScaleY / scaleY); } #endif Affine destRectTransform = BuildImageBoundsPath(source.Width, source.Height, destX, destY, ox, oy, scaleX, scaleY, angleRadians, imgBoundsPath); // We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004] Affine sourceRectTransform = destRectTransform.CreateInvert(); var imgSpanGen = new ImgSpanGenRGBA_BilinearClip( source, Drawing.Color.Black, new SpanInterpolatorLinear(sourceRectTransform)); VectorToolBox.GetFreeVxs(out VertexStore v1); destRectTransform.TransformToVxs(imgBoundsPath, v1); Render(v1, imgSpanGen); VectorToolBox.ReleaseVxs(ref v1); #if false // this is some debug you can enable to visualize the dest bounding box LineFloat(BoundingRect.left, BoundingRect.top, BoundingRect.right, BoundingRect.top, WHITE); LineFloat(BoundingRect.right, BoundingRect.top, BoundingRect.right, BoundingRect.bottom, WHITE); LineFloat(BoundingRect.right, BoundingRect.bottom, BoundingRect.left, BoundingRect.bottom, WHITE); LineFloat(BoundingRect.left, BoundingRect.bottom, BoundingRect.left, BoundingRect.top, WHITE); #endif } else // TODO: this can be even faster if we do not use an intermediat buffer { Affine destRectTransform = BuildImageBoundsPath(source.Width, source.Height, destX, destY, imgBoundsPath); // We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004] Affine sourceRectTransform = destRectTransform.CreateInvert(); var interpolator = new SpanInterpolatorLinear(sourceRectTransform); ImgSpanGen imgSpanGen = null; switch (source.BitDepth) { case 32: imgSpanGen = new ImgSpanGenRGBA_NN_StepXBy1(source, interpolator); break; //case 24: // imgSpanGen = new ImgSpanGenRGB_NNStepXby1(source, interpolator); // break; case 8: imgSpanGen = new ImgSpanGenGray_NNStepXby1(source, interpolator); break; default: throw new NotImplementedException(); } VectorToolBox.GetFreeVxs(out VertexStore v1); destRectTransform.TransformToVxs(imgBoundsPath, v1); Render(v1, imgSpanGen); VectorToolBox.ReleaseVxs(ref v1); unchecked { destImageChanged++; }; } VectorToolBox.ReleaseVxs(ref imgBoundsPath); }