WPF——后台代码实现将多张图片拼接成一张

1. 利用DrawingVisual实现绘制拼接
2. 将DrawingVisual转为RenderTargetBitmap
3. 最后再通过复制像素转为WriteableBitmap

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;


namespace WpfApp17
{
    class numberctrl:Decorator
    {
        int iComboCount = 0;                      //连击数字
        int iNumImgCount  = 0;                    //图像数量
        int iComboFrameIndex = 0;                 //当前播放帧数
        const int kComboFrameCount = 40;          //需要播放的总帧数
        WriteableBitmap numComboBitmap = null;    //拼接后的图像
        System.Timers.Timer timer = new System.Timers.Timer();

        public numberctrl()
        {
            timer.Interval = 60;
            timer.Elapsed += new System.Timers.ElapsedEventHandler(OnTimer);
            timer.AutoReset = true;
            timer.Enabled = false;
        }

        // 随着计时器迭代加帧数,重新绘制
        private void OnTimer(object source, System.Timers.ElapsedEventArgs e)
        {
            System.Windows.Application.Current.Dispatcher.Invoke(() =>
            {
                iComboFrameIndex++;
                InvalidateVisual();
                if (iComboFrameIndex >= kComboFrameCount)
                {
                    if (timer.Enabled)
                    {
                        timer.Stop();
                    }
                }
            });
        }

        // 外界通过该接口实现触发更新
        public void UpdateCombo(int iNewComboCount)
        {

            iComboCount = iNewComboCount;
            if (iComboCount == 0)
            {
                if (timer.Enabled)
                {
                    timer.Stop();
                }
                InvalidateVisual();
            }
            else
            {
                if (!timer.Enabled)
                {
                    timer.Start();
                }
            }
        }

        // 重写Decorator渲染函数
        protected override void OnRender(DrawingContext dc)
        {
            base.OnRender(dc);
            if (iComboCount > 0)
            {
                DoCartoon(dc);
            }
        }

        // 获取图片
        public BitmapImage GetBitmapCacheByNum(int num)
        {
            try
            {
                BitmapImage bmp;
                num = num > 9 ? 9 : num;
                num = num < 0 ? 0 : num;

                string filePath = $"pack://application:,,,/WpfApp17;Component/Resources/{num}.png";
                bmp = new BitmapImage(new Uri(filePath));
                bmp.Freeze();

                return bmp;
            }
            catch { }

            return null;
        }

        // 将拼接好的图像进行渲染
        private void DoCartoon(DrawingContext dc)
        {
            //获取图片列表
            if (numComboBitmap == null)
            {
                List<BitmapImage> numBitmpList = new List<BitmapImage>();
                if (iComboCount >= 100)
                {
                    if (iComboCount > 999)
                        iComboCount = 999;

                    numBitmpList.Add(GetBitmapCacheByNum(iComboCount / 100));
                    numBitmpList.Add(GetBitmapCacheByNum((iComboCount % 100) / 10));
                    numBitmpList.Add(GetBitmapCacheByNum(iComboCount % 10));
                }
                else if (iComboCount >= 10)
                {
                    numBitmpList.Add(GetBitmapCacheByNum(iComboCount / 10));
                    numBitmpList.Add(GetBitmapCacheByNum(iComboCount % 10));
                }
                else
                {
                    numBitmpList.Add(GetBitmapCacheByNum(iComboCount % 10));
                }
                //拼接图片为单个
                numComboBitmap = CreateNumberBitmap(numBitmpList);
                iNumImgCount = numBitmpList.Count;
            }

            // 画位图
            Rect combRect = getDrawRectByCombo(20, 20, iNumImgCount, iComboFrameIndex);
            dc.DrawImage(numComboBitmap, combRect);

        }

        // list<BitmapImage> -> WriteableBitmap
        private WriteableBitmap CreateNumberBitmap(List<BitmapImage> numBitmpList)
        {
            if (numBitmpList.Count == 0)
                return null;

            WriteableBitmap bitmpCache = null;
            try
            {

                Rect bitmapRect = new Rect(0, 0, numBitmpList.ElementAt(0).Width * numBitmpList.Count, numBitmpList.ElementAt(0).Height);
                bitmpCache = new WriteableBitmap((int)bitmapRect.Width, (int)bitmapRect.Height, 96, 96, PixelFormats.Pbgra32, null);
                byte[] pixels = new byte[(int)bitmapRect.Width * (int)bitmapRect.Height * 4];

                // images -> drawingvisual
                DrawingVisual drawingVisual = new DrawingVisual();
                {
                    DrawingContext dc = drawingVisual.RenderOpen();
                    double point = 0;
                    for (int i = 0; i < numBitmpList.Count; i++)
                    {
                        Rect drawRect = new Rect(point, 0, numBitmpList.ElementAt(i).Width, numBitmpList.ElementAt(i).Height);
                        dc.DrawImage(numBitmpList.ElementAt(i), drawRect);
                        int iOffX = 2;
                        if (i > 0)
                        {
                            iOffX = 5;
                        }

                        point += numBitmpList.ElementAt(i).Width - iOffX;
                    }
                    dc.Close();
                    dc = null;
                }

                // drawingvisual -> rendertargetbitmap
                RenderTargetBitmap r = new RenderTargetBitmap((int)bitmapRect.Width, (int)bitmapRect.Height, 96, 96, PixelFormats.Pbgra32);
                r.Render(drawingVisual);
                int stride = (r.PixelWidth * r.Format.BitsPerPixel + 7) / 8;
                r.CopyPixels(pixels, stride, 0);
                r.Freeze();


                // rendertargetbitmap -> WriteableBitmap
                bitmpCache.Lock();
                Int32Rect rect = new Int32Rect(0, 0, (int)bitmapRect.Width, (int)bitmapRect.Height);
                bitmpCache.WritePixels(rect, pixels, stride, 0);
                bitmpCache.AddDirtyRect(rect);
                bitmpCache.Unlock();

            }
            catch (Exception e1)
            {
            }

            return bitmpCache;
        }

        // 根据帧索引确定绘制区域
        private Rect getDrawRectByCombo(int x, int y, int count, int iFrame)
        {
            // 确认每帧更改宽度
            const double dMaxWidth = 35;
            const double dMinWdith = 22;
            double changeSpan = (dMaxWidth - dMinWdith) / kComboFrameCount;

            // 帧数范围防御
            double iIndex = (double)iFrame;
            iIndex = iIndex > kComboFrameCount ? kComboFrameCount : iIndex;
            iIndex = iIndex < 0 ? 0 : iIndex;

            // 最大宽度与高度
            double sourceWidth = dMaxWidth;
            double sourceHeight = sourceWidth * 38 / 29;

            // 当前帧数的宽度与高度
            double desWidth = sourceWidth - changeSpan * iIndex;
            double desHeight = desWidth * 38 / 29;
            double offx = (sourceWidth - desWidth) / 2;
            double offy = (sourceHeight - desHeight) / 2;

            return new Rect(x + offx, y + offy, desWidth * count, desWidth * 38 / 29);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值