예제 #1
0
        public void Render(IBitmapSrc source, AffinePlan[] affinePlans)
        {
            VectorToolBox.GetFreeVxs(out var v1, out var v2);

            //BuildImageBoundsPath(source.Width, source.Height, affinePlans, v1);
            BuildOrgImgRectVxs(source.Width, source.Height, v1);


            //Affine destRectTransform = Affine.NewMatix(affinePlans);

            var destRectTransform = new AffineMat();

            destRectTransform.BuildFromAffinePlans(affinePlans);

            //TODO: review reusable span generator an interpolator ***
            var spanInterpolator = new SpanInterpolatorLinear();

            // We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004]

            _reuseableAffine.SetElements(destRectTransform.CreateInvert());
            spanInterpolator.Transformer = _reuseableAffine;//

            var imgSpanGen = new ImgSpanGenRGBA_BilinearClip(
                source,
                Drawing.Color.Transparent,
                spanInterpolator);

            TransformToVxs(ref destRectTransform, v1, v2);

            Render(v2, imgSpanGen);
            //
            VectorToolBox.ReleaseVxs(ref v1, ref v2);
        }
        public void Sharpen(IBitmapSrc img, int radius)
        {
            unsafe
            {
                TempMemPtr bufferPtr = img.GetBufferPtr();
                int[]      output    = new int[bufferPtr.LengthInBytes / 4]; //TODO: review here again

                fixed(int *outputPtr = &output[0])
                {
                    byte *srcBuffer     = (byte *)bufferPtr.Ptr;
                    int * srcBuffer1    = (int *)srcBuffer;
                    int * outputBuffer1 = (int *)outputPtr;
                    int   stride        = img.Stride;
                    int   w             = img.Width;
                    int   h             = img.Height;

                    MemHolder srcMemHolder = new MemHolder((IntPtr)srcBuffer1, bufferPtr.LengthInBytes / 4);//
                    Surface   srcSurface   = new Surface(stride, w, h, srcMemHolder);
                    //
                    MemHolder destMemHolder = new MemHolder((IntPtr)outputPtr, bufferPtr.LengthInBytes / 4);
                    Surface   destSurface   = new Surface(stride, w, h, destMemHolder);
                    //
                    SharpenRenderer shRenderer1 = new SharpenRenderer();

                    shRenderer1.Amount = radius;
                    shRenderer1.Render(srcSurface, destSurface, new PixelFarm.Drawing.Rectangle[] {
                        new PixelFarm.Drawing.Rectangle(0, 0, w, h)
                    }, 0, 1);
                }

                bufferPtr.Release();
                //ActualImage.SaveImgBufferToPngFile(output, img.Stride, img.Width + 1, img.Height + 1, "d:\\WImageTest\\test_1.png");
                img.ReplaceBuffer(output);
            }
        }
        public void Render(IBitmapSrc source, AffinePlan[] affinePlans)
        {
            using (VxsTemp.Borrow(out var v1, out var v2))
            {
                BuildOrgImgRectVxs(source.Width, source.Height, v1);

                AffineMat destRectTransform;
                if (affinePlans == null)
                {
                    destRectTransform = AffineMat.Iden;
                    _reuseableAffine.SetElements(destRectTransform);
                }
                else
                {
                    destRectTransform = new AffineMat();
                    destRectTransform.BuildFromAffinePlans(affinePlans);
                    _reuseableAffine.SetElements(destRectTransform.CreateInvert());
                }
                //TODO: review reusable span generator an interpolator ***
                //We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004]

                _spanInterpolator.Transformer = _reuseableAffine;

                _currentImgSpanGen.BackgroundColor = Drawing.Color.Transparent;
                _currentImgSpanGen.SetInterpolator(_spanInterpolator);
                _currentImgSpanGen.SetSrcBitmap(source);
                TransformToVxs(ref destRectTransform, v1, v2);
                Render(v2, _currentImgSpanGen);
                _currentImgSpanGen.ReleaseSrcBitmap();
            }
        }
예제 #4
0
        public MemBitmap GetTransformedBitmap(IBitmapSrc bitmap)
        {
            _srcBmp = bitmap;

            if (bitmap == null)
            {
                return(null);
            }

            _srcBmp = bitmap;
            _srcH   = bitmap.Height;
            _srcW   = bitmap.Width;


            //-------------------
            if (_srcH == 0 || _srcW == 0)
            {
                return(null);
            }
            switch (this.Interpolation)
            {
            default: throw new NotSupportedException();

            case InterpolationMode.None:
                return(GetTransformedBitmapNoInterpolation());

            case InterpolationMode.Bilinear:
                return(GetTransformedBilinearInterpolation());

            case InterpolationMode.Bicubic:
                return(GetTransformedBicubicInterpolation());
            }
        }
 public void Render(IBitmapSrc source, double destX, double destY, double srcX, double srcY, double srcW, double srcH)
 {
     //map some part of src img to destination
     _subBitmap.SetSrcBitmap(source, (int)srcX, (int)srcY, (int)srcW, (int)srcH);
     Render(_subBitmap, destX, destY);
     _subBitmap.Reset();
 }
예제 #6
0
        public unsafe static TempMemPtr FromBmp(IBitmapSrc actualBmp, out int *headPtr)
        {
            TempMemPtr ptr = actualBmp.GetBufferPtr();

            headPtr = (int *)ptr.Ptr;
            return(ptr);
        }
예제 #7
0
 public void SetSrcBitmap(IBitmapSrc src)
 {
     if (src.BitDepth != 32)
     {
         throw new NotSupportedException("The source is expected to be 32 bit.");
     }
     _bmpSrc = src;
 }
 public ImgSpanGenRGBA_BilinearClip(IBitmapSrc src,
                                    Drawing.Color back_color,
                                    ISpanInterpolator inter)
     : base(inter)
 {
     m_bgcolor = back_color;
     _imgsrc   = src;
     bytesBetweenPixelInclusive = _imgsrc.BytesBetweenPixelsInclusive;
 }
 public void SetSrcBitmap(IBitmapSrc src, int x, int y, int w, int h)
 {
     _orgSrcW = src.Width;
     _src     = src;
     _x       = x;
     _y       = y;
     _w       = w;
     _h       = h;
 }
 public ImgSpanGenRGBA_NN_StepXBy1(IBitmapSrc src, ISpanInterpolator spanInterpolator)
     : base(spanInterpolator)
 {
     _bmpSrc = src;
     if (_bmpSrc.BitDepth != 32)
     {
         throw new NotSupportedException("The source is expected to be 32 bit.");
     }
 }
예제 #11
0
 public SubBitmapBlender(IBitmapSrc image,
                         PixelBlender32 blender,
                         int distanceBetweenPixelsInclusive,
                         int arrayOffset32,
                         int bitsPerPixel)
 {
     this.OutputPixelBlender = blender;
     Attach(image, blender, distanceBetweenPixelsInclusive, arrayOffset32, bitsPerPixel);
 }
예제 #12
0
        public override void CopyFrom(IBitmapSrc sourceImage,
                                      Q1Rect sourceImageRect,
                                      int destXOffset,
                                      int destYOffset)
        {
            Q1Rect destRect = sourceImageRect.CreateNewFromOffset(destXOffset, destYOffset);

            if (Q1Rect.IntersectRectangles(destRect, _clippingRect, out Q1Rect clippedSourceRect))
            {
                // move it back relative to the source
                base.CopyFrom(sourceImage, clippedSourceRect.CreateNewFromOffset(-destXOffset, -destYOffset), destXOffset, destYOffset);
            }
        }
예제 #13
0
        public void CopyFrom(IBitmapSrc srcimg, Q1Rect srcImgRect, int destXOffset, int destYOffset)
        {
            if (Q1Rect.IntersectRectangles(srcimg.GetBounds(), srcImgRect, out Q1Rect clipped_srcRect))
            {
                Q1Rect dstImgRect = clipped_srcRect.CreateNewFromOffset(destXOffset, destYOffset);

                if (Q1Rect.IntersectRectangles(dstImgRect, GetBounds(), out Q1Rect clipped_dstRect))
                {
                    // we need to make sure the source is also clipped to the dest. So, we'll copy this back to source and offset it.
                    clipped_srcRect = clipped_dstRect.CreateNewFromOffset(-destXOffset, -destYOffset);
                    CopyFromNoClipping(srcimg, clipped_srcRect, destXOffset, destYOffset);
                }
            }
        }
예제 #14
0
        public override void CopyFrom(IBitmapSrc sourceImage,
                                      RectInt sourceImageRect,
                                      int destXOffset,
                                      int destYOffset)
        {
            RectInt destRect = sourceImageRect;

            destRect.Offset(destXOffset, destYOffset);
            RectInt clippedSourceRect = new RectInt();

            if (clippedSourceRect.IntersectRectangles(destRect, _clippingRect))
            {
                // move it back relative to the source
                clippedSourceRect.Offset(-destXOffset, -destYOffset);
                base.CopyFrom(sourceImage, clippedSourceRect, destXOffset, destYOffset);
            }
        }
예제 #15
0
        void Attach(IBitmapSrc sourceImage,
                    PixelBlender32 outputPxBlender,
                    int distanceBetweenPixelsInclusive,
                    int arrayElemOffset,
                    int bitsPerPixel)
        {
            _sourceImage = sourceImage;
            SetDimmensionAndFormat(sourceImage.Width,
                                   sourceImage.Height,
                                   sourceImage.Stride,
                                   bitsPerPixel,
                                   distanceBetweenPixelsInclusive);

            int srcOffset32 = sourceImage.GetBufferOffsetXY32(0, 0);

            SetBuffer(sourceImage.GetBufferPtr(), srcOffset32 + arrayElemOffset);
            this.OutputPixelBlender = outputPxBlender;
        }
예제 #16
0
        public void CopyFrom(IBitmapSrc sourceImage, Q1Rect sourceImageRect, int destXOffset, int destYOffset)
        {
            Q1Rect sourceImageBounds      = sourceImage.GetBounds();
            Q1Rect clippedSourceImageRect = new Q1Rect();

            if (clippedSourceImageRect.IntersectRectangles(sourceImageRect, sourceImageBounds))
            {
                Q1Rect destImageRect = clippedSourceImageRect;
                destImageRect.Offset(destXOffset, destYOffset);
                Q1Rect destImageBounds      = GetBounds();
                Q1Rect clippedDestImageRect = new Q1Rect();
                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 void Render(IBitmapSrc source, ICoordTransformer coordtx)
        {
            using (VxsTemp.Borrow(out var v1, out var v2))
            {
                BuildOrgImgRectVxs(
                    source.Width,
                    source.Height, v1);
                //**

                //TODO: review reusable span generator an interpolator ***

                //We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004]
                _spanInterpolator.Transformer      = coordtx.CreateInvert();
                _currentImgSpanGen.BackgroundColor = Color.Transparent;
                _currentImgSpanGen.SetInterpolator(_spanInterpolator);
                _currentImgSpanGen.SetSrcBitmap(source);
                TransformToVxs(coordtx, v1, v2);
                Render(v2, _currentImgSpanGen);
                _currentImgSpanGen.ReleaseSrcBitmap();
            }
        }
예제 #18
0
        internal unsafe static void NN_StepXBy1(IBitmapSrc bmpsrc, int srcIndex, Drawing.Color[] outputColors, int dstIndex, int len)
        {
            using (CpuBlit.TempMemPtr srcBufferPtr = bmpsrc.GetBufferPtr())
            {
                int *pSource = (int *)srcBufferPtr.Ptr + srcIndex;
                do
                {
                    int srcColor = *pSource;
                    //separate each component
                    //TODO: review here, color from source buffer
                    //should be in 'pre-multiplied' format.
                    //so it should be converted to 'straight' color by call something like ..'FromPreMult()'
                    outputColors[dstIndex++] = Drawing.Color.FromArgb(
                        (srcColor >> CO.A_SHIFT) & 0xff,  //a
                        (srcColor >> CO.R_SHIFT) & 0xff,  //r
                        (srcColor >> CO.G_SHIFT) & 0xff,  //g
                        (srcColor >> CO.B_SHIFT) & 0xff); //b

                    pSource++;                            //move next
                } while (--len != 0);
            }
        }
        public void Render(IBitmapSrc 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 = new RectInt((int)destX, (int)destY, (int)destX + source.Width, (int)destY + source.Height);
            //sourceBounds.Offset((int)destX, (int)destY);

            RectInt destBounds = _destBitmapBlender.GetBounds();

            if (!RectInt.DoIntersect(sourceBounds, destBounds))
            {
                //if (inScaleX != 1 || inScaleY != 1 || angleRadians != 0)
                //{
                //    throw new NotImplementedException();
                //}
                return;
            }

            double scaleX = inScaleX;
            double scaleY = inScaleY;

            ICoordTransformer 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


                using (VxsTemp.Borrow(out var imgBoundsPath, out var v1))
                {
                    BuildOrgImgRectVxs(source.Width, source.Height, imgBoundsPath);
                    Affine destRectTransform = CreateAffine(destX, destY, _ox, _oy, scaleX, scaleY, angleRadians);

                    //TODO: review reusable span generator an interpolator ***

                    // We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004]
                    //spanInterpolator.Transformer = destRectTransform.CreateInvert();

                    //var imgSpanGen = new ImgSpanGenRGBA_BilinearClip(
                    //    Drawing.Color.Black,
                    //    spanInterpolator);
                    _spanInterpolator.Transformer = destRectTransform.CreateInvert();
                    _currentImgSpanGen.SetInterpolator(_spanInterpolator);
                    _currentImgSpanGen.SetSrcBitmap(source);
                    destRectTransform.TransformToVxs(imgBoundsPath, v1);
                    Render(v1, _currentImgSpanGen);
                    _currentImgSpanGen.ReleaseSrcBitmap();
                }


                ////Affine destRectTransform = BuildImageBoundsPath(source.Width, source.Height,
                ////    destX, destY, ox, oy, scaleX, scaleY, angleRadians, imgBoundsPath);

                //Affine destRectTransform = CreateAffine(destX, destY, ox, oy, scaleX, scaleY, angleRadians);
                ////TODO: review reusable span generator an interpolator ***
                //var spanInterpolator = new SpanInterpolatorLinear();
                //// We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004]
                //spanInterpolator.Transformer = destRectTransform.CreateInvert();

                //var imgSpanGen = new ImgSpanGenRGBA_BilinearClip(
                //    source,
                //    Drawing.Color.Black,
                //    spanInterpolator);

                //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 intermediate buffer
            {
                //Affine destRectTransform = BuildImageBoundsPath(
                //    source.Width, source.Height,
                //    destX, destY, imgBoundsPath);
                using (VxsTemp.Borrow(out var imgBoundsPath, out var v1))
                {
                    BuildOrgImgRectVxs(source.Width, source.Height, imgBoundsPath);
                    //...
                    Affine destRectTransform = CreateAffine(destX, destY);

                    //TODO: review reusable span generator an interpolator ***


                    // We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004]

                    _spanInterpolator.Transformer = destRectTransform.CreateInvert();
                    //we generate image by this imagespan generator

                    ImgSpanGen imgSpanGen = null;
                    switch (source.BitDepth)
                    {
                    case 32:
                        if (_imgSpanGenCustom != null)
                        {
                            //use custom span gen
                            _imgSpanGenCustom.SetInterpolator(_spanInterpolator);
                            _imgSpanGenCustom.SetSrcBitmap(source);
                            imgSpanGen = _imgSpanGenCustom;
                        }
                        else
                        {
                            _imgSpanGenNNStepXBy1.SetInterpolator(_spanInterpolator);
                            _imgSpanGenNNStepXBy1.SetSrcBitmap(source);
                            imgSpanGen = _imgSpanGenNNStepXBy1;
                        }

                        break;

                    //case 8:
                    //    imgSpanGen = new ImgSpanGenGray_NNStepXby1(source, interpolator);
                    //    break;
                    default:
                        throw new NotImplementedException();
                    }

                    destRectTransform.TransformToVxs(imgBoundsPath, v1);
                    //...
                    Render(v1, imgSpanGen);
                }


                //
                unchecked { _destImageChanged++; };
            }
        }
예제 #20
0
        // Create
        //--------------------------------------------------------------------
        public void Create(IBitmapSrc src)
        {
            // we are going to create a dialated image for filtering
            // we add m_dilation pixels to every side of the image and then copy the image in the x
            // dirrection into each end so that we can sample into this image to get filtering on x repeating
            // if the original image look like this
            //
            // 123456
            //
            // the new image would look like this
            //
            // 0000000000
            // 0000000000
            // 5612345612
            // 0000000000
            // 0000000000

            m_height          = (int)AggMath.uceil(src.Height);
            m_width           = (int)AggMath.uceil(src.Width);
            m_width_hr        = (int)AggMath.uround(src.Width * LineAA.SUBPIXEL_SCALE);
            m_half_height_hr  = (int)AggMath.uround(src.Height * LineAA.SUBPIXEL_SCALE / 2);
            m_offset_y_hr     = m_dilation_hr + m_half_height_hr - LineAA.SUBPIXEL_SCALE / 2;
            m_half_height_hr += LineAA.SUBPIXEL_SCALE / 2;
            int bufferWidth    = m_width + m_dilation * 2;
            int bufferHeight   = m_height + m_dilation * 2;
            int bytesPerPixel  = src.BitDepth / 8;
            int newSizeInBytes = bufferWidth * bufferHeight * bytesPerPixel;

            if (m_DataSizeInBytes < newSizeInBytes)
            {
                m_DataSizeInBytes = newSizeInBytes;
                m_data            = new int[m_DataSizeInBytes / 4];
            }


            m_buf = new PixelProcessing.SubBitmapBlender(m_data, 0, bufferWidth, bufferHeight, bufferWidth * bytesPerPixel, src.BitDepth, bytesPerPixel);

            unsafe
            {
                CpuBlit.Imaging.TempMemPtr destMemPtr = m_buf.GetBufferPtr();
                CpuBlit.Imaging.TempMemPtr srcMemPtr  = src.GetBufferPtr();

                int *destBuffer = (int *)destMemPtr.Ptr;
                int *srcBuffer  = (int *)srcMemPtr.Ptr;
                // copy the image into the middle of the dest
                for (int y = 0; y < m_height; y++)
                {
                    for (int x = 0; x < m_width; x++)
                    {
                        int sourceOffset = src.GetBufferOffsetXY32(x, y);
                        int destOffset   = m_buf.GetBufferOffsetXY32(m_dilation, y + m_dilation);
                        destBuffer[destOffset] = srcBuffer[sourceOffset];
                    }
                }

                // copy the first two pixels form the end into the begining and from the begining into the end
                for (int y = 0; y < m_height; y++)
                {
                    int s1Offset = src.GetBufferOffsetXY32(0, y);
                    int d1Offset = m_buf.GetBufferOffsetXY32(m_dilation + m_width, y);
                    int s2Offset = src.GetBufferOffsetXY32(m_width - m_dilation, y);
                    int d2Offset = m_buf.GetBufferOffsetXY32(0, y);

                    for (int x = 0; x < m_dilation; x++)
                    {
                        destBuffer[d1Offset++] = srcBuffer[s1Offset++];
                        destBuffer[d2Offset++] = srcBuffer[s2Offset++];
                    }
                }

                srcMemPtr.Release();
                destMemPtr.Release();
            }
        }
예제 #21
0
        public void Fill(IBitmapSrc bufferToFillOn, int x, int y)
        {
            y -= imageHeight;
            unchecked // this way we can overflow the uint on negative and get a big number
            {
                if ((uint)x >= bufferToFillOn.Width || (uint)y >= bufferToFillOn.Height)
                {
                    return;
                }
            }
            _destImgRW = bufferToFillOn;
            TempMemPtr destBufferPtr = bufferToFillOn.GetBufferPtr();

            unsafe
            {
                imageWidth  = bufferToFillOn.Width;
                imageHeight = bufferToFillOn.Height;
                //reset new buffer, clear mem?
                pixelsChecked = new bool[imageWidth * imageHeight];

                int *destBuffer             = (int *)destBufferPtr.Ptr;
                int  startColorBufferOffset = bufferToFillOn.GetBufferOffsetXY32(x, y);

                int start_color = *(destBuffer + startColorBufferOffset);

                fillRule.SetStartColor(Drawing.Color.FromArgb(
                                           (start_color >> 16) & 0xff,
                                           (start_color >> 8) & 0xff,
                                           (start_color) & 0xff));


                LinearFill(destBuffer, x, y);

                while (ranges.Count > 0)
                {
                    Range range           = ranges.Dequeue();
                    int   downY           = range.y - 1;
                    int   upY             = range.y + 1;
                    int   downPixelOffset = (imageWidth * (range.y - 1)) + range.startX;
                    int   upPixelOffset   = (imageWidth * (range.y + 1)) + range.startX;
                    for (int rangeX = range.startX; rangeX <= range.endX; rangeX++)
                    {
                        if (range.y > 0)
                        {
                            if (!pixelsChecked[downPixelOffset])
                            {
                                int bufferOffset = bufferToFillOn.GetBufferOffsetXY32(rangeX, downY);

                                if (fillRule.CheckPixel(*(destBuffer + bufferOffset)))
                                {
                                    LinearFill(destBuffer, rangeX, downY);
                                }
                            }
                        }

                        if (range.y < (imageHeight - 1))
                        {
                            if (!pixelsChecked[upPixelOffset])
                            {
                                int bufferOffset = bufferToFillOn.GetBufferOffsetXY32(rangeX, upY);
                                if (fillRule.CheckPixel(*(destBuffer + bufferOffset)))
                                {
                                    LinearFill(destBuffer, rangeX, upY);
                                }
                            }
                        }
                        upPixelOffset++;
                        downPixelOffset++;
                    }
                }
            }
            destBufferPtr.Release();
        }
예제 #22
0
 public void ReleaseSrcBitmap()
 {
     _bmpSrc = null;
 }
예제 #23
0
 public void ReleaseSrcBitmap()
 {
     _imgsrc = null;
 }
예제 #24
0
 public void SetSrcBitmap(IBitmapSrc src)
 {
     _imgsrc = src;
     bytesBetweenPixelInclusive = _imgsrc.BytesBetweenPixelsInclusive;
 }
예제 #25
0
 internal void ReleaseSrcBitmap()
 {
     _bmpSrc = null;
 }
예제 #26
0
 public SubBitmapBlender(IBitmapSrc image, PixelBlender32 blender)
 {
     Attach(image, blender, image.BytesBetweenPixelsInclusive, 0, image.BitDepth);
 }
예제 #27
0
        // Create
        //--------------------------------------------------------------------
        public void Create(IBitmapSrc src)
        {
            // we are going to create a dialated image for filtering
            // we add m_dilation pixels to every side of the image and then copy the image in the x
            // dirrection into each end so that we can sample into this image to get filtering on x repeating
            // if the original image look like this
            //
            // 123456
            //
            // the new image would look like this
            //
            // 0000000000
            // 0000000000
            // 5612345612
            // 0000000000
            // 0000000000

            _height          = (int)AggMath.uceil(src.Height);
            _width           = (int)AggMath.uceil(src.Width);
            _width_hr        = (int)AggMath.uround(src.Width * LineAA.SUBPIXEL_SCALE);
            _half_height_hr  = (int)AggMath.uround(src.Height * LineAA.SUBPIXEL_SCALE / 2);
            _offset_y_hr     = _dilation_hr + _half_height_hr - LineAA.SUBPIXEL_SCALE / 2;
            _half_height_hr += LineAA.SUBPIXEL_SCALE / 2;
            int bufferWidth    = _width + _dilation * 2;
            int bufferHeight   = _height + _dilation * 2;
            int bytesPerPixel  = src.BitDepth / 8;
            int newSizeInBytes = bufferWidth * bufferHeight * bytesPerPixel;

            if (_DataSizeInBytes < newSizeInBytes)
            {
                _DataSizeInBytes = newSizeInBytes;

                _data.Dispose();

                IntPtr nativeBuff = System.Runtime.InteropServices.Marshal.AllocHGlobal(_DataSizeInBytes);
                _data = new TempMemPtr(nativeBuff, _DataSizeInBytes);
            }

            _buf = new PixelProcessing.SubBitmapBlender(_data, 0, bufferWidth, bufferHeight, bufferWidth * bytesPerPixel, src.BitDepth, bytesPerPixel);

            unsafe
            {
                using (TempMemPtr destMemPtr = _buf.GetBufferPtr())
                    using (TempMemPtr srcMemPtr = src.GetBufferPtr())
                    {
                        int *destBuffer = (int *)destMemPtr.Ptr;
                        int *srcBuffer  = (int *)srcMemPtr.Ptr;
                        // copy the image into the middle of the dest
                        for (int y = 0; y < _height; y++)
                        {
                            for (int x = 0; x < _width; x++)
                            {
                                int sourceOffset = src.GetBufferOffsetXY32(x, y);
                                int destOffset   = _buf.GetBufferOffsetXY32(_dilation, y + _dilation);
                                destBuffer[destOffset] = srcBuffer[sourceOffset];
                            }
                        }

                        // copy the first two pixels form the end into the begining and from the begining into the end
                        for (int y = 0; y < _height; y++)
                        {
                            int s1Offset = src.GetBufferOffsetXY32(0, y);
                            int d1Offset = _buf.GetBufferOffsetXY32(_dilation + _width, y);
                            int s2Offset = src.GetBufferOffsetXY32(_width - _dilation, y);
                            int d2Offset = _buf.GetBufferOffsetXY32(0, y);

                            for (int x = 0; x < _dilation; x++)
                            {
                                destBuffer[d1Offset++] = srcBuffer[s1Offset++];
                                destBuffer[d2Offset++] = srcBuffer[s2Offset++];
                            }
                        }
                    }
            }
        }
예제 #28
0
        public void Render(IBitmapSrc source,
                           double destX, double destY,
                           double angleRadians,
                           double inScaleX, double inScaleY)
        {
            {   // 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 renderRequriesSourceSampling = isScale || isRotated || destX != (int)destX || destY != (int)destY;

            VectorToolBox.GetFreeVxs(out VertexStore imgBoundsPath);

            // this is the fast drawing path
            if (renderRequriesSourceSampling)
            {
                // 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);
                //}
                //Affine destRectTransform = BuildImageBoundsPath(source.Width, source.Height,
                //    destX, destY, ox, oy, scaleX, scaleY, angleRadians, imgBoundsPath);

                //1.
                BuildOrgImgRectVxs(source.Width, source.Height, imgBoundsPath);
                //2.
                Affine destRectTransform = CreateAffine(destX, destY, ox, oy, scaleX, scaleY, angleRadians);
                //TODO: review reusable span generator an interpolator ***
                var interpolator = new SpanInterpolatorLinear();

                // We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004]
                interpolator.Transformer = destRectTransform.CreateInvert();
                var imgSpanGen = new ImgSpanGenRGBA_BilinearClip(source, Drawing.Color.Black, interpolator);

                VectorToolBox.GetFreeVxs(out var v1);
                destRectTransform.TransformToVxs(imgBoundsPath, v1);
                Render(v1, imgSpanGen);
                VectorToolBox.ReleaseVxs(ref v1);
                // 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);
            }
            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);

                BuildOrgImgRectVxs(source.Width, source.Height, imgBoundsPath);

                //
                var destRectTransform = new AffineMat();
                destRectTransform.Translate(destX, destY);
                //TODO: review reusable span generator an interpolator ***
                var interpolator = new SpanInterpolatorLinear();
                // We invert it because it is the transform to make the image go to the same position as the polygon. LBB [2/24/2004]
                _reuseableAffine.SetElements(destRectTransform.CreateInvert());
                interpolator.Transformer = _reuseableAffine;
                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 var v1);
                TransformToVxs(ref destRectTransform, imgBoundsPath, v1);

                Render(v1, imgSpanGen);
                VectorToolBox.ReleaseVxs(ref v1);
                //
                unchecked { destImageChanged++; };
            }
            VectorToolBox.ReleaseVxs(ref imgBoundsPath);
        }
 public void Reset()
 {
     _src = null;
 }
예제 #30
0
        /// <summary>
        /// create thumbnail img with super-sampling technique,(Expensive, High quality thumb)
        /// </summary>
        /// <param name="source"></param>
        /// <param name="dst"></param>
        public static MemBitmap CreateThumbnailWithSuperSamplingTechnique(this MemBitmap source, float scaleRatio)
        {
            // Paint.NET (MIT,from version 3.36.7, see=> https://github.com/rivy/OpenPDN
            //in this version new image MUST smaller than the original one ***
            if (scaleRatio >= 1 || scaleRatio < 0)
            {
                return(null);
            }

            //create new bitmap
            int newBmpW = (int)Math.Round(source.Width * scaleRatio);
            int newBmpH = (int)Math.Round(source.Height * scaleRatio);

            MemBitmap  thumbBitmap = new MemBitmap(newBmpW, newBmpH); //***
            IBitmapSrc source_1    = (IBitmapSrc)source;

            unsafe
            {
                Rectangle dstRoi2 = new Rectangle(0, 0, newBmpW, newBmpH);

                int dstWidth  = dstRoi2.Width;
                int dstHeight = dstRoi2.Height;

                int srcH = source.Height;
                int srcW = source.Width;

                Imaging.TempMemPtr dstMemPtr = MemBitmap.GetBufferPtr(thumbBitmap);
                int dstStrideInt32           = newBmpW;

                for (int dstY = dstRoi2.Top; dstY < dstRoi2.Bottom; ++dstY)
                {
                    //from dst  => find proper source (y)

                    //double srcTop = (double)(dstY * srcH) / (double)dstHeight;
                    double srcTop       = (double)(dstY * srcH) / (double)dstHeight;
                    double srcTopFloor  = Math.Floor(srcTop);
                    double srcTopWeight = 1 - (srcTop - srcTopFloor);
                    int    srcTopInt    = (int)srcTopFloor;

                    //double srcBottom = (double)((dstY + 1) * srcH) / (double)dstHeight;
                    double srcBottom       = (double)((dstY + 1) * srcH) / (double)dstHeight;
                    double srcBottomFloor  = Math.Floor(srcBottom - 0.00001);
                    double srcBottomWeight = srcBottom - srcBottomFloor;
                    int    srcBottomInt    = (int)srcBottomFloor;


                    int *srcBuffer      = (int *)(MemBitmap.GetBufferPtr(source)).Ptr;
                    int  srcStrideInt32 = source.Width;                            //***

                    int *dstAddr = (int *)dstMemPtr.Ptr + (dstStrideInt32 * dstY); //begin at

                    for (int dstX = dstRoi2.Left; dstX < dstRoi2.Right; ++dstX)
                    {
                        //from dst=> find proper source (x)

                        double srcLeft       = (double)(dstX * srcW) / (double)dstWidth;
                        double srcLeftFloor  = Math.Floor(srcLeft);
                        double srcLeftWeight = 1 - (srcLeft - srcLeftFloor);
                        int    srcLeftInt    = (int)srcLeftFloor;

                        double srcRight       = (double)((dstX + 1) * srcW) / (double)dstWidth;
                        double srcRightFloor  = Math.Floor(srcRight - 0.00001);
                        double srcRightWeight = srcRight - srcRightFloor;
                        int    srcRightInt    = (int)srcRightFloor;

                        double blueSum  = 0;
                        double greenSum = 0;
                        double redSum   = 0;
                        double alphaSum = 0;

                        //now we know (left,top) of source that we want
                        //then ask the pixel value from source at that pos

                        //(1) left fractional edge
                        {
                            //PaintFx.ColorBgra* srcLeftPtr = source.GetPointAddressUnchecked(srcLeftInt, srcTopInt + 1);
                            int *srcLeftColorAddr = srcBuffer + source_1.GetBufferOffsetXY32(srcLeftInt, srcTopInt + 1);

                            for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY)
                            {
                                int    srcColor = *srcLeftColorAddr;
                                double a_w      = ((srcColor >> CO.A_SHIFT) & 0xff) * srcLeftWeight;

                                blueSum  += ((srcColor >> CO.B_SHIFT) & 0xff) * a_w;
                                greenSum += ((srcColor >> CO.G_SHIFT) & 0xff) * a_w;
                                redSum   += ((srcColor >> CO.R_SHIFT) & 0xff) * a_w;
                                alphaSum += a_w;

                                //move to next row
                                srcLeftColorAddr += srcStrideInt32;
                                //srcLeftPtr = (ColorBgra*)((byte*)srcLeftPtr + source._stride);
                            }
                        }
                        //
                        {
                            //(2) right fractional edge
                            //ColorBgra* srcRightPtr = source.GetPointAddressUnchecked(srcRightInt, srcTopInt + 1);
                            int *srcRightColorAddr = srcBuffer + source_1.GetBufferOffsetXY32(srcRightInt, srcTopInt + 1);

                            for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY)
                            {
                                int    srcColor = *srcRightColorAddr;
                                double a_w      = ((srcColor >> CO.A_SHIFT) & 0xff) * srcRightWeight;

                                blueSum  += ((srcColor >> CO.B_SHIFT) & 0xff) * a_w;
                                greenSum += ((srcColor >> CO.G_SHIFT) & 0xff) * a_w;
                                redSum   += ((srcColor >> CO.R_SHIFT) & 0xff) * a_w;
                                alphaSum += a_w;

                                //srcRightPtr = (ColorBgra*)((byte*)srcRightPtr + source._stride);
                                srcRightColorAddr += srcStrideInt32; //move to next row
                            }
                        }
                        //
                        {
                            //(3) top fractional edge
                            //ColorBgra* srcTopPtr = source.GetPointAddressUnchecked(srcLeftInt + 1, srcTopInt);
                            int *srcTopColorAddr = srcBuffer + source_1.GetBufferOffsetXY32(srcLeftInt + 1, srcTopInt);

                            for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX)
                            {
                                int    srcColor = *srcTopColorAddr;
                                double a_w      = ((srcColor >> CO.A_SHIFT) & 0xff) * srcTopWeight;

                                blueSum  += ((srcColor >> CO.B_SHIFT) & 0xff) * a_w;
                                greenSum += ((srcColor >> CO.G_SHIFT) & 0xff) * a_w;
                                redSum   += ((srcColor >> CO.R_SHIFT) & 0xff) * a_w;
                                alphaSum += a_w;

                                //move to next column
                                //++srcTopPtr;
                                ++srcTopColorAddr;
                            }
                        }
                        //
                        {
                            //(4) bottom fractional edge
                            //ColorBgra* srcBottomPtr = source.GetPointAddressUnchecked(srcLeftInt + 1, srcBottomInt);
                            int *srcBottomColorAddr = srcBuffer + source_1.GetBufferOffsetXY32(srcLeftInt + 1, srcBottomInt);

                            for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX)
                            {
                                int    srcColor = *srcBottomColorAddr;
                                double a_w      = ((srcColor >> CO.A_SHIFT) & 0xff) * srcBottomWeight;

                                blueSum  += ((srcColor >> CO.B_SHIFT) & 0xff) * a_w;
                                greenSum += ((srcColor >> CO.G_SHIFT) & 0xff) * a_w;
                                redSum   += ((srcColor >> CO.R_SHIFT) & 0xff) * a_w;
                                alphaSum += a_w;

                                //++srcBottomPtr;
                                //move to next column
                                //++srcTopPtr;
                                ++srcBottomColorAddr;
                            }
                        }
                        {
                            //(5) center area
                            for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY)
                            {
                                //ColorBgra* srcPtr = source.GetPointAddressUnchecked(srcLeftInt + 1, srcY);
                                int *srcColorAddr = srcBuffer + source_1.GetBufferOffsetXY32(srcLeftInt + 1, srcY);

                                for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX)
                                {
                                    int srcColor = *srcColorAddr;

                                    int a = ((srcColor >> CO.A_SHIFT) & 0xff);
                                    blueSum  += ((srcColor >> CO.B_SHIFT) & 0xff) * a;
                                    greenSum += ((srcColor >> CO.G_SHIFT) & 0xff) * a;
                                    redSum   += ((srcColor >> CO.R_SHIFT) & 0xff) * a;
                                    alphaSum += a;

                                    ++srcColorAddr;
                                }
                            }
                        }


                        //(6) four corner pixels
                        {
                            //6.1
                            //ColorBgra srcTL = source.GetPoint(srcLeftInt, srcTopInt);
                            int srcColor = *(srcBuffer + source_1.GetBufferOffsetXY32(srcLeftInt, srcTopInt));

                            double a_w = ((srcColor >> CO.A_SHIFT) & 0xff) * (srcTopWeight * srcLeftWeight);

                            blueSum  += ((srcColor >> CO.B_SHIFT) & 0xff) * a_w;
                            greenSum += ((srcColor >> CO.G_SHIFT) & 0xff) * a_w;
                            redSum   += ((srcColor >> CO.R_SHIFT) & 0xff) * a_w;
                            alphaSum += a_w;
                        }

                        {
                            //6.2
                            //ColorBgra srcTR = source.GetPoint(srcRightInt, srcTopInt);
                            //double srcTRA = srcTR.A;
                            //blueSum += srcTR.B * (srcTopWeight * srcRightWeight) * srcTRA;
                            //greenSum += srcTR.G * (srcTopWeight * srcRightWeight) * srcTRA;
                            //redSum += srcTR.R * (srcTopWeight * srcRightWeight) * srcTRA;
                            //alphaSum += srcTR.A * (srcTopWeight * srcRightWeight);

                            int    srcColor = *(srcBuffer + source_1.GetBufferOffsetXY32(srcRightInt, srcTopInt));
                            double a_w      = ((srcColor >> CO.A_SHIFT) & 0xff) * (srcTopWeight * srcRightWeight);

                            blueSum  += ((srcColor >> CO.B_SHIFT) & 0xff) * a_w;
                            greenSum += ((srcColor >> CO.G_SHIFT) & 0xff) * a_w;
                            redSum   += ((srcColor >> CO.R_SHIFT) & 0xff) * a_w;
                            alphaSum += a_w;
                        }


                        {
                            //(6.3)
                            int    srcColor = *(srcBuffer + source_1.GetBufferOffsetXY32(srcLeftInt, srcBottomInt));
                            double a_w      = ((srcColor >> CO.A_SHIFT) & 0xff) * (srcBottomWeight * srcLeftWeight);

                            blueSum  += ((srcColor >> CO.B_SHIFT) & 0xff) * a_w;
                            greenSum += ((srcColor >> CO.G_SHIFT) & 0xff) * a_w;
                            redSum   += ((srcColor >> CO.R_SHIFT) & 0xff) * a_w;
                            alphaSum += a_w; //without a


                            //ColorBgra srcBL = source.GetPoint(srcLeftInt, srcBottomInt);
                            //double srcBLA = srcBL.A;
                            //blueSum += srcBL.B * (srcBottomWeight * srcLeftWeight) * srcBLA;
                            //greenSum += srcBL.G * (srcBottomWeight * srcLeftWeight) * srcBLA;
                            //redSum += srcBL.R * (srcBottomWeight * srcLeftWeight) * srcBLA;
                            //alphaSum += srcBL.A * (srcBottomWeight * srcLeftWeight);
                        }

                        {
                            //(6.4)

                            //ColorBgra srcBR = source.GetPoint(srcRightInt, srcBottomInt);
                            //double srcBRA = srcBR.A;
                            //blueSum += srcBR.B * (srcBottomWeight * srcRightWeight) * srcBRA;
                            //greenSum += srcBR.G * (srcBottomWeight * srcRightWeight) * srcBRA;
                            //redSum += srcBR.R * (srcBottomWeight * srcRightWeight) * srcBRA;
                            //alphaSum += srcBR.A * (srcBottomWeight * srcRightWeight);

                            int    srcColor = *(srcBuffer + source_1.GetBufferOffsetXY32(srcRightInt, srcBottomInt));
                            double a_w      = ((srcColor >> CO.A_SHIFT) & 0xff) * (srcBottomWeight * srcRightWeight);

                            blueSum  += ((srcColor >> CO.B_SHIFT) & 0xff) * a_w;
                            greenSum += ((srcColor >> CO.G_SHIFT) & 0xff) * a_w;
                            redSum   += ((srcColor >> CO.R_SHIFT) & 0xff) * a_w;
                            alphaSum += a_w;
                        }


                        double area = (srcRight - srcLeft) * (srcBottom - srcTop);

                        double alpha = alphaSum / area;
                        double blue;
                        double green;
                        double red;

                        if (alpha == 0)
                        {
                            blue  = 0;
                            green = 0;
                            red   = 0;
                        }
                        else
                        {
                            blue  = blueSum / alphaSum;
                            green = greenSum / alphaSum;
                            red   = redSum / alphaSum;
                        }

                        // add 0.5 so that rounding goes in the direction we want it to
                        blue  += 0.5;
                        green += 0.5;
                        red   += 0.5;
                        alpha += 0.5;


                        //***
                        //dstPtr->Bgra = (uint)blue + ((uint)green << 8) + ((uint)red << 16) + ((uint)alpha << 24);
                        //++dstPtr;
                        *dstAddr = ((byte)alpha) << CO.A_SHIFT |
                                   ((byte)blue) << CO.B_SHIFT |
                                   ((byte)green) << CO.G_SHIFT |
                                   ((byte)red) << CO.R_SHIFT;

                        //(uint)blue + ((uint)green << 8) + ((uint)red << 16) + ((uint)alpha << 24);
                        ++dstAddr;
                    }
                }
            }
            return(thumbBitmap);
        }